Bitcall logoBitcall API
The Gateway

Key Management

How admins mint, scope, rotate, and revoke API keys and manage tenant access.

Key management is the control plane of the gateway. It's where admins mint keys, decide what each key can do, and manage per‑tenant access to products and rate limits. This is the feature everything else depends on.

The management API

Management operations live on a separate, internal API — not the public /v1/* surface.

  • It binds to loopback only (127.0.0.1, default port 8081) and is never exposed publicly, regardless of how the public API is bound. Reach it locally or over an SSH tunnel.
  • Every operation is a POST to /internal/keymgmt/<action>.
  • It uses its own auth: a single x-mgmt-secret header carrying a signed, action‑bound envelope (distinct from the key id + secret used by /v1/*), with a tighter ±60s clock skew and its own nonce replay protection.

Because it can mint credentials, the management API is operator‑only. Keep it behind loopback/SSH; never route it through a public load balancer.

Who can manage what

Authority follows the role hierarchy client < admin < superadmin, and the gateway never trusts the caller's claims — it enforces these rules itself:

  • superadmin — cross‑tenant; may manage any tenant's keys and platform‑wide settings.
  • admin — bound to its own tenant; manages keys for its own principal only.
  • client — bound to its own tenant and its own user.

An actor can only mint a key whose role is at or below its own, and only with scopes that fit that key's role tier. A client key can never be granted admin/super scopes.

Operations

All paths below are POST /internal/keymgmt/<action>.

Keys

ActionBodyResult
key/create{ targetId, userId, role, principalKind?, grantedScopes[], allowedIps[], rateLimit }Creates a key. Returns { keyId, secret, createdAt }secret shown once.
keys/list{ targetId, userId? }Lists keys (never secrets). Non‑super callers see only their own principal.
key/rotate{ keyId }Mints a replacement and revokes the old key. Returns the new { keyId, secret }.
key/revoke{ keyId }Revokes a key. Idempotent; unknown/out‑of‑scope ids return { ok: true } without leaking.
key/scopes{ keyId, grantedScopes[] }Replaces the key's granted scopes (must fit its role tier).

Tenant features & user access

ActionBodyResult
feature/set{ targetId, feature, enabled }Turns a product on/off for a tenant (admin+).
user/disable-api{ targetId, userId, api }Disables one API for a user (admin+).
user/enable-api{ targetId, userId, api }Re‑enables it.

Rate limits

ActionBodyResult
rate/set-default{ role, windowSec, max }Platform‑wide default for a role (superadmin only).
rate/set-override{ targetId, userId, windowSec, max }Per‑principal override (superadmin only).
rate/clear-override{ targetId, userId }Clears an override (superadmin only).
rate/effective{ targetId, userId, role? }Reports the resolved limit and where it came from.

Minting a key

A key/create request:

{
  "targetId": "NEWDEVT",
  "userId": 42,
  "role": "client",
  "grantedScopes": ["otp:read", "otp:purchase"],
  "allowedIps": [],
  "rateLimit": { "windowSec": 60, "max": 120 }
}

Response — capture the secret now, it will not be shown again:

{
  "keyId": "ak_test_1a2b…",
  "secret": "9f83…",
  "createdAt": "2026-07-17T10:00:00.000Z"
}

Hand the keyId + secret to the integrating app; it signs requests with them as shown in the Quick Start.

allowedIps: [] means "any IP". To lock a key to known egress addresses, list them as exact IPs or CIDR ranges.

Good practices

  • Least privilege. Grant only the scopes an integration needs; widen later with key/scopes.
  • Rotate on leak. Any suspected exposure → key/rotate, roll out, then the old key is already revoked.
  • One key per integration. Separate keys make revocation and auditing surgical. (Minting more keys does not raise quota — rate limits are per principal, not per key.)

On this page