Skip to content

Authentication & scopes

API keys, the four scopes, rotation, test vs live, and which endpoint needs what.

Updated 2026-09-28

API keys

Every request carries a key as a bearer token: Authorization: Bearer sticky_live_…. Keys are created on the Developers page of the admin (under Advanced in the sidebar) with New API key, shown once, and stored only as a hash. A key belongs to one programme and one mode:

  • sticky_test_… writes to the programme's sandbox — see Test mode.
  • sticky_live_… writes to the real programme.

Keys issued before the rename (cvos_live_…, cvos_test_…) keep working forever.

Scopes

A key carries one or more of four scopes. Give each integration the least it needs.

ScopeLets the key…
ingestSend events, and read back the status of the events it sent.
readRead members, ledgers, redemptions, reservations, the programme, liability, programme versions and export jobs; run simulations; mint member session tokens; ask for redemption quotes.
actEnrol, resolve, update and erase members; adjust balances; reserve, redeem, confirm, void, release; apply referrals; mint portal links; queue and download exports.
webhooksManage webhook endpoints.

Every operation in the reference states its scope as x-required-scope. A key without it gets 403 forbidden with the missing scope in detail. Two answers are about the programme, not the key: 403 with reason: plan_restricted means the programme's plan does not include the API, and 402 payment-required means the programme has no active plan at all.

A live key with act or ingest can change balances, and one with read or webhooks can reach members' personal details, so only a programme owner or admin can create or rotate a live key, and only within a few minutes of signing in. When the programme asks for second approval, creating one is a request, not a key: nothing exists until a second owner or admin approves it under Approvals. Then the person who asked goes back to Developers, presses Create the approved key within 7 days, and sees the key once — nobody else ever does. (An owner or admin with nobody else to approve creates the key directly, on a fresh sign-in.) Rotating an existing key needs no second approval. Test keys, with any scope, can be created by anyone with access to Developers.

Adjusting balances with a key

POST /v1/members/{id}/adjust (scope act) follows the same rules as a person in the admin:

  • Approval limit. An adjustment over the programme's approval limit — or any debit, when debits need approval — is not posted. You get 202 with data.status: "pending_approval" and data.approval_request_id, and a teammate decides it under Approvals. Resend the same Idempotency-Key to see its current status (pending_approval, approved, rejected or cancelled); balance.updated fires if it is approved and posted. If nobody but the key's creator could approve it, the call is refused with 403 and reason: approval_required — make it in the admin instead.
  • Daily credit cap. Credits through one key (and its rotated replacements) are capped per UTC day: the programme's own setting, else 20 × its approval limit, else 10,000 in the programme's currency (1000000). Over the cap you get 429 with reason: daily_credit_cap, cap_cents, used_cents, resets_at and a Retry-After that runs to midnight UTC. Debits are never capped.
  • No negative balances. A debit larger than the member's spendable balance is 422 balance-insufficient, and nothing is written. A plan that cannot add liability answers credits with 409 and reason: plan_restricted.

Which key for what

You are building…Scopes
A store that sends orders and shows balancesingest, read
…that also redeems at checkout or enrols customersadd act
A till that issues and confirms vouchersread, act
A reporting syncread
A webhook receiver's configuration scriptwebhooks

Rotation and revocation

Rotate mints a new key with the same scopes; the old one keeps working for 24 hours so you can deploy the new one first. A key already rotated can't be rotated again (rotate its replacement), and the replacement shares the old key's daily credit cap and its adjust Idempotency-Keys. Revoke stops a key immediately, with no grace — use it for a leaked key; adjustments it left waiting for approval are cancelled.

Test vs live in one integration

Read the mode from GET /v1/ping (data.mode) rather than parsing the prefix, and never let a test key's data reach live code paths: the sandbox is a separate programme with its own members.

Member session tokens are not API keys

A browser or app never holds an API key. Your server mints a member session token (POST /v1/members/{id}/session-tokens, scope read) — read-only, one member, 15 minutes — and the page uses it against GET /v1/public/member only. See A mobile app.

Authentication & scopes — StickyTier API