Skip to main content
Every request to the Samsa API is authenticated with an organization API key. Keys are scoped, shown once, and act for the organization that owns them — credits are drawn from that organization’s pool and generated assets appear in the app under the account of the admin who created the key.
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 (OWNER or ADMIN) 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.
Samsa stores only a SHA-256 hash of each key, never the plaintext. That is why a key can never be shown again or recovered — there is nothing to recover from. If you lose a key, revoke it and create a new one.

The Authorization header

Send your key as a Bearer token on every request:
Authorization: Bearer samsa_sk_your_key_here
curl https://api.samsa.ai/public/v1/me \
  -H "Authorization: Bearer $SAMSA_API_KEY"
Use 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.
ScopeEndpoints unlocked
images.generatePOST /images/generations, GET /images/generations/{id}
images.editPOST /images/edits, GET /images/edits/{id}
videos.generatePOST /videos/generations, GET /videos/generations/{id}, GET /videos/models
models.readGET /models, GET /models/{id}, GET /models/{id}/status
models.writePOST /models, POST /models/prepare, POST /models/{id}/complete, PATCH /models/{id}, DELETE /models/{id}
usage.readGET /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 — returns 401 invalid_api_key:
401 Unauthorized
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The provided API key is invalid, expired, or revoked.",
    "request_id": "req_8f14e45fceea167a"
  }
}
A valid key that lacks the endpoint’s scope returns 403 missing_scope, naming the required scope:
403 Forbidden
{
  "error": {
    "type": "permission_error",
    "code": "missing_scope",
    "message": "The API key is missing the required scope: images.generate.",
    "request_id": "req_1c9a3b7d2e5f4a80",
    "param": "scope"
  }
}
Expired and unknown keys both return 401 invalid_api_key — deliberately indistinguishable, so an outsider cannot probe which keys once existed.

Security best practices

Keep keys out of source control. Load them from an environment variable or a secrets manager — never hard-code them.
export SAMSA_API_KEY="samsa_sk_..."
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.
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.
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

  1. Create a new key in Settings → API Keys and copy it.
  2. Deploy the new key to your integration.
  3. Revoke the old key. Revocation is immediate and cannot be undone.

Key format

A key looks like:
samsa_sk_gK3n8vQ1xY7bT2mW9cR4jL6hF0dS5pZaU8eN1oI3rAb
└───┬───┘└──────────────────┬─────────────────────┘
 prefix           43 random base62 characters
The 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.
The constant samsa_sk_ prefix lets secret scanners (GitHub secret scanning, pre-commit hooks, CI checks) detect an accidentally committed Samsa key. Enable secret scanning on your repositories so a leaked key is caught before it ships.