/v1 merchant endpoint authenticates with a store API key sent as a bearer
token:
Key format
A live key is alwaystbrn_live_ followed by 48 hexadecimal characters. That is the
only accepted shape — anything else fails validation before it reaches the store
lookup.
The tbrn_live_ prefix exists so that a key leaked into a log, a screenshot or a
public repository is recognisable both to a human and to automated secret scanners.
A key is bound to one store. Taberna derives the store from the key, which is
why no
/v1 endpoint takes a store id — POST /v1/orders creates an order for the
key’s store and nothing else.Scopes
Scopes are chosen when the key is minted and are fixed for its lifetime. To change them, create a new key and revoke the old one.
Notes worth internalising:
- Invoice templates read under
invoices:read, not a scope of their own — they are invoice authoring material. webhooks:writeis replay only. It lets a key push a failed delivery back into the queue. It does not permit changing where a store’s events are sent; that stays a dashboard action.- Choosing scopes is mandatory. There is no implicit full-access key. An empty scope array, or an unknown scope name, is rejected at key creation.
The one endpoint that needs no scope
GET /v1/store — “whoami” — is callable by any valid key, whatever it was granted.
Its response includes the calling key’s own scopes array:
storefrontUrl is the canonical public origin of the store’s storefront (an active
custom domain wins over the slug subdomain) and is null while the storefront is
unclaimed or switched off.
401 versus 403
The two are not interchangeable and the distinction matters for how your client should react.- 401 — bad credential
- 403 — insufficient scope
Returned for every authentication failure: missing header, malformed header,
unknown key, revoked key, expired key.The body is always exactly
{ "error": "Unauthorized" }. The reason is
deliberately not disclosed — telling a caller “revoked” rather than “unknown”
would confirm to whoever is guessing that a key exists. Never branch on the body.The RFC 6750 challenge in the WWW-Authenticate header is the only signal that
distinguishes cases:Rotation and revocation
Keys are minted, listed and revoked from the dashboard by a store owner.1
The raw key is shown once
At creation, and only at creation. Taberna keeps a SHA-256 hash and cannot
recover the original. Put it straight into your secret manager.
2
Rotate by overlap, not by swap
Mint the new key first, deploy it, confirm traffic is flowing on it, then revoke
the old one. Because scopes are immutable, a scope change is always a rotation.
3
Revocation is immediate
A revoked key answers
401 on the next request. So does a key past its optional
expiresAt. Keys created without an expiry do not expire.A key’s
lastUsedAt is tracked, so the key list in the dashboard will tell you
whether a key you are about to revoke is still receiving traffic.