Skip to main content
This walks the order flow end to end. If your amounts are decided per request rather than drawn from a catalogue, read Invoices instead: the setup is identical and step 2 becomes a single POST /v1/invoices call with no product setup.
There is no test mode yet. Every payment method is a live chain and every payment moves real funds. Develop against small amounts, and expect a real transfer to be needed before an order reaches completed.

Before you start

Three things happen in the dashboard, not through the API. Create a store, enable at least one payment method and set a payout wallet for its chain — walked through in Create your store. Then create at least one listed product and note its id, a UUID: that is what you pass as productId. See Products. A store with no payment methods enabled cannot create orders, and an unlisted product is rejected at order creation with Product is not available.

Mint an API key with the scopes you need

In the dashboard’s developer settings, create a key. You must choose scopes; there is no implicit full-access key. For this quickstart:
  • orders:write — to create and expire orders
  • orders:read — to read them back
The raw key is shown once, at creation. Taberna stores only a SHA-256 hash, so if you lose it, revoke and mint a new one.Verify it works with the whoami call, which needs no scope at all:
The response carries the calling key’s own scopes, and enabledPaymentMethods confirms your setup landed. See the whoami endpoint for the full body.

Create an order

201 Created
Three things to do with that response:
  • Persist id. It is the order’s public short id and the value every webhook for this order carries as data.id.
  • Note expiresAt. 30 minutes from creation by default; pass expiresIn (10 minutes to 90 days) to widen it.
  • Use extraContext to carry your own correlation data. It is echoed back verbatim in every webhook for this order, which is how you find the user again.
The Idempotency-Key header makes the create safe to retry. A repeat with the same key returns the original order rather than minting a second one — no matter how the body changed.

Redirect the buyer to checkoutUrl

Send the customer to checkoutUrl. Everything from there is Taberna’s hosted page: the buyer picks a token from your enabled methods, gets a locked quote and a deposit address, pays, and watches confirmations tick up.When the payment completes, the page shows a Continue button pointing at your successUrl. The dead-end states — expired, partial — link to cancelUrl. Neither is required, but without successUrl the buyer simply stays on the hosted page.
Never grant anything based on the buyer arriving at your successUrl. It is a browser redirect with no authentication. Fulfil on the webhook, or on a server-side read of GET /v1/orders/:id.

Learn that it was paid

Two mechanisms, and you want the first.Webhooks (recommended). Set a webhook URL in the dashboard, save the returned tbrn_whsec_… secret, and handle order.completed:
Node.js (Express)
Polling (fallback). Read the order back from your server whenever a webhook did not arrive:
Act on status === "completed". See Webhooks for the full event list and signature scheme.

Authentication

The eight scopes, what each unlocks, and 401 versus 403.

Conventions

Money formats, timestamps, ids and the error shape.

Webhooks

Payload shapes and signature verification in three languages.

Payment lifecycle

State machines, partial payments, confirmation depths.