API keys and scopes
Every community route is authenticated with a community API key and gated
on a scope. Each endpoint in the REST API reference
lists the scope it requires, taken from the route definition rather than from
documentation that could drift. A key holding ADMIN satisfies every scope.
Create keys in the community admin (Integrations → API keys). Community keys
start with ck_.
The header
X-API-Key: <your key>Send the key in the X-API-Key header on every request
(Authorization: Bearer <key> is accepted too). The
JavaScript client does this for you.
Publishable vs. secret keys
Publishable (ck_…, public) | Secret (ck_…, server-only) | |
|---|---|---|
| Where it lives | Browser bundles. Treat it as public. | Your server's environment. Never in a front end. |
| Scopes | READ_PUBLIC, WRITE_APPLICATIONS, WRITE_CART only | Whatever was granted to it |
Member sign-in (MEMBER_AUTH) | Refused (403 SECRET_KEY_REQUIRED) | Allowed |
| Operator writes (approve members, refunds, tier changes, finance reads) | Refused, scope or no scope | Allowed with the scope |
A publishable key is fetched by an unauthenticated endpoint and ships in
browser bundles. It carries READ_PUBLIC, WRITE_APPLICATIONS and
WRITE_CART only.
It deliberately does not carry WRITE_MEMBERS. That scope lets the caller
name any email in the body, so a browser-exposed key holding it would let
anyone record a membership action against any address. A test pins the 403.
Anything marked WRITE_MEMBERS, MEMBERS_ADMIN, ADMIN, APP_*,
WRITE_FEED, WRITE_NOTIFICATIONS or READ_FINANCE* is a server-side
call. Do not put those keys in a front end. The finance reads enforce this:
a publishable key is refused outright, scope or no scope.
On the finance API a publishable key is accepted only on browser buyer flows
(checkout, checkout status, the guest order link and receipt, buyer refunds,
donations, apply checkout). Host-initiated actions (refund a sale, cancel a
member's subscription, change a member's tier) need a secret key and answer
403 SECRET_KEY_REQUIRED otherwise. The default publishable key does not carry
WRITE_SALES, so call those buyer flows from your server unless the community
granted its publishable key that scope.
A key with an expiresAt in the past is 401 everywhere.
Tenant binding
Every key belongs to exactly one community. The :communityTag in the URL
must be that community:
- A key from another community is
403 WRONG_COMMUNITY. - A tag that does not exist is
404. There is no fallback that looks a resource up by id alone, so a guessed tier, form or event id from another community is never served.
Scopes
| Scope | Used by |
|---|---|
READ_PUBLIC | branding, members, events, articles, products, segment forms |
WRITE_APPLICATIONS | segment submit, paid apply checkout |
WRITE_CART | the whole cart surface |
MEMBER_AUTH | member sign-in, sign-up and recovery, and every /me route (secret keys only) |
WRITE_SALES | ticket and marketplace checkout, quotes, buyer and host refunds, donations, guest order links |
WRITE_SUBSCRIPTIONS | cancelling a member's paid membership, moving them to another tier |
WRITE_MEMBERS | approve / reject an application, rules acceptance by email |
MEMBERS_ADMIN | the full member roster for admin integrations, including members hidden from the directory (secret keys only; never on publishable keys, never granted to apps) |
WRITE_SEGMENTS | changing a membership tier's name, pricing or active status |
WRITE_EVENTS | the event bridge (create / update events by key), editing an event |
WRITE_ARTICLES | creating, editing, publishing and unpublishing articles |
WRITE_BROADCASTS | sending an email broadcast |
WRITE_FEED · WRITE_NOTIFICATIONS | posting to the feed, sending notifications |
APP_HANDOFF | exchanging a handoff code |
APP_MINT_MEMBER_TOKEN | minting a short-lived member token for a known member |
APP_IDENTITY_EMAIL · APP_IDENTITY_PROFILE | identity fields returned by the handoff exchange |
APP_ONBOARDING | reading and satisfying a member's onboarding |
APP_DATA | per-app member key/value storage |
APP_IDENTITY_LOCALE_WRITE | writing a member's language |
READ_FINANCE | the community's ledger, settlements and totals (secret keys only) |
READ_FINANCE_PII | adds buyer identity to those reads; a separate grant on purpose |
ADMIN | wildcard: satisfies every scope above |
WRITE_ARTICLES and WRITE_SEGMENTS used to be covered by ADMIN, which is
a wildcard: an integration that only needed to publish articles was being
handed member management and tier pricing as well. Ask for the narrow scope.
Keys already holding ADMIN keep working, since it still satisfies any
required scope.
Personal user keys (uk_) are a different credential with one scope,
READ_OWN. See Member sessions and user keys.
To filter the reference by what a key can call, use the Key type and Scope filters on the REST API reference.