claimSubdomain
Claim a branded `*.fotowall.io` subdomain for your tenant. Write-once enforced.
POST /claimSubdomain Atomic uniqueness transaction that writes the subdomain field on tenants/{tid}. Slug must match `^[a-z0-9][a-z0-9-]{1,38}[a-z0-9]$` (3-40 chars, lowercase alphanumeric + hyphen). A reserved-word list blocks ~120 technical / brand / profanity slugs. Once a slug is `active`, the tenant admin cannot change it — releaseSubdomain is the superadmin-only escape hatch. Soft errors (invalid / reserved / taken / already-claimed) return `{ ok: false, reason }` so the admin UI can render inline.
AUTH NOTE
Requires a Firebase Auth ID token with role=admin (or superadmin) custom claim. Tenant-scoped unless invoked by a superadmin with an explicit tenantId.
Request
| Field | Type | Required | Description |
|---|---|---|---|
slug | string | yes | 3-40 chars, lowercase alphanumeric + hyphen. No leading or trailing hyphen. |
tenantId | string | no | Superadmin-only: claim on behalf of another tenant. Tenant admins MUST omit or pass their own tenantId. |
EXAMPLE BODY
{
"slug": "acme-gala"
} Response
| Field | Type | Always present | Description |
|---|---|---|---|
ok | boolean | yes | true on a successful (or idempotent) claim. false on a soft error. |
idempotent | boolean | no | Present and true when the caller re-claims the same slug they already own. |
reason | "invalid" | "reserved" | "taken" | "already-claimed" | no | Present when ok=false. |
EXAMPLE BODY
{
"ok": true
} curl
curl -X POST https://us-central1-freedomgrc-photowall.cloudfunctions.net/claimSubdomain \
-H "Authorization: Bearer <firebase-id-token>" \
-H "Content-Type: application/json" \
-d '{"data":{"slug":"acme-gala"}}' JavaScript
We don't ship a first-party JS SDK yet (it's on the roadmap).
For callable endpoints, the Firebase Functions SDK is the recommended
path — it handles ID-token attachment and payload framing.
Plain fetch works too.
import { getFunctions, httpsCallable } from 'firebase/functions';
const functions = getFunctions(app, 'us-central1');
const claim = httpsCallable(functions, 'claimSubdomain');
const result = await claim({ slug: 'acme-gala' });
// On success: result.data === { ok: true }
// Already owned: result.data === { ok: true, idempotent: true }
// Soft error: result.data === { ok: false, reason: 'taken' } Error cases
| Code | When |
|---|---|
unauthenticated | No Firebase Auth ID token. |
permission-denied | Caller is not a tenant admin (or superadmin). Or admin tried to claim for a different tenant. |
invalid-argument | No target tenant resolvable from auth + input. |
not-found | tenantId references a non-existent tenant. |
internal | Uniqueness transaction failed (typically Firestore contention). |
Need a different shape?
The API surface is small. Tell us what you need and we'll work backward from your integration.