Docs
guides · API keys

API keys

Keys authenticate every request. Each can be tied to one project or span your whole account — and the secret is shown exactly once, at creation, then stored only as a hash you can't read back.

An API key is sent as a Bearer token on every request: Authorization: Bearer $DRIN_API_KEY. Manage keys in the dashboard under API Keys, or over the API with the endpoints below.

01 Project-scoped vs account-wide

A Drin account can hold several projects, each with its own sender identity, domains, and keys. How a key is scoped decides which projects it can act on — and whether you must name the project per request.

Project-scoped keyCreated with a senderId. Tied to one project; the project is implied, so you send with just the Authorization header. The recommended default — least privilege.
Account-wide keyCreated without a senderId. Spans every project, so you name the sender per request with the X-Drin-Product header (or the SDK's sender option).
Naming the project on an account-wide keyAccount-wide keys need X-Drin-Product: my-project on each request to say who's sending. Authentication covers the header and its X-Drin-Sender alias in full.

02 Create a key

POST/v1/api-keys

name is required and is for your own bookkeeping. Pass senderId to scope the key to one project; omit it for an account-wide key. An optional scopes array narrows what the key may do.

# Project-scoped: pass the project's senderId
curl https://api.drin.run/v1/api-keys \
  -H "Authorization: Bearer $DRIN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "production · receipts", "senderId": "snd_8f12" }'

The response includes the one-time secret. Every later read shows only the non-secret metadata — keyPrefix, last4, scope, and timestamps:

201 · secret shown once
{
  "id": "ak_0Q7d…",
  "name": "production · receipts",
  "keyPrefix": "drin_live",
  "last4": "9c2e",
  "senderId": "snd_8f12",
  "senderExternalId": "receipts",
  "scopes": [],
  "secret": "drin_live_3f9a…9c2e",
  "lastUsedAt": null,
  "revokedAt": null,
  "createdAt": "2026-06-02T09:00:00Z"
}
The secret is shown onceThe full secret is returned only in this create response. Drin stores a hash, never the secret itself — there is no endpoint to read it back. Copy it into your secret manager immediately. Lost it? Revoke the key and create a new one.

03 List keys

GET/v1/api-keys

A cursor-paged list of every key on the account. Secrets are never included — you see keyPrefix and last4 to identify a key, plus lastUsedAt and revokedAt.

curl https://api.drin.run/v1/api-keys \
  -H "Authorization: Bearer $DRIN_API_KEY"

04 Revoke a key

DELETE/v1/api-keys/{id}

Revoking takes effect immediately — the next request using that key gets a 401. Revocation is permanent; there's no un-revoke. Returns 204 No Content.

curl -X DELETE https://api.drin.run/v1/api-keys/ak_0Q7d \
  -H "Authorization: Bearer $DRIN_API_KEY"
Don't revoke the key you're holdingMint and deploy the replacement first, then revoke the old key. A revoked key that's still in use anywhere — a worker, a cron job, the dashboard's own service key — turns every one of its requests into a 401 the moment it's gone.

05 Scoping & security

  • Server-side only. A key is a secret. Never embed one in a browser, mobile app, or anything shipped to a user — it grants full send and account access.
  • Prefer project-scoped keys. Give each project — and ideally each environment and service — its own key. The blast radius of a leak is then one project, and revoking it touches nothing else.
  • One key per environment. Separate production, staging, and CI so you can rotate or revoke one without disrupting the others.
  • Rotate on suspicion. If a key might have leaked, revoke it and create a new one. lastUsedAt helps you spot a key that's active when it shouldn't be, or stale and safe to retire.
Name keys for their jobA descriptive name like prod · receipts-worker makes the list self-documenting and makes the right key obvious when it's time to rotate.

06 Related