Appearance
API keys
Create, list, rebind, rotate, and revoke your API keys. These are dashboard-session operations: they need the signed-in web session, not an API key. A request authenticated with an API key (or by a team member acting for the owner) returns 403 forbidden, so a leaked key can never mint or change keys.
A key can be bound to a preset with defaultPresetId. A bound key needs no settings on POST /jobs — the request is just the key and the image. See Configuring your own settings.
Create a key
POST /keysBody
| Field | Type | Required | Notes |
|---|---|---|---|
label | string | no | A name for the key. Truncated to 120 characters. |
mode | live | test | no | Default live. |
class | secret | management | no | Default secret (the data-plane key used for jobs). |
scopes | string[] | no | Secret keys only. Narrows the default scopes (variants:write, jobs:read, inspect:read); it can never widen them. A key created with a narrowed list keeps exactly that list. |
defaultPresetId | string | no | Secret keys only. A system preset or one of yours. An unknown id is a 400. |
Response — 201 Created
The key's public meta plus the raw secret under key. You can read the full key again at any time from List keys.
json
{ "key": "fg_sk_live_…8f3c", "id": "key_…", "class": "secret", "mode": "live", "last4": "8f3c", "defaultPresetId": "preset_…", "state": "active" }List keys
GET /keysYour keys, newest first, each with its full key under secret: { "keys": [ { "id": "key_…", "last4": "8f3c", …, "secret": "fg_sk_live_…8f3c" } ] }. The response is sent with Cache-Control: no-store.
secret is null when no copy of the key is held yet: a key created before full keys were kept gets its copy the next time it is used successfully. It is also null for a revoked key. Keys still authenticate by hash; the copy is stored encrypted and is only ever returned here, to the signed-in owner.
Spend per key
GET /keys/usage?days=30Files produced and spend per key over the last days UTC calendar days, today included (days 1–90, default 30).
json
{
"days": 30,
"since": "2026-09-19T00:00:00.000Z",
"trackedSince": "2026-10-18T00:00:00.000Z",
"totals": { "files": 4620, "photos": 4620, "videos": 0, "ultraSafeFiles": 4620, "spendUsd": 129.36 },
"keys": [
{ "keyId": "key_…", "files": 4620, "photos": 4620, "videos": 0, "ultraSafeFiles": 4620, "spendUsd": 129.36,
"lastJobAt": "2026-10-18T09:12:44.000Z",
"daily": [ { "date": "2026-09-19", "files": 0, "spendUsd": 0 } ] }
]
}| Field | Notes |
|---|---|
files | Output copies requested by jobs created with the key (not uploads). |
ultraSafeFiles | Ultra Safe photo copies, billed at 2x. |
spendUsd | What your balance was debited when each job was created, at your plan's rate at that time. Refunds for failed or short jobs are credited separately and not subtracted here. |
trackedSince | When per-key counting started. Jobs before it are not attributed to a key. |
daily | Exactly days entries, oldest first, zero-filled. |
Keys with no jobs in the window are left out. 400 if days is out of range.
Bind, change, or clear a key's preset
PATCH /keys/{id}Change the default preset of an existing key without minting a new one.
Body
| Field | Type | Required | Notes |
|---|---|---|---|
defaultPresetId | string | null | yes | The preset to bind, or null to clear it. |
bash
curl -s -X PATCH "$API/keys/key_…" \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "defaultPresetId": "preset_…" }'Response — 200 OK
The key's updated public meta.
Errors
| Status | error | When |
|---|---|---|
400 | bad_request | defaultPresetId is missing or not a string/null, the preset is unknown, or the key is not a secret key. |
403 | forbidden | Not a dashboard session. |
404 | not_found | No active key with that id. |
Rotate a key
POST /keys/{id}/rotateReturns a new raw secret (once) in the same shape as create. The old secret keeps working for a short grace window so you can deploy the new one without downtime. 404 if there is no active key with that id.
Revoke a key
DELETE /keys/{id}Revokes the key immediately — the next request with it returns 401. Response: { "revoked": true, "id": "key_…" }. 400 if there is no active key with that id.