Tenants and API keys
A tenant is an organisation using Paprika: its templates, fonts, brand kits, outputs, keys and usage are its own, and no other tenant’s requests can reach them. Its systems and people use API keys, each acting for the tenant within its scopes. The admin API, under /v1/admin, makes and manages both. The operator operations are in the API reference.
The admin token
Section titled “The admin token”The admin API takes the token in PAPRIKA_ADMIN_TOKEN instead of an API key. Several can be listed, comma-separated, so a new one can be brought in before the old one is removed; without one the admin API is off. Keep it off the internet (security).
The examples use the API’s address and the token:
export PAPRIKA_URL=http://localhost:4179export PAPRIKA_ADMIN_TOKEN=…Without the token, or with a wrong one, the answer is 401:
curl "$PAPRIKA_URL/v1/admin/tenants"{ "code": "admin-unauthorized", "message": "A valid admin token is required: Authorization: Bearer …", "requestId": "fab35336"}Tenants
Section titled “Tenants”Make a tenant with an id (lower-case letters, digits and dashes, fixed for good) and a name:
curl -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" -H "Content-Type: application/json" -d '{"id": "fabrikam", "name": "Fabrikam"}' "$PAPRIKA_URL/v1/admin/tenants"{ "id": "fabrikam", "name": "Fabrikam", "tier": null, "retentionDays": null, "createdAt": "2026-11-10T15:51:56.007Z", "suspendedAt": null, "deletedAt": null}An id taken already is 409 tenant-exists. List every tenant, local (the editor’s) among them:
curl -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants"Change a tenant’s name, how many days its unused uploads are kept (retentionDays, 30 when null) or its tier (scheduler):
curl -X PATCH -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" -H "Content-Type: application/json" -d '{"retentionDays": 90}' "$PAPRIKA_URL/v1/admin/tenants/fabrikam"Issue a key with a name and its scopes, and an expiresAt if it should stop working on a date:
curl -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" -H "Content-Type: application/json" -d '{"name": "website", "scopes": ["render"], "expiresAt": "2030-01-01T00:00:00Z"}' "$PAPRIKA_URL/v1/admin/tenants/fabrikam/keys"{ "key": "ppk_Vb7Qm2Rk9TxW_s3cr3tExampleOnly", "id": "Vb7Qm2Rk9TxW", "tenant": "fabrikam", "name": "website", "scopes": ["render"], "createdAt": "2026-11-10T15:51:56.052Z", "expiresAt": "2030-01-01T00:00:00.000Z", "revokedAt": null, "lastUsedAt": null, "rotatedTo": null, "tier": null}The secret, key, is shown only in this answer. The scopes are:
| Scope | Allows |
|---|---|
render |
Reading templates and versions, rendering, jobs, batches, outputs and named resources, reading the font library |
publish |
Making templates and versions, changing the font library and brand kits |
keys |
The tenant’s own keys and webhooks |
A tenant with a keys key manages its own keys from then on (authentication), never giving one more scopes than its own. List a tenant’s keys, with when each was last used:
curl -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam/keys"Rotate a key to replace it without an outage: the answer is a new key, and the old one keeps working for 24 hours.
curl -X POST -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam/keys/Vb7Qm2Rk9TxW/rotate"Revoke one that may have leaked: it stops working at once.
curl -X DELETE -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam/keys/Vb7Qm2Rk9TxW"Suspend, delete and restore
Section titled “Suspend, delete and restore”Suspending a tenant stops its keys at once and cancels its queued jobs; its data stays. Resuming gives its keys back:
curl -X POST -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam/suspend"curl -X POST -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam/resume"Deleting a tenant refuses its keys at once too. For 30 days it can be restored as it was; after that the hourly sweep purges every row and file of it, keeping only its usage for the last bill (metering).
curl -X DELETE -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam"curl -X POST -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/fabrikam/restore"{ "id": "fabrikam", "name": "Fabrikam", "tier": null, "retentionDays": 90, "createdAt": "2026-11-10T15:51:56.007Z", "suspendedAt": null, "deletedAt": null}The editor’s tenant, local, can’t be deleted:
curl -X DELETE -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/tenants/local"{ "code": "bad-request", "message": "Bad request: the local tenant cannot be deleted", "requestId": "d60827d6"}The audit log
Section titled “The audit log”Every change to tenants and keys, by the admin or by a tenant’s own keys key, and every font rights assertion (fonts) is written to the audit log, kept 400 days. Read a tenant’s, newest first:
curl -H "Authorization: Bearer $PAPRIKA_ADMIN_TOKEN" "$PAPRIKA_URL/v1/admin/audit?tenant=fabrikam"[ { "at": "2026-11-10T15:49:12.358Z", "tenant": "fabrikam", "actor": "admin", "action": "tenant.restored", "target": "fabrikam", "details": null, "requestId": "e7cb5dd9" }]