Tabanca Partner API (v1)
Integration contract for external platforms. Two flows plus a read-only catalogue:
- Hand-off in — send a holder of one of your tickets/items to Tabanca to resell it ("List on Tabanca").
- Sold callback out — when it sells, Tabanca calls your webhook so you can void the original and reissue to the buyer.
- Catalogue — read Tabanca's public listings and events.
No money moves between platforms in v1: Tabanca charges the buyer and pays the seller through its own payouts. The API communicates item lifecycle only.
Credentials
Tabanca issues you, per credential:
| Value | Use |
|---|---|
key_id (pk_…) |
Public identifier, first half of your bearer token |
Bearer secret (sk_…) |
Second half of your bearer token. Stored hashed by Tabanca — shown once |
Hand-off signing secret (hs_…) |
HMAC key. Signs the hand-off links you mint, and signs the webhooks Tabanca sends you |
Catalogue requests authenticate with:
Authorization: Bearer <key_id>.<bearer secret>
Scopes: catalogue:read, resale:handoff. Rate limit ~120 requests/minute per
key. Rotation: ask for a second credential, migrate, then have the old one
revoked — during the window both are valid.
Flow 1 — hand-off ("List on Tabanca")
Build a claims object, sign it, and link the holder to Tabanca.
{
"partner": "your-slug",
"external_ref": "YOUR-TICKET-REF-123",
"kind": "ticket",
"title": "Soca Brainwash — GA",
"event_name": "Soca Brainwash",
"event_date": "2026-02-14",
"holder_email": "holder@example.com",
"location": "Grenada",
"image_url": "https://your-cdn/event-flyer.jpg",
"suggested_price": 250,
"currency": "XCD",
"nonce": "unique-per-click"
}
kind:ticket|costume|other.location(optional): where the item/event is — prefills the listing's location.image_url(optional, https): event flyer or costume photo — prefills the listing's first image. The seller can replace it.nonce: unique per click — each redeemed link burns its nonce, so generate a fresh token every time the button is pressed.exp(optional, unix seconds): defaults to now + 15 minutes and may not exceed it.- Required:
partner,external_ref,kind,title,holder_email,nonce.
Token: base64url(JSON claims) + . + hex HMAC-SHA256 of that base64url
string, keyed with your hand-off signing secret. Sign the encoded string, not
the raw JSON.
Link: https://tabanca.store/sell?handoff=<token>
A holder without a session is sent to Tabanca auth (sign in or create an
account) and returned to the same link afterwards — your token survives the
round trip, subject to its expiry. Their session email must equal
holder_email; the token alone does not prove ownership. The listing form
then arrives prefilled (type, title, event date, location, image, price
suggestion; sale method fixed to online) and they publish.
Sellers do not need Tabanca seller verification to list a hand-off item — your
signature stands in for it — but they are told at listing time that receiving
their payout requires submitting banking details and getting verified. Re-generating a link for the same external_ref refreshes the draft;
once the item is listed or sold, further redeems return already_listed /
already_sold.
Partner-origin listings sell online only. This is enforced server-side and
is not seller-configurable: the online purchase is what captures a verified
buyer identity (the name and email in resale.sold) for you to reissue
against, and it is the trigger for the callback. There is no offline/cash path
for these listings.
Redeem errors your UI may want to handle if you probe
POST /api/v1/handoff/redeem yourself: bad_signature, expired,
exp_too_far, invalid_claims, unknown_partner, partner_disabled,
holder_mismatch, already_redeemed, already_listed, already_sold.
Flow 2 — webhooks
Deliveries are POSTed to your configured webhook URL:
Content-Type: application/json
X-Tabanca-Event: resale.sold
X-Tabanca-Delivery: resale.sold:4:YOUR-TICKET-REF-123
X-Tabanca-Signature: t=1786466061,v1=<hex hmac>
Body:
{
"event": "resale.sold",
"delivery_id": "resale.sold:4:YOUR-TICKET-REF-123",
"data": {
"external_ref": "YOUR-TICKET-REF-123",
"item_kind": "ticket",
"buyer_email": "buyer@example.com",
"buyer_name": "Buyer Name",
"sold_at": "2026-08-11T19:00:00.000Z",
"amount": 250,
"currency": "XCD",
"tabanca_listing_id": 321,
"tabanca_order_id": 77
}
}
On resale.sold, void the original item and reissue it to buyer_email.
The sale is always an online purchase through Tabanca's checkout, so
buyer_email and buyer_name are the identity the buyer paid under, and
tabanca_order_id is always present.
Verify the signature: compute HMAC-SHA256 over <t>.<raw body> with your
hand-off signing secret and compare to v1. Reject stale t values to prevent
replays.
Respond 2xx quickly. Anything else retries with backoff (1m, 5m, 30m, 2h,
8h, 24h) and then dead-letters for manual review. Deliveries can arrive more
than once — dedupe on X-Tabanca-Delivery.
Flow 3 — catalogue
All endpoints require Authorization: Bearer <key_id>.<secret> with
catalogue:read.
| Endpoint | Notes |
|---|---|
GET /api/v1/listings |
?limit= (max 100), ?country=, ?category=, ?cursor=. Returns { data, next_cursor } |
GET /api/v1/listings/{id-or-slug} |
Single listing |
GET /api/v1/events |
Upcoming public events with ticket types. ?limit=, ?region= |
GET /api/v1/events/{id-or-slug} |
Single event |
Listing DTO: id, source (listing | vendor_product), slug, title,
description, category, price, currency, images, seller_name,
location, event_date, created_at, url. Event DTO adds ticket_types
(name, price, sold_out).
Pagination is a keyset cursor: pass next_cursor back until it returns null.
Errors
Errors are { "error": "<code>" } with a conventional status: 401 bad or
missing credentials, 403 disabled partner or missing scope, 404 not found,
409 conflict, 429 rate limited.
Testing
scripts/partner-simulator.mjs in the Tabanca repo plays your side of the
integration: it mints signed hand-off links and runs a listener that verifies
webhook signatures. See the header of that file for usage.
Your partner portal
Every partner has a portal at https://tabanca.store/partner. Sign in with a
Tabanca account that your Tabanca contact has added to your partner's access
list (your registered contact email works by default). The portal shows:
- API keys — key IDs, scopes, and when each was last used. Secrets are displayed once at issue time and cannot be recovered; if one is lost, a replacement credential is issued.
- Webhook endpoint — the URL Tabanca delivers events to. Editable here;
must be
https. - Recent deliveries — each webhook attempt with status, HTTP response and error detail. A delivery that has exhausted its retries shows a Redeliver button, which requeues it for the next delivery run.
- API usage — your call volume for the last 30 days, per endpoint and status class, from the same rollups the Tabanca team monitors.