Read this company's connected custom domain
/api/organization/website/domainThe "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.
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
Response Body
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/api/organization/website/domain"{ "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" }}Publish a page's draft content live (admin) POST
Copies `draft_content` over `published_content` and stamps `published_at`. Unconditionally admin-only, no `manage_org_settings` escape hatch (unlike the save route above): migration 0112 grants UPDATE on `draft_content`/`updated_at` only, deliberately never on `published_content`, so this is the ONLY place "publish" is actually enforced. A company that never touched this page's draft gets a clean 200 no-op: the live page already renders its generated default and there is nothing to copy forward.
Connect a custom domain (admin) POST
v1 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.