Keyring

Tenants

A tenant is whatever you would put on an invoice, and it is what you are billed on.

A tenant is whatever you would put on an invoice. It belongs to the workspace, not to a project or an environment: a customer who uses two of your APIs in both test and live is still one tenant, so they are counted once.

  • You have customer organisations. One tenant per organisation. Several humans log in on the org's behalf; one tenant holds the keys, and one line appears on your invoice.
  • You have only user accounts, no organisation concept. One tenant per user account.
  • Never one tenant per user inside an organisation. It multiplies the bill (each tenant is a billable unit) and gives each member their own full scope: 'tenant' rate-limit quota instead of one shared one, which is not what "Acme gets 10,000 a day" means.

Tenants → New tenant takes an external id and a name. The external id is unique per workspace and is meant to be your identifier for that customer — the org id in the first shape above, the user id in the second — so a lookup from your side never needs a mapping table: mint the tenant, then store the id the call returns on that same row, indexed and unique, one column.

The Tenants page: two tenants and the New tenant form

curl -X POST https://api.keyringdev.com/v1/tenants \
  -H "Authorization: Bearer $KEYRING_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"external_id":"acme-corp","name":"Acme Corp"}'
{
  "object": "tenant",
  "id": "01a0...",
  "external_id": "acme-corp",
  "name": "Acme Corp"
}
-- your own table, after the call above
update organizations set keyring_tenant_id = '01a0...' where id = 'acme-corp';

That is true of this API call, and false of what arrives on a request — it is exactly where the sentence above misleads. "Looking a tenant up from your side" is the mint call, keyed on your external_id; a request carries req.keyring.tenantId, which is Keyring's id (01a0... above), never your external_id — the verified context has no external_id field at all. So a handler that needs your own row back looks it up by keyring_tenant_id (the column you just stored), not by re-deriving external_id from anything on the request.

What the tenant page shows

The tenant's page in the dashboard has its usage per project and environment, its keys, its settings (name and a free-form meta object), its embed sessions, and a delete control.

What a tenant is for

  • Verification. req.keyring.tenantId is the tenant the calling key belongs to. Your handler scopes its query on it.
  • Rate limits with scope: 'tenant' share one counter across every key the tenant holds, which is what "this organisation gets 10,000 a day" means and what survives a rotation.
  • Idempotency is scoped per (project, env, tenant), so a retry that arrives on a freshly rotated key still finds the record the old key wrote.
  • Billing. The billable unit is an active tenant per month, counted from live traffic only. Test-mode traffic never enters that count.

Deleting a tenant

Deleting a tenant revokes its keys in the same transaction, the same way deleting a project does.

On this page