API keys.
How to create, list, and revoke keys programmatically — and through the dashboard. Plus the practices that keep them out of the wrong hands.
§ 01Overview
The endpoints on this page are session-protected — they are how the dashboard manages your keys. The keys themselves are then used to authenticate calls to the data-plane API (/api/v1/...) using Authorization: Bearer esk_.... Two different layers, one identity model.
essarion_session cookie, not with an esk_ key. In practice you'll usually create and revoke keys from the dashboard UI; the endpoints exist for power users running their own admin tooling.§ 02List keys
Returns every key on the calling account, ordered by created_at descending. Plaintext is never included — only the prefix.
| Field | Type | Description |
|---|---|---|
| id | string | Stable id for the key. Use this to revoke. |
| name | string | Human label you set at creation. |
| prefix | string | First few characters of the key — esk_live_a1b2 — for display only. |
| status | string | active, revoked, or inactive. |
| created_at | string | ISO-8601 creation timestamp. |
| last_used_at | string | ISO-8601 last successful auth timestamp. Null if never used. |
curl https://api.essarion.com/api/keys \
-H "Cookie: essarion_session=$ESSARION_SESSION"
{
"keys": [
{
"id": "key_01HXYZAAA",
"name": "prod-backend",
"prefix": "esk_live_a1b2",
"status": "active",
"created_at": "2026-04-12T08:00:00Z",
"last_used_at": "2026-05-01T13:55:21Z"
},
{
"id": "key_01HXYZBBB",
"name": "local-dev",
"prefix": "esk_test_c3d4",
"status": "active",
"created_at": "2026-03-22T15:14:09Z",
"last_used_at": null
}
]
}
§ 03Create a key
Creates a new key on the calling account. The response includes the plaintext field — once. Subsequent reads will never include it.
Request body
| Param | Type | Required | Description |
|---|---|---|---|
| name | string | yes | Human label. 1-64 characters. Use it to track where the key is deployed. |
curl https://api.essarion.com/api/keys \
-X POST \
-H "Cookie: essarion_session=$ESSARION_SESSION" \
-H "Content-Type: application/json" \
-d '{"name": "prod-backend"}'
{
"id": "key_01HXYZAAA",
"name": "prod-backend",
"prefix": "esk_live_a1b2",
"plaintext": "esk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0",
"status": "active",
"created_at": "2026-05-01T14:30:00Z",
"last_used_at": null
}
plaintext is returned exactly once, in this response. We store only the SHA-256 hash. If you don't capture the plaintext now, the key is unrecoverable — you'll have to revoke it and create a new one.§ 04Revoke a key
Marks the key as revoked. The change is immediate — within a few seconds, calls authenticated with the revoked key will return 401 with code KEY_REVOKED. Revocation is permanent; you cannot reactivate.
curl https://api.essarion.com/api/keys/key_01HXYZAAA \
-X DELETE \
-H "Cookie: essarion_session=$ESSARION_SESSION"
§ 05Best practices
The technical surface is small. The practices around it are what keep your account safe.
Rotate periodically
Even without a known compromise, rotate keys on a schedule. Quarterly is a sensible default for production, monthly for high-risk environments. Create the new key, deploy it, verify traffic on the new prefix in the dashboard, then revoke the old.
Scope keys to environments
One key per environment, per service. Don't share local-dev with prod, don't share prod-backend with the cron worker. When something does go wrong, granular keys mean the blast radius of a revocation is one service, not the whole stack.
Store as env vars or in a secrets manager
Read keys from process.env / os.environ at runtime; populate the env from your platform's secrets manager. Never write keys to log lines, error reports, or shell history.
Never commit, never ship to clients
Add .env* to your .gitignore and verify with a pre-commit secret scanner. Never embed keys in a frontend bundle, mobile app, or browser extension — anything that ships to a user can be reverse-engineered. Browser-side workflows must broker through your own backend.
last_used_at on every key. Audit periodically; any key that hasn't been used in 90 days is a candidate for revocation, even if it's not in active rotation.