Tooling
One SDK today, more on the way.
The official Node client is real and shipping vt_ key routing, typed errors, retries, idempotency, webhook verification. Python, PHP, Go and Ruby are on the roadmap, generated from the same OpenAPI spec.
Install#
@zatabox/node is at 0.2.0-alpha. Until the npm publish lands, install it straight from the repository the package name and API are stable either way.
# until the npm publish lands, install straight from the repositorynpm install zatabox/zatabox-node # → @zatabox/node 0.2.0-alphaInitialize#
One client, one key. The constructor takes the key plus three optional knobs and the host is inferred from the key prefix, so there is no environment flag to forget.
import Zatabox from '@zatabox/node' const zatabox = new Zatabox.Client({ apiKey: process.env.ZATABOX_API_KEY, // vt_test_… for test mode, vt_live_… for production})| Field | Description | |
|---|---|---|
apiKeyreq | string | Your vt_live_… or vt_test_… key. |
baseUrl | string | Override the API host. Routing defaults by key prefix test mode for vt_test_, production for vt_live_. |
timeoutMs | int | Per-request timeout, in milliseconds. |
maxRetries | int | Retry budget for 5xx responses. |
Surface map#
The whole client fits on a handful of lines. Each method maps one-to-one onto a REST endpoint, so the REST reference doubles as the SDK reference including the passwordless purchase chain: create the order, pay it, verify the payment.
zatabox.events .list() .get() .create() .update() .publish() .cancel()zatabox.tickets .list() .create()zatabox.orders .create() .get() .pay() .cancel()zatabox.payments .verify()zatabox.auth .requestCode() .exchangeCode() // passwordless buyer loginzatabox.checkin .scan() .stats()zatabox.webhooks .parseEvent() // signature verificationErrors#
Every non-2xx response throws a ZataboxError carrying .code, .status, .message, .requestId and .details the REST error envelope, as an exception.
import Zatabox, { ZataboxError } from '@zatabox/node' const zatabox = new Zatabox.Client({ apiKey: process.env.ZATABOX_API_KEY }) try { await zatabox.orders.create({ items: [{ ticketTypeId: 'tkt_8f2k', quantity: 2 }], })} catch (err) { if (err instanceof ZataboxError) { console.error(err.code, err.status, err.requestId) if (err.code === 'TICKET_SOLD_OUT') { // sold out is a state, not a crash render it as one } } else { throw err }}| Field | Description | |
|---|---|---|
.code | string | Machine-readable code the same set the REST API uses, e.g. TICKET_SOLD_OUT. |
.status | int | HTTP status of the failed response. |
.message | string | Human-readable summary. |
.requestId | string | Echo of meta.request_id quote it when you write to support. |
.details | object | Field-level specifics, when the API provides them. |
Retries & idempotency#
The transport layer handles the boring-but-critical parts so your application code never has to.
- Every write gets an auto-generated UUID
Idempotency-Keyyou never hand-roll one. - 5xx responses are retried automatically with backoff, up to
maxRetries. The same key rides along on each attempt, so the server replays the original result instead of repeating the write.
Test mode#
Initialize with a vt_test_ key and every call runs in test mode no real money, no flag, no second client. Swap in vt_live_ when you ship; nothing else changes. A hosted sandbox at sandbox.api.zatabox.com is on the roadmap; the key-prefix routing in the client is already built for it.