Docs menu

API keys API reference

Create, list and revoke API keys.

View as Markdown

List API keys

GET /api-keys

Auth: API key with scope keys:manage, or access token.

Requires keys:manage. Non-revoked keys, newest first (max 100). Secrets are never returned. An API key caller sees only keys of its own environment.

Credits. Free: no credits.

Responses

200 Keys.

Schema ApiKeyList (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

Example 200 response
{
  "data": [
    {
      "id": "7d0e1a52-3c4b-4f6e-9a8d-2b1c0f9e8a7d",
      "name": "string",
      "prefix": "ss_live_AbCd",
      "environment": "live",
      "scopes": [],
      "status": "active",
      "createdAt": "2026-10-21T12:00:00.000Z",
      "lastUsedAt": "2026-10-21T12:00:00.000Z",
      "expiresAt": "2026-10-21T12:00:00.000Z"
    }
  ]
}
400 INVALID_INPUT. A credential sent in the query string is refused before authentication, without RateLimit headers.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

401 UNAUTHORIZED: missing, malformed, unknown, revoked or expired credential.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

403 FORBIDDEN: see details.reason.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

429 RATE_LIMITED: the request rate of the API key (details.scope key) or of the account (user) is exhausted for this window, or too many failed authentication attempts came from this IP (no details.scope and no RateLimit headers). Retry after Retry-After seconds.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy , Retry-After

default Error (see ErrorEnvelope and /v1/docs/errors).

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

Create an API key

POST /api-keys

Auth: API key with scope keys:manage, or access token.

Requires keys:manage. The full key is in this response only. An API key acting as the manager can only create keys for its own environment with a subset of its own scopes.

Credits. Free: no credits.

Request body application/json

Required. Schema CreateApiKeyRequest.

FieldTypeDescription
namerequiredstring1–64 characters after trimming; need not be unique.
environmentrequiredApiKeyEnvironment
scopesarray of ApiKeyScopeDefaults to every scope except keys:manage, billing:read, billing:write, webhooks:read and webhooks:write.
expiresAtstringOptional RFC 3339 expiry, in the future and at most 365 days ahead.Format: date-time
Example request body
{
  "name": "string",
  "environment": "live",
  "scopes": [
    "generations:write"
  ],
  "expiresAt": "2026-10-29T12:00:00.000Z"
}

Responses

201 Created. Store key now; it is never shown again.

Schema CreatedApiKey (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

Example 201 response
{
  "id": "7d0e1a52-3c4b-4f6e-9a8d-2b1c0f9e8a7d",
  "name": "string",
  "prefix": "ss_live_AbCd",
  "environment": "live",
  "scopes": [
    "generations:write"
  ],
  "status": "active",
  "createdAt": "2026-10-21T12:00:00.000Z",
  "lastUsedAt": "2026-10-21T12:00:00.000Z",
  "expiresAt": "2026-10-21T12:00:00.000Z",
  "key": "string"
}
400 INVALID_INPUT. A credential sent in the query string is refused before authentication, without RateLimit headers.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

401 UNAUTHORIZED: missing, malformed, unknown, revoked or expired credential.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

403 FORBIDDEN: see details.reason.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

413 PAYLOAD_TOO_LARGE.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

429 RATE_LIMITED: the request rate of the API key (details.scope key) or of the account (user) is exhausted for this window, or too many failed authentication attempts came from this IP (no details.scope and no RateLimit headers). Retry after Retry-After seconds.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy , Retry-After

default Error (see ErrorEnvelope and /v1/docs/errors).

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

Revoke an API key

DELETE /api-keys/{id}

Auth: API key with scope keys:manage, or access token.

Requires keys:manage. Idempotent: revoking an already-revoked key returns 204. Takes effect on the next request.

Credits. Free: no credits.

Parameters

Name In Type Description
id required path string Format: uuid

Responses

204 Revoked.

Headers: X-Request-Id , RateLimit , RateLimit-Policy

400 INVALID_INPUT. A credential sent in the query string is refused before authentication, without RateLimit headers.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

401 UNAUTHORIZED: missing, malformed, unknown, revoked or expired credential.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

403 FORBIDDEN: see details.reason.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

404 NOT_FOUND: no such resource for this caller.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

429 RATE_LIMITED: the request rate of the API key (details.scope key) or of the account (user) is exhausted for this window, or too many failed authentication attempts came from this IP (no details.scope and no RateLimit headers). Retry after Retry-After seconds.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy , Retry-After

default Error (see ErrorEnvelope and /v1/docs/errors).

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , RateLimit , RateLimit-Policy

Start device authorization

POST /auth/device

No authentication.

No authentication. For an agent or tool without an API key (RFC 8628): returns a user_code and a console link for its human, and a secret device_code to poll POST /auth/device/token with every interval seconds. The human signs in to the developer console, checks the request and approves or denies it; on approval the next poll returns a new API key. Codes expire after expires_in seconds (10 minutes) and work once. Accepts JSON or application/x-www-form-urlencoded. Device authorization may be disabled on a server: then this answers 404 NOT_FOUND. Limited per IP address (429 RATE_LIMITED with Retry-After).

When to use. When STORESHOT_API_KEY is not set: start here, show your human verification_uri_complete and user_code, then poll POST /auth/device/token.

Credits. Free: no credits.

Request body application/json

Optional. Schema DeviceAuthorizationRequest.

FieldTypeDescription
client_namestringYour tool’s name, shown to the human as an unverified label. 1–64 printable ASCII characters. When absent, client_id is used instead (generic OAuth libraries send one).
scopestringSpace-separated scopes for the new key. Default generations:write generations:read uploads:write usage:read. keys:manage, billing:write and webhooks:write cannot be requested. The human may narrow the list, or add billing:read and webhooks:read.
environmentApiKeyEnvironmentEnvironment of the new key. Default live.
Example request body
{
  "client_name": "Claude Code",
  "scope": "generations:write generations:read uploads:write usage:read",
  "environment": "live"
}

Request body application/x-www-form-urlencoded

Optional. Schema DeviceAuthorizationRequest.

FieldTypeDescription
client_namestringYour tool’s name, shown to the human as an unverified label. 1–64 printable ASCII characters. When absent, client_id is used instead (generic OAuth libraries send one).
scopestringSpace-separated scopes for the new key. Default generations:write generations:read uploads:write usage:read. keys:manage, billing:write and webhooks:write cannot be requested. The human may narrow the list, or add billing:read and webhooks:read.
environmentApiKeyEnvironmentEnvironment of the new key. Default live.

Responses

200 Started. Show verification_uri_complete and user_code to the human.

Schema DeviceAuthorization (application/json).

Headers: X-Request-Id , Cache-Control

Example 200 response
{
  "device_code": "string",
  "user_code": "BCDF-GHJK",
  "verification_uri": "https://console.storeshot.art/device",
  "verification_uri_complete": "https://console.storeshot.art/device?code=BCDF-GHJK",
  "expires_in": 600,
  "interval": 5
}
400 INVALID_INPUT: see details.issues.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

404 NOT_FOUND: device authorization may be disabled on this server, and then both operations answer the /v1 404 envelope.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

429 RATE_LIMITED: too many requests from this IP address, or too many pending ones (details.reason too_many_pending). Retry after Retry-After seconds.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id , Retry-After

default Error (see ErrorEnvelope and /v1/docs/errors).

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

Poll for the device authorization result

POST /auth/device/token

No authentication.

No authentication. Send grant_type=urn:ietf:params:oauth:grant-type:device_code and the device_code from POST /auth/device, as application/x-www-form-urlencoded (RFC 8628 §3.4) or JSON. Poll every interval seconds until the human decides. Approved: 200 with the new API key in access_token, returned once; the code then answers invalid_grant. Errors here are the one deliberate exception to ErrorEnvelope: refusals are HTTP 400 { "error", "error_description" } (RFC 6749 §5.2) with error authorization_pending (keep polling), slow_down (add 5 seconds to your interval; Retry-After gives the new one), access_denied, expired_token (start again), invalid_grant, invalid_request or unsupported_grant_type. The X-Request-Id header is on every response: quote it to support. Other failures (404 while device authorization is disabled on this server, 413, 5xx) use ErrorEnvelope.

When to use. Every interval seconds after POST /auth/device, until it returns the key; add 5 s on slow_down; stop on access_denied or expired_token.

Credits. Free: no credits.

Request body application/x-www-form-urlencoded

Required. Schema DeviceTokenRequest.

FieldTypeDescription
grant_typerequiredstringOne of: "urn:ietf:params:oauth:grant-type:device_code"
device_coderequiredstring

Request body application/json

Required. Schema DeviceTokenRequest.

FieldTypeDescription
grant_typerequiredstringOne of: "urn:ietf:params:oauth:grant-type:device_code"
device_coderequiredstring
Example request body
{
  "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
  "device_code": "string"
}

Responses

200 Approved: the new API key. Store access_token now; it is never shown again.

Schema DeviceToken (application/json).

Headers: X-Request-Id , Cache-Control , Pragma

Example 200 response
{
  "access_token": "string",
  "token_type": "Bearer",
  "scope": "string",
  "key_id": "7d0e1a52-3c4b-4f6e-9a8d-2b1c0f9e8a7d",
  "environment": "live"
}
400 OAuth error (RFC 6749 §5.2), not ErrorEnvelope. slow_down also carries Retry-After.

Schema DeviceTokenError (application/json).

Headers: X-Request-Id , Retry-After

404 NOT_FOUND: device authorization may be disabled on this server, and then both operations answer the /v1 404 envelope.

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id

default Error (see ErrorEnvelope and /v1/docs/errors).

Schema ErrorEnvelope (application/json).

Headers: X-Request-Id