Connecting Samsa to an MCP client (Claude, ChatGPT, Claude Code, Cursor…)? The
MCP server uses these same API keys for headless clients and OAuth 2.1
sign-in for interactive ones — the scopes below apply to MCP tools identically.
How keys work
- Organization-owned. A key belongs to an organization, not a person. Anyone holding the key acts for that organization.
- Admin-created. Only an organization admin (
OWNERorADMIN) can create or revoke keys, in the app’s Settings → API Keys tab. - Scoped. Each key carries a set of scopes that determine which endpoints it can call. Keys are created with all scopes by default; narrow them to match what the integration needs.
- Shown once. The full secret is displayed exactly once, at creation.
The Authorization header
Send your key as a Bearer token on every request:
GET /me to confirm a key works — it
returns the key’s organization, its safe metadata (prefix, scopes, expiry), and the
organization’s available credit balance, but never the secret.
Scopes
Scopes follow a<resource>.<verb> shape. A request to an endpoint whose scope the
key lacks fails with 403 missing_scope.
| Scope | Endpoints unlocked |
|---|---|
images.generate | POST /images/generations, GET /images/generations/{id} |
images.edit | POST /images/edits, GET /images/edits/{id} |
videos.generate | POST /videos/generations, GET /videos/generations/{id}, GET /videos/models |
models.read | GET /models, GET /models/{id}, GET /models/{id}/status |
models.write | POST /models, POST /models/prepare, POST /models/{id}/complete, PATCH /models/{id}, DELETE /models/{id} |
usage.read | GET /credits, GET /usage |
GET /me needs any valid key — it requires no specific scope. New capabilities
add new scope strings; existing keys never inherit them automatically, so an admin
edits the key’s scopes or issues a new key to grant access.When authentication fails
Authentication and authorization failures return the standard error envelope. A missing, malformed, unknown, expired, or revoked key — or a key whose creator is no longer a member of the organization — returns401 invalid_api_key:
401 Unauthorized
403 missing_scope, naming
the required scope:
403 Forbidden
Expired and unknown keys both return
401 invalid_api_key — deliberately
indistinguishable, so an outsider cannot probe which keys once existed.Security best practices
Store keys in environment variables
Store keys in environment variables
Keep keys out of source control. Load them from an environment variable or a
secrets manager — never hard-code them.
Never expose keys client-side
Never expose keys client-side
The Samsa API is server-side first — CORS is deliberately restrictive and
browser calls from arbitrary origins are unsupported. A key in front-end code or
a mobile app is a leaked key. Always call the API from your backend.
Rotate by revoke + create
Rotate by revoke + create
There is no in-place rotation. To rotate, create a new key,
deploy it, then revoke the old one. Revocation is terminal and takes effect on
the very next request.
Set an expiry for short-lived integrations
Set an expiry for short-lived integrations
Keys can be created with an optional expiry. An expired key fails exactly
like an unknown one (
401 invalid_api_key). Use expiry for temporary
integrations, trials, and contractors.Rotating a key
- Create a new key in Settings → API Keys and copy it.
- Deploy the new key to your integration.
- Revoke the old key. Revocation is immediate and cannot be undone.
Key format
A key looks like:samsa_sk_ body is 43 base62 characters encoding 256 bits of randomness. In the
app, keys are displayed as samsa_sk_gK3n…3rAb (a stable prefix plus the last four
characters) so you can identify a key without exposing it.