Skip to main content
POST
Mint a new secret API key (lid_live_*) with exactly the scopes you choose.
The returned rawKey appears exactly once — only its SHA-256 hash is stored server-side. Store it the moment the call returns; losing it means revoking the key and minting a new one.

Authorization

This endpoint is dashboard-only. An API key can never create, list, or revoke API keys — a leaked key must not be able to clone itself or mint a more powerful one. Call it with a dashboard JWT with role merchant_admin, merchant_member (with team permission api-keys:manage) or super_admin. API-key callers are rejected with 401 {"error":"Invalid or expired token"} — the JWT guard runs first and an API key is not a session token, so the call never reaches the role check. The key is not revoked; it simply cannot authenticate a dashboard-only route. Rate limit: 5/min.
A super_admin passes the role guard, but platform accounts carry no merchant context, so the handler short-circuits with 400 {"ok":false,"error":{"code":"NO_MERCHANT_CONTEXT","message":"No merchant context"}}. In practice this endpoint is for merchant accounts.
MFA is required on this very call. The calling user must have TOTP enabled or a registered passkey — otherwise you get 403 {"ok":false,"error":{"code":"MFA_SETUP_REQUIRED",...}}. Anti-escalation for team members: a merchant_member can only put scopes on a key that their own team role already holds (minting a refunds:create key requires holding refunds:manage). Violations return 403 PERMISSION_ESCALATION. Owners (merchant_admin) skip this check.

Parameters

string
required
1–100 characters. Unique among your active keys (duplicate → 409 DUPLICATE_LABEL).
string[]
required
At least one entry. Any of the merchant scopes. Unknown values → 400 INVALID_PERMISSIONS.
string[]
Plain IPv4/IPv6 addresses (no CIDR). Invalid entry → 400 INVALID_IP. Empty/omitted = any IP.
integer
1–3650. Omit for a non-expiring key. Expired keys are rejected at verification time.
One strong factor is required on this call: either totpCode or passkeyResponse + challengeKey.
string
6–8 characters: TOTP or backup code. Required unless you pass a passkey assertion instead.
object
WebAuthn assertion (alternative to TOTP). Sent together with challengeKey.
string
Accompanies passkeyResponse.

Response fields

string
The key’s ID.
string
The secret key material. Appears exactly once — only its SHA-256 hash is stored server-side.
string
The key’s label.
string[]
The granted scopes.
string | null
Expiry timestamp, or null for a non-expiring key.

Errors

Backup codes are single-use and consumed atomically (two concurrent uses of the same code: only one wins).

See also