Skip to main content
Taberna hosts the page the buyer pays on, and drives it through the /v1/checkouts endpoints. You normally never call them — you redirect to the URL Taberna returned and wait for a webhook. They are documented because you may need to read one, and because their trust model explains why no API key is involved. Always use the URL Taberna returned. Do not construct it yourself — the host is environment-specific and the path may change. What the buyer actually sees on that page is described in Orders and payments.

The trust model

These endpoints are deliberately unauthenticated, because they run in the buyer’s browser and the buyer has no Taberna account.
Possession of the short id is the credential. It is unguessable in practice, and every payload served here is redacted for a buyer audience — no buyer email, no merchant metadata, no payer IP. Never send an API key from a browser.The corollary: do not treat the id as a secret beyond being unguessable, and never grant value based on a status a browser reported. Fulfil from a webhook or a server-side read.

Retrieve a checkout

GET /v1/checkouts/{id} — no auth. {id} accepts either an order short id or an invoice short id; one resource serves both hosted pages. The response is a tagged union — a payload whose shape depends on a discriminator field. Read type first, then the branch fields.
items[].delivery is null until the order is completed — see what delivery looks like on a completed order.Deliberately absent: customerEmail, extraContext, the payer IP. The page only learns whether an email is on file, via hasCustomerEmail.
A well-formed id that resolves to nothing answers 404 with { "error": "Checkout not found" }the same message for both resources, so the endpoint never reveals which one you probed. A malformed short id is rejected before the lookup as a 400; see Errors.

The active attempt

activeAttempt is null when no quote is live, and otherwise:
cryptoAmount and receivedAmount are integer strings in the token’s smallest unit. transactions is [] until a transfer is attributed. An attempt is created when the buyer picks a token. Re-selecting the same token returns the same attempt — same address, same locked quote — so reloading the page is safe. Selecting a different token abandons the live attempt and locks a new quote on a newly generated address; the abandoned address stays watched until its own window ends, so funds sent to it after the switch still complete the parent. Abandonment emits no webhook. See Payment lifecycle.

Confirmation progress

confirmation is payer-facing progress, and nothing gates on it.
Do not render progress while stale is true, and do not treat confirmed as “paid”. A confirmed state says the transfers on file are buried deeply enough — it says nothing about whether they add up to the amount owed. An underpayment can sit at confirmed indefinitely. The authoritative signal is the order or invoice status.
See Confirmations for how each state arises and what the per-chain depths are.

Start a payment attempt

POST /v1/checkouts/{id}/attempts — no auth. Driven by the checkout UI; you normally do not call this.
Request
Returns the refreshed checkout union — the same payload as the GET, now carrying the new activeAttempt. Works on both branches. Taberna refuses to price an attempt on a stale exchange rate rather than risk mis-quoting it. That last error is transient — the buyer retrying a moment later normally succeeds.

Attach a receipt email (orders only)

PUT /v1/checkouts/{id}/email — no auth.
Request
200 OK
The address is never echoed back — the checkout payload only ever reports the boolean. This route is order-only. An invoice’s recipient is set by the merchant who issued it, so passing an invoice id is a 400 — not a 404. GET /v1/checkouts/{id}/download/{orderItemId} — no auth. Mints a short-lived presigned URL — a temporary, signed link to private storage — for a file_shared delivery on a completed order item.
200 OK
expiresIn is the link’s lifetime in seconds — 300, five minutes. Every substantive failure — unknown checkout, order not completed, wrong item, a delivery that is not a file, an invoice id — answers with the same 404 and the same message, { "error": "Download not available" }, so the endpoint never reveals which check failed. Both path segments are short ids and both are validated first, as everywhere else: if {id} or {orderItemId} is not a well-formed short id the request is rejected as 400 { "error": "Invalid request data" } before any lookup runs.

Polling

You may poll GET /v1/checkouts/{id} as a fallback, and the hosted page does exactly that while an attempt is live. But for your integration, webhooks are the recommended completion signal — and if you poll from your own server, poll the authenticated endpoints, GET /v1/orders/{id} or GET /v1/invoices/{id}. They are the merchant view, they carry extraContext and metadata, and they are not readable by anyone holding the link.
Stop polling as soon as status leaves pending (or open, for invoices): every other state is terminal.