Getting started
First ticket in ten minutes.
Everything below runs in test mode with a vt_test_ key no real money, full feature parity.
0 · Get a key#
- Create a free organizer account at organizer.zatabox.com no card required.
- In API keys, create a test key. It starts with
vt_test_and runs every call in test mode. - Optionally install the Node SDK or stay in cURL, the API is plain REST + JSON.
# Node until the npm publish lands, install from the repositorynpm install zatabox/zatabox-node # → @zatabox/node 0.2.0-alpha# Python, PHP, Go, Ruby: on the roadmap use plain REST + JSON meanwhile1 · Create a draft event#
Events are created as drafts invisible to buyers until you publish. Send an Idempotency-Key on writes so retries can never double-create.
import Zatabox from '@zatabox/node' const zatabox = new Zatabox.Client({ apiKey: process.env.ZATABOX_API_KEY, // vt_test_…}) const event = await zatabox.events.create({ title: 'Friday Salsa Night', category: 'music', startDate: '2026-07-04T20:00:00Z', endDate: '2026-07-04T23:30:00Z', timezone: 'America/New_York', venueType: 'physical', venueName: 'The Loft', venueCity: 'New York', venueCountry: 'US', capacity: 80,})// → { id: 'evt_…', slug: 'friday-salsa-night', status: 'draft' }curl https://api.zatabox.com/api/v1/organizer/events \ -H "Authorization: Bearer vt_test_…" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "title": "Friday Salsa Night", "category": "music", "startDate": "2026-07-04T20:00:00Z", "endDate": "2026-07-04T23:30:00Z", "timezone": "America/New_York", "venueType": "physical", "venueName": "The Loft", "venueCity": "New York", "venueCountry": "US", "capacity": 80 }'2 · Add tickets & publish#
A ticket type holds price, inventory and sale window. Add as many as the event needs general, VIP, early-bird, free then flip the event live.
await zatabox.tickets.create({ eventId: event.id, name: 'General Admission', type: 'general', price: 20, currency: 'USD', quantityTotal: 80, saleStart: new Date().toISOString(), saleEnd: '2026-07-04T19:59:59Z',}) await zatabox.events.publish(event.id)// status: draft → published the hosted page is live3 · Sell a test ticket passwordless#
This three-call chain orders → pay → verify is the canonical buyer integration, and it is exactly what the hosted event page runs in its checkout modal. Buyers never set a password: a full name and email creates the account, and logging back in later is an emailed 6-digit code (POST /api/v1/auth/token/request then /exchange).
// 1 · guest order full name + email is all a buyer needsconst order = await zatabox.orders.create({ items: [{ ticketTypeId: 'tkt_…', quantity: 2 }], guestName: 'Alice Johnson',})// a buyer account is auto-created; the order carries its own access token // 2 · pay crypto (nowpayments), paystack or flutterwaveconst payment = await zatabox.orders.pay(order.id, { provider: 'nowpayments', // crypto response carries payAddress + payAmount payCurrency: 'usdttrc20',}) // 3 · verify an active call, no inbound webhook requiredawait zatabox.payments.verify({ orderId: order.id })// → order completed, tickets emailed with QR + .ics calendar invite4 · Hear about it#
Register a webhook endpoint in the portal (or via POST /api/v1/webhooks), then verify the signature and fulfil. During development, send yourself a synthetic delivery with POST /api/v1/webhooks/{id}/test.
import express from 'express'const app = express() app.post('/webhooks/zatabox', express.raw({ type: 'application/json' }), (req, res) => { const event = zatabox.webhooks.parseEvent( req.body, req.headers['x-zatabox-signature'], process.env.ZATABOX_WEBHOOK_SECRET, ) if (event.type === 'order.completed') { console.log('tickets minted:', event.data.tickets.length) } res.json({ received: true }) })5 · Go live#
- Swap
vt_test_forvt_live_nothing else changes. - Sales settle into per-currency balances in the portal's Wallet; payout requests are rolling out.
- Share your hosted page (
zatabox.com/o/your-handle/your-event) the whole purchase completes right on it. Embeddable widgets are in development.