Connect a custom domain (admin)
/api/organization/website/domainv1 is subdomain-CNAME only (migration 0148's own header has the full reasoning): an apex/root domain like "yourbusiness.com.au" is accepted the same way at this layer, the scope restriction is a UI/product decision, not a validation rule here. Attaches hostname to this Vercel project (src/lib/vercel/domains.ts) and upserts book_custom_domains, one row per company (migration 0148's unique(company_id)); connecting a second domain replaces the first. verificationChallenge in the response is a TXT record Vercel wants for ownership proof, present only when Vercel could not verify immediately (most often a domain seen elsewhere before); the CNAME instruction itself is constant and not part of the response, the UI renders it directly.
Authorization
sessionCookie The dashboard's Supabase Auth session cookie, set at sign-in. Large sessions are split across
numbered chunks (…auth-token.0, .1), so treat this as a cookie family rather than one name.
Every request re-validates it against the Auth server (getUser()), never by decoding the cookie
locally: a JWT nothing has checked is not a credential. Tenancy is then read from the verified
app_metadata.company_id claim and enforced by row-level security; it is never read from request
input, on any route, ever.
role (admin / staff) is deliberately not in RLS. It gates specific actions in route code,
the operations marked admin below, so hiding a button in the UI is cosmetic only, and a route's
own check is the enforcement.
In: cookie
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/organization/website/domain" \ -H "Content-Type: application/json" \ -d '{ "hostname": "string" }'{ "domain": { "hostname": "string", "vercelVerified": true, "dnsMisconfigured": true, "verificationChallenge": { "type": "string", "domain": "string", "value": "string" }, "lastCheckedAt": "2019-08-24T14:15:22Z", "createdAt": "2019-08-24T14:15:22Z" }}Read this company's connected custom domain GET
The "Your domain" card on the Website status screen. `domain` is null until an admin connects one. Appointments only, same as every other route under the Website screen: the page itself already redirects a hospitality org away before this could ever be called. Readable by any member; only the writes below are admin-only.
Re-check this company's connected domain against Vercel (admin) PATCH
The poll the UI drives every ~30s while a connected domain sits unverified, waiting on the operator's own DNS change to propagate. Vercel has no webhook for "DNS propagated" or "cert issued" (see src/lib/vercel/domains.ts), so re-checking on demand against Vercel's own verify + config endpoints is the documented pattern. No-op success is not possible here: 404 if nothing is connected yet.