Skip to main content
The API is a single service under /api, deployed once and shared by every site. It exists for two reasons: anything that needs a secret, and anything that must be enforced server-side regardless of what a client sends. Sites reach it through API_URL.

Authentication

Most routes need a member session: a bearer token from the site’s sign-in, verified server-side, then a check that the member can act on the org_id in the request. Row ownership is never trusted from the client. Public-by-design routes are hardened instead: campaign link resolution, form submits (token-gated), access requests (honeypot, origin check, cooldowns, per-org caps), the private-site mode lookup, and visit ingest (origin-verified, rate-limited, classification fields never trusted from the body). Cron routes (scheduled publishing, social publishing, metrics polling) are protected by a shared secret.

Route groups

Publishing

POST /api/build dispatches on the org’s publish_mode: Both outbound calls are guarded: HTTPS only, no redirects, public-only DNS resolution, a timeout. Errors back to the admin are terse (“No deploy hook”, “Can’t reach hook”). The route returns as soon as the hook accepts and stamps last_build_at, which the editor uses to decide whether to highlight Publish.

Errors

Routes fail loudly rather than partially. A lookup that cannot complete is a 500, not a partial count. A resource in another org answers exactly like a missing one, because existence is tenant data too.

Compatibility

Every route obeys the additive-only rule. Fields and routes are added; existing ones keep their meaning until a breaking release after the whole fleet has moved past them.