WzGate
Build your own website

Keys and CORS

Publishable and secret API keys, the origin rule, rotation and revocation, how CORS follows your site's domains, and the monitor-then-enforce rollout.

Every public call may carry an API key in X-Api-Key. Keys are per site and are created, rotated and revoked in Settings → Websites → Connect your website.

Two kinds of key

Publishable pk_…Secret sk_…
Where it runsThe browserYour own server (SSR, a backend job)
Secret?No — it is inlined into your bundle by designYes — stored hashed, shown once at creation
Origin checkedYes: only your site's own domainsNo — a server call has no Origin
Rate limitsStandardFive times higher
Bot checkRequired on the five protected writesSkipped
Visible in the CRMFull value, any timePrefix only, after creation

A publishable key is not a password. Its value is elsewhere: you can revoke it, it is rate-limited on its own, and it tells the CRM which integration a call came from. Anyone can read it out of your JavaScript — and it will not work for them, because it is refused from any origin that is not one of your domains.

A secret key is a password. It skips the origin check precisely because a server-to-server call has no origin to check, so treat it as a credential: keep it in a server-only environment variable (never one prefixed NEXT_PUBLIC_), never commit it, and rotate it if it ever appears in a browser bundle, a log or a screenshot.

The origin rule

A pk_ call is accepted when its Origin is one of the site's domains. Outside production http://localhost and http://127.0.0.1 are also accepted, so local development works with the real key. Anything else is 403 SITE_KEY_ORIGIN_MISMATCH, with the same code when a key names a different site than the request resolved to.

That is why the Domains tab matters twice: it decides which sites a host resolves, and it decides which origins a publishable key works from.

Rotation and revocation

  • Rotate creates a new key and revokes the old one in a single step. Deploy the new value, then confirm nothing still uses the old one.
  • Revoke kills a key immediately. A call with it answers 401 SITE_KEY_REVOKED.
  • A secret key's value is shown once, in the dialog that creates it. There is no way to read it again; if it is lost, rotate.
  • Keys record a "last used" time, so you can tell a live key from a forgotten one before revoking it.

Rotating a publishable key is a deployment: the key lives in your build, so the new value only reaches visitors when the site is rebuilt. Rotate the secret key first if you are doing both.

CORS

CORS follows your site's domains, and nothing else. /api/public/* reflects an Origin only when it is:

  • a domain added to a site, or
  • one of the platform's own configured front-ends, or
  • localhost, outside production.

Every other origin is refused before the handler runs — the browser reports a CORS failure and there is no response body to read. If your fetch fails in the browser but the same call works from curl, the origin is the thing to check, not the key.

Request headers are allow-listed explicitly: Content-Type, Authorization, X-Subdomain, X-Site, X-Api-Key, X-Turnstile-Token, X-Organization-Id, X-Simulated-Organization-Id. A header outside that list fails the preflight, so the browser never sends the request at all — which reads as a CORS bug rather than a rejected header. Do not invent your own.

The rollout: monitor, then enforce

Keys are being switched on in two stages, so no existing website breaks at a deploy.

  1. Monitor (where the platform is now). A write with no key, an unknown key or a wrong origin is served, and the refusal is written to the server log instead. Nothing you build fails for lack of a key today.
  2. Enforce. The same request is refused: 401 SITE_KEY_REQUIRED, 401 SITE_KEY_REVOKED or 403 SITE_KEY_ORIGIN_MISMATCH.

The switch is announced in the changelog before it happens. Send your keys now: in monitor mode a correct integration is indistinguishable from an enforced one, and on the day of the switch nothing changes for you.

Next

On this page