Token reference
All five Amba token types — developer PAT, internal token, client key, server key, and end-user session JWT — with the exact header, endpoint group, lifetime, and what each cannot do.
Amba uses five distinct token types. They are not interchangeable: using the wrong token on an endpoint returns a specific error code that identifies the mismatch.
At a glance
| Token | Prefix | Header | Endpoint group | Lifetime |
|---|---|---|---|---|
| Developer PAT | amb_dpat_ | Authorization: Bearer | All /v1/admin/* | Until rotated |
| Developer JWT | eyJ… (HS256) | Authorization: Bearer | All /v1/admin/* | 24 h |
| Internal token | amb_int_ | Authorization: Bearer | Project-scoped /v1/admin/projects/:id/* only | Until rotated |
| Client API key | amb_dev_ck_ / amb_live_ck_ | X-Api-Key | All /v1/client/* | Until revoked |
| Server API key | amb_dev_sk_ / amb_live_sk_ | X-Api-Key or Authorization: Bearer | Project-scoped /v1/admin/projects/:id/* + server-side client calls | Until revoked |
| End-user session JWT | eyJ… (HS256) | Authorization: Bearer | User-scoped /v1/client/* | 30 days |
Developer PAT
Prefix: amb_dpat_ (followed by 32 base64url characters)
The recommended credential for every developer-authenticated call. The developer PAT is long-lived, doesn't require a refresh dance, and is the credential the MCP server and CLI use by default.
How to obtain:
- Returned as
data.patin thePOST /auth/developer/signupresponse (one-time — the plaintext is shown once). - Rotate at any time:
POST /auth/developer/pat/rotate(authenticated with the current PAT or a fresh session JWT). The old PAT becomes invalid within 30 seconds (cache TTL). Rotating also disconnects every app connected through OAuth (the console's Connected apps page lists them); the response'soauth_grants_revokedcounts them. - Via MCP:
amba_developer_rotate_pat.
Usage:
What it authenticates: All /v1/admin/* routes — project list/create, developer profile, API key management, every project-scoped admin operation.
What it cannot do:
- Authenticate
/v1/client/*routes (those require an API key inX-Api-Key). - Authenticate webhook endpoints (those use provider-specific HMAC signatures).
Storage: One PAT per developer account, stored as a sha256 hash in the control database — the plaintext is never persisted.
Developer JWT
Format: HS256 JWT (eyJ…) with claims type=developer, iss=amba, sub=<developerId>
The developer access JWT is issued alongside a refresh token by POST /auth/developer/signup and POST /auth/developer/login. The console uses it for browser-session auth; the MCP server mints a short-lived (5-minute) internal variant when converting an OAuth token to a downstream API call.
What it authenticates: Same /v1/admin/* surface as the developer PAT.
What it cannot do: Same restrictions as the developer PAT above. Additionally, it expires after 24 hours, and stops working as soon as its session ends (POST /auth/developer/logout, or a refresh token presented twice) — use the developer PAT for long-running agent or server contexts where a refresh loop is impractical. See Sessions.
How to obtain: The access_token field in the POST /auth/developer/signup, POST /auth/developer/login, or POST /auth/developer/otp/verify response (the last is the passwordless path: request a 6-digit code with POST /auth/developer/otp/request, then redeem it). Refresh via POST /auth/developer/refresh using the accompanying refresh_token (valid 30 days, rotating on use).
Internal token
Prefix: amb_int_ (followed by 32 base64url characters)
The internal token is a project-scoped credential. It authenticates a single project's subset of admin routes and is injected automatically into the Amba functions runtime as env.AMBA_INTERNAL_TOKEN. You never create or rotate it manually — Amba provisions it when your project is created and rotates it transparently with a 120-second overlap window.
What it authenticates: /v1/admin/projects/:projectId/* — but only for the project the token belongs to. Using a token from project A on a URL containing project B's ID returns 403 WRONG_PROJECT. Using an invalid or revoked token returns 401 INVALID_INTERNAL_TOKEN.
What it cannot do (and this is the common confusion):
- It does NOT authenticate global admin routes. Routes like
GET /v1/admin/projects(list all projects) orPOST /v1/admin/projects(create a project) require a developer PAT or JWT — they rejectamb_int_*with401 INVALID_DEVELOPER_TOKEN. If you seeINVALID_DEVELOPER_TOKENwhen making admin calls, you are using an internal token where a developer PAT is required. - It does NOT authenticate
/v1/client/*routes. - It does NOT authenticate another project's admin routes.
Usage inside a function:
The token is also used by Amba internal routing (the platform's own infrastructure components calling back into the API). That surface is not customer-accessible and is handled automatically — you only ever interact with this token through env.AMBA_INTERNAL_TOKEN in your functions.
Client API key
Prefixes: amb_dev_ck_ (development) / amb_live_ck_ (production)
The client API key is the project-identifying credential for all end-user-facing SDK and HTTP calls. It is not secret — it ships inside mobile apps and browser bundles by design.
How to obtain: The full key appears once, in the response that creates it: signup, POST /v1/admin/projects, or POST /v1/admin/projects/:projectId/api-keys (the amba_api_keys_create MCP tool). GET /v1/admin/projects/:projectId lists each key's key_prefix only, so store the key when you create it and mint a new one if it's lost.
Usage:
What it authenticates: All /v1/client/* routes when passed as X-Api-Key. User-scoped routes additionally require the end-user session JWT in Authorization: Bearer.
What it cannot do:
- Authenticate
/v1/admin/*routes. - Act on behalf of a specific user without a session token (use a server key +
X-On-Behalf-Offor server-side user operations).
Server API key
Prefixes: amb_dev_sk_ (development) / amb_live_sk_ (production)
The server API key is the server-side counterpart to the client key. It is secret — never embed it in a mobile app or browser bundle.
How to obtain: Same as client keys — returned in the project key set at signup, or created via POST /v1/admin/projects/:projectId/api-keys.
What it authenticates:
-
Project-scoped admin routes (
/v1/admin/projects/:projectId/*) — pass asAuthorization: Bearer:The server key is validated against the project it was created for; using it on a different project's URL returns
403 WRONG_PROJECT. -
Server-side client operations (
/v1/client/*on behalf of a user) — pass asX-Api-KeyalongsideX-On-Behalf-Of: <userId>:This is the mechanism the Node SDK's
asUser()method uses. The server key must belong to the project; theuserIdmust be a user in that project's database.
What it cannot do:
- Global admin routes (project list/create, developer auth) — those require a developer PAT.
- Replace the developer PAT for non-project-scoped operations.
End-user session JWT
Format: HS256 JWT (eyJ…) with claims type=session, sub=<userId>, pid=<projectId>
End-user session JWTs authenticate individual users on client-plane routes. The SDK acquires and rotates them automatically via the auth flow; you rarely handle them directly.
How to obtain: Returned as session_token by any /v1/client/auth/* sign-in endpoint. Refreshed automatically by the SDK; manually via POST /v1/client/auth/refresh.
Usage: Always paired with the client API key:
The pid claim inside the JWT must match the project that owns the X-Api-Key — the API rejects cross-project replays with 403 SESSION_PROJECT_MISMATCH.
Lifetime: 30 days. The refresh token that can renew it is valid for 90 days and rotates on use. A refresh token can be presented again within 30 seconds of its first use and returns a new pair, as long as the session it was exchanged for is still active; after that a replayed refresh token is detected and rejected.
Anonymous → identified is in place. When an anonymous user signs in via POST /v1/client/auth/link, Amba attaches the new credential to the same user — the user_id is unchanged and all of that user's data (collections, currency, inventory, streaks, XP, entitlements) is preserved. A link that adds an identity gives the user a new anonymous_id (returned in user.anonymous_id), and the old one no longer signs in to the user. The OTP / email-password link paths keep the existing session valid unless the call sends rotate_session: true. You never have to migrate anonymous data into a "real" account — there's only one account. See Account linking.
What it cannot do:
- Authenticate any
/v1/admin/*route. - Stand in for the
X-Api-Keyheader — both must be present on user-scoped client routes.
Quick-reference: error codes
| Error code | Meaning |
|---|---|
MISSING_AUTH_HEADER | No Authorization header where one is required |
INVALID_AUTH_SCHEME | Authorization header present but not Bearer |
MISSING_API_KEY | No X-Api-Key where one is required |
INVALID_API_KEY | API key hash not found or revoked |
INVALID_PAT | Developer PAT hash not found or revoked |
INVALID_DEVELOPER_TOKEN | Developer JWT failed signature or expiry check |
INVALID_INTERNAL_TOKEN | Internal token (amb_int_*) not found or revoked |
INVALID_SESSION_TOKEN | End-user session JWT failed signature or expiry |
SESSION_PROJECT_MISMATCH | Session JWT pid doesn't match the request's API key project |
WRONG_PROJECT | Server key or internal token used on a different project's URL |
PROJECT_NOT_FOUND | Project id malformed, or a project your token doesn't manage |
MISSING_ON_BEHALF_OF | Server key used on a user-scoped route without X-On-Behalf-Of |