Skip to main content
Key management is self-serve: any key holding api-keys.write can mint another, so rotation needs no dashboard and no downtime. Concepts in Authentication.

Create a key

Success: 201.
"test" | "live"
default:"test"
Determines both the key’s prefix and what it can reach.
  • testck_test_…. Confined to sandbox merchants, whatever the account’s status.
  • liveck_live_…. Can check out at real merchants.
A sandbox-only account cannot create a live key.
string
Optional, max 200 characters. Shown in the list; never sent anywhere.
string[]
1–32 entries. Omit for full access — the key gets ["*"], which is what a key has always meant here and what every key issued before scopes existed still carries.Valid values:
write implies read on the same resource, so ["checkouts.write"] is enough to create, poll, cancel and answer checkouts. Scopes are fixed at creation — there is no re-scoping.
string
Bind the key to one of your end users. 1 to 200 characters after trimming, your own opaque id — we never generate one. Omit for a tenant-wide key, which is what every key issued before this existed already is. "" is a 400, not a tenant-wide key by another name.A bound key sees and creates only that subject’s checkouts and buyer profiles, and is refused outright on the account-wide endpoints (GET/DELETE /v1/api-keys, /v1/usage, /v1/webhooks). Fixed at creation — there is no rebinding and no unbinding.Minting from a bound key inherits the binding: omitting subject gives you another key for the same end user, not a tenant-wide one, and naming a different subject is a 403. Full contract in End-user isolation.
An empty body is valid and produces a full-access test key — tenant-wide, unless the key you called with is itself bound. The body is otherwise strict: an unknown field is a 400 with an unrecognized_keys issue, so a misspelled subjectt cannot hand you a tenant-wide key you believed was bound.
Response (201) — the bound variant
subject appears here only when the key is bound. A tenant-wide key’s creation response has no subject field at all.
key is returned exactly once, here. Only sha256(key) is stored — no endpoint, support process or database query can recover it.
string
The first 16 characters. Safe to store and display next to a key row — it identifies which key without being one.

Errors

400 — bad scope string
403 — escalation refused
The no-escalation check is what stops api-keys.write being a one-call route to *. A key can only ever hand out authority it already holds, so the widest key in your account is the widest key that can ever exist in it.

List keys

Success: 200.
Read data. It is the field checkouts, buyer profiles and webhook endpoints already answer with, and this route now matches them. The response also repeats that identical array as keys — the field’s original name, elided from the example above for length. It is kept because existing callers and the published MCP client read it, and it is not going away; data is simply the one to write new code against. nextCursor is always null here — the collection is small and tenant-bounded, so there is nothing to page. It exists so a generic list helper does not need a special case. Newest first. Revoked keys are included, with revokedAt set — filter client-side if you only want active ones. Listing never returns a secret. keyPrefix is the most a list can show. It does return scopes, which is how you audit what each outstanding key can reach; ["*"] is a full-access key.
string | null
Always present here, unlike on the creation response. null is a tenant-wide key; a string is a key bound to that one end user. This listing is the only place you can audit which of your keys act for whom — see End-user isolation.
string | null
Written best-effort on every authenticated request; never blocks it. A good rotation signal, not an audit log.
A subject-bound key cannot call this endpoint or DELETE /v1/api-keys/{id} — both are 403. The key list is a tenant-wide fact, and revocation is a tenant-wide power: a credential acting for one end user must not be able to enumerate its siblings or take the account’s own key offline.

Revoke a key

Success: 200.
Takes effect immediately. Revocation is a timestamp, not a row delete — knowing which key was live when matters more than a tidy table if one is ever abused. 404 Key not found or already revoked covers all three cases: unknown id, another tenant’s key, and one already revoked.
Nothing stops a key revoking itself. Revoke the old key after you have confirmed the new one is in use — check that the old key’s lastUsedAt has stopped advancing.