Skip to main content
The API accepts two bearer credentials interchangeably: long-lived API keys (ck_live_…, see Authentication) and short-lived OAuth access tokens (ck_oat_…). OAuth is the better fit when your platform already manages OAuth credentials, or when you want tokens that expire on their own instead of a key that lives until revoked. The server implements the standard client credentials grant (RFC 6749 §4.4), token revocation (RFC 7009), and discovery metadata at /.well-known/oauth-authorization-server (RFC 8414).

1. Register a client

An owner or admin registers an OAuth client for the business (same policy as API keys — see who can create keys). Registration returns: Like an API key, a client is pinned to one business and owned by the member who created it. Its effective scopes are clamped to that member’s current role on every request.

2. Exchange for a token

POST /oauth/token at the API root (not under /v1). Authenticate with HTTP Basic (recommended) or client_id/client_secret form parameters:
scope is optional and space-delimited; omit it to receive every scope the client holds. Requesting a scope the client wasn’t granted returns invalid_scope — never a silent narrowing.

3. Call the API

Send the token exactly like an API key, on any /v1 endpoint or the MCP server:
Scope rules, error shapes, and rate limits are identical to API-key requests. Tokens expire after one hour — fetch a new one when you receive 401, and don’t cache tokens past expires_in.

Revocation

  • POST /oauth/revoke with token=ck_oat_… (client-authenticated, RFC 7009) kills one token immediately. A client can only revoke its own tokens.
  • Revoking the client in Cherry kills every outstanding token instantly and stops future issuance.
Use this flow when your product’s users connect their own Cherry business — a “Connect Cherry” button instead of copy-pasted credentials. It requires redirect URIs registered on the client (exact-match, https only except localhost/127.0.0.1), and PKCE with S256 is mandatory.
  1. Send the user to the consent page on the Cherry web app:
    The user signs in, sees your client’s name, the requested scopes, and which business the grant binds, and approves. The scopes a user can approve are capped by their own role — a read-only member cannot grant write.
  2. Receive the code. The browser returns to your redirect_uri with ?code=ck_ac_…&state=…. Codes are single-use and expire in 5 minutes.
  3. Exchange it (server-side, with your client secret and the PKCE verifier):
    The response includes a refresh_token (ck_rt_…) alongside the usual access token.
  4. Refresh. Refresh tokens rotate on every use — each refresh response carries a new refresh_token, and the old one dies. Presenting a retired refresh token is treated as theft and answers invalid_grant.
Tokens from this flow act as the consenting user: requests are attributed to them, and the token’s scopes are clamped to their current role on every call — if they leave the business, the grant stops working. POST /oauth/revoke accepts ck_rt_… refresh tokens as well as access tokens.

Partner apps (one credential, many businesses)

A partner client belongs to a vetted integrator instead of a single business, so one ck_client_…/ck_secret_… pair can be authorized by any number of Cherry businesses. Partner clients are registered by the Cherry team — talk to us to become one. The authorization-code flow above works unchanged, with three differences:
  • The consent screen asks which business. A user who belongs to several eligible businesses picks one; each approval creates a grant for that (partner, business) pair, and every token minted through it is bound to the grant.
  • Brand-new users can complete the flow. Someone with no Cherry account signs up right from the consent redirect and creates their business inline — they never leave the flow. While Cherry is in gated beta this needs the signup-gate capability on your partner record (Cherry grants it on request; it is off by default and revocable): with it enabled, Cherry’s sign-in page passes the user’s email through POST /oauth/signup-allowlist automatically and their signup is admitted. The endpoint always answers {ok:true} and is volume-bounded per partner.
  • client_credentials is refused for partner clients (unauthorized_client): without a user’s grant there is nobody for a machine token to act as. Mint tokens only through consent + refresh.
Disconnection is two-sided: you can revoke your own tokens (RFC 7009), and a business can disconnect your grant from Cherry without your involvement — the next API call answers 401 and the next refresh answers invalid_grant. Treat that pair of signals as “the customer disconnected; send them through consent again if they want to reconnect.”

Token endpoint errors