Powered by Smartsupp
BOX OFFICE OPEN5% PER TICKET SOLD NOTHING ELSEFREE EVENTS ARE FREEWHITE-LABEL BY DEFAULTREST API · 5 SDKS · MCP SERVERPAYOUTS IN USD · NGN · ZAR
zatabox

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.
install (optional)
# Node until the npm publish lands, install from the repository
npm install zatabox/zatabox-node # → @zatabox/node 0.2.0-alpha
# Python, PHP, Go, Ruby: on the roadmap use plain REST + JSON meanwhile

1 · 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' }

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.

tickets + publish
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 live

3 · 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).

order + pay + verify
// 1 · guest order full name + email is all a buyer needs
const order = await zatabox.orders.create({
items: [{ ticketTypeId: 'tkt_…', quantity: 2 }],
guestEmail: '[email protected]',
guestName: 'Alice Johnson',
})
// a buyer account is auto-created; the order carries its own access token
// 2 · pay crypto (nowpayments), paystack or flutterwave
const payment = await zatabox.orders.pay(order.id, {
provider: 'nowpayments', // crypto response carries payAddress + payAmount
payCurrency: 'usdttrc20',
})
// 3 · verify an active call, no inbound webhook required
await zatabox.payments.verify({ orderId: order.id })
// → order completed, tickets emailed with QR + .ics calendar invite

4 · 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.

webhook handler
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_ for vt_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.