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

Agents

Your box office, as tools.

A first-party MCP server that maps the integrator-facing REST surface to agent tools so an agent can sell, manage events, scan and reconcile, with an audit trail behind every move.

What it is#

If your agent speaks the Model Context Protocol, it already speaks Zatabox. The server is first-party and sits directly on the REST API documented here: the integrator-facing surface discovery and the full purchase chain, event/ticket/schedule/section management, promo codes, check-in, community, growth, analytics, wallets and webhooks is exposed as tools, with the same scopes, the same rate limits and the same idempotency guarantees plus an audit layer built for the awkward question of who did what. (Platform-admin, white-label internals, API-key minting and scanner-token endpoints are intentionally out of the agent surface.)

Connect#

Two transports stdio and streamable HTTP plus a Dockerfile, so the same server runs hosted, local while developing, or self-hosted behind your own network rules.

{
"mcpServers": {
"zatabox": {
"url": "https://mcp.zatabox.com",
"headers": { "Authorization": "Bearer vt_live_…" }
}
}
}

Auth & scopes#

  • The server forwards a Zatabox API key vt_live_ (production) or vt_test_ (test mode) on every call: the ZATABOX_API_KEY env var on stdio, or the Authorization: Bearer header on the streamable-HTTP initialize request (bound to that session).
  • Keys use a scope grammar events:read, orders:write, checkin:write and the rest; * is admin-only. A tool needs the same scope as the REST endpoint it wraps: event_publish wants events:write, checkin_scan wants checkin:write. API-key calls are pinned to the key's organization.
  • The buyer-side tools (my_tickets_list, my_profile_get, my_data_export, refund_request, organizer_message, report_submit) act for a signed-in user and need a buyer session token rather than an organizer API key. Guest checkout (order_createorder_payorder_verify_payment) works unauthenticated using the order's accessToken, and the passwordless community tools (review_submit, waitlist_join, org_follow) prove intent with the body, no token.
  • Rate limits and idempotency are enforced by the underlying REST API per endpoint the MCP layer adds no separate limit.

Calling a tool#

Arguments are plain JSON Schema what you'd send the REST endpoint, minus the URL. Results come back as pretty-printed JSON in the tool's text content, and errors arrive as the same CODE: message strings the REST API uses, so an agent can branch on TICKET_SOLD_OUT the way your code would.

// tools/call request arguments are plain JSON Schema inputs
{
"name": "order_create",
"arguments": {
"items": [{ "ticketTypeId": "tkt_8f2k", "quantity": 2 }],
"guestEmail": "[email protected]",
"guestName": "Alice Johnson"
}
}

Tool catalog#

70 tools, named noun-first so they sort the way you think. Expand any row for its arguments req marks the ones the tool must receive, READ tools only fetch, and WRITE tools change state every write is audited and idempotency-keyed automatically.

Discovery & purchase

READdiscover_eventsSearch the public catalog with buyer intent the canonical first call for “find me something fun this Friday”.

Returns event cards with id, slug, dates, venue and lowest ticket price. Identical backend to event_list.

FieldDescription
qFree-text search across title and description.
categorymusic, sports, business, arts, food, tech, community or other.
cityCase-insensitive contains match on venue city.
dateFromISO 8601 window start.
dateToISO 8601 window end.
priceMaxCeiling on the lowest ticket price.
READevent_searchFree-text search the fastest path from a phrase (“the jazz night in Lagos”) to an event id and slug.

Same backend as event_list switch to event_list when you need dates, price or pagination filters.

FieldDescription
qreqFree-text search across title and description.
categoryOptional category narrow.
cityOptional city narrow.
WRITEorder_createCreate an order for one or more ticket types guest checkout needs only a name and email.

Inventory is checked atomically on TICKET_SOLD_OUT, re-run ticket_type_list for an alternative or fall back to waitlist_join. The response includes accessToken for the guest order.

FieldDescription
itemsreqLine items one entry per ticket type.
items[].ticketTypeIdreqThe ticket type to buy.
items[].quantityreqHow many, within the type’s purchase caps.
guestEmailGuest checkout where tickets and the receipt go.
guestNameName on the order.
promoCodeApplied before totals.
WRITEorder_payInitiate payment on a pending order and get the provider’s checkout material.

nowpayments returns the generated deposit details (payAddress, payAmount, payCurrency, network, memo); the redirect providers return an authorizationUrl. Call crypto_currencies_list first to pick a valid payCurrency. The agent cannot complete payment itself hand the details to the human, then confirm with order_verify_payment. Free orders error with NOTHING_TO_PAY (tickets were issued at creation); paid orders with ALREADY_PAID.

FieldDescription
idreqOrder id from order_create.
providernowpayments (crypto, default), paystack or flutterwave.
payCurrencynowpayments only the crypto coin to pay in (e.g. btc, eth, usdttrc20). Defaults to btc.
tokenThe order’s accessToken when acting for a guest checkout.
READcrypto_currencies_listThe crypto coins NOWPayments can take call before order_pay (provider nowpayments) to pick a valid payCurrency.

Returns ticker, label and symbol per coin (e.g. btc, eth, sol, usdttrc20). No auth needed.

No arguments.

READpayment_statusRead-only order + payment status and the list of payment attempts inspect without confirming or issuing.

Unlike order_verify_payment this does not confirm a charge or issue tickets.

FieldDescription
orderIdreqOrder id.
tokenGuest order access token, if applicable.
WRITEorder_verify_paymentConfirm the charge server-side after the human has paid issues tickets, no webhook needed.

Idempotent and poll-safe re-call every few seconds until the order status is completed.

FieldDescription
idreqOrder id.
tokenSame guest token used for order_pay, if applicable.
READorder_getCurrent state of an order by id.
FieldDescription
idreqOrder id.
WRITEorder_cancelCancel an order that has not been paid releases held inventory.

Completed orders cannot be cancelled use refund_request instead.

FieldDescription
idreqOrder id.

Events

READevent_listList the public catalog with the full filter set dates, price, country, pagination.
FieldDescription
qFree-text search.
categorymusic, sports, business, arts, food, tech, community or other.
cityContains match on venue city.
countryISO 3166-1 alpha-2.
venueContains match on venue name.
dateFrom / dateToISO 8601 window.
priceMaxLowest-price ceiling.
cursorOpaque cursor from the previous page.
limit1–50, default 20.
READevent_getFull event detail by slug ticket types, schedule and organizer info included.

Private events resolve too when the API key belongs to the event’s organization other callers get EVENT_NOT_FOUND.

FieldDescription
slugreqEvent slug from list results.
WRITEevent_createCreate a draft event under the organizer’s active organization.

Lands in draft status add ticket types, then event_publish to go on sale. Returns the server-assigned id and slug.

FieldDescription
titlereqEvent title.
categoryreqmusic, sports, business, arts, food, tech, community or other.
startDatereqISO 8601, in the future.
endDatereqISO 8601, after startDate.
timezonereqIANA timezone, e.g. America/New_York.
venueTypereqphysical, online or hybrid.
capacityreqTotal capacity.
descriptionLong-form description.
shortDescUp to 280 characters.
venueName / venueAddress / venueCityPhysical venue fields.
venueCountryISO 3166-1 alpha-2.
onlineLinkStream link for online / hybrid.
coverImageCover image URL.
WRITEevent_updatePartial update send only the fields to change; omitted fields keep their value.

Major changes to a published event (date, venue) notify ticket holders.

FieldDescription
idreqEvent id from event_create.
…any create fieldAll event_create fields are accepted, each optional.
WRITEevent_publishTransition draft → published so the event goes on sale.

Fails if required fields are missing or the event has no ticket types.

FieldDescription
idreqEvent id.
WRITEevent_unpublishThe inverse of event_publish pull a published event back to draft, off public listings.

Preserves tickets and data; does NOT cancel the event or make tickets refund-eligible (use event_cancel for that).

FieldDescription
idreqEvent id.
WRITEevent_cancelCancel an event destructive; issued tickets become refund-eligible.

Only call when the user explicitly asks to cancel.

FieldDescription
idreqEvent id.
reasonreqAt least 10 characters quoted in refund notifications to holders.
READevent_customization_getThe event page’s theme, layout, colors, CTA, section toggles, FAQs and SEO fields.

Returns both the saved customization and platform defaults, so effective values are visible.

FieldDescription
eventIdreqEvent id.
WRITEevent_customization_setRestyle the public event page “make it match my brand”, “add an FAQ”, “change the buy button”.

Partial update send only the fields to change.

FieldDescription
eventIdreqEvent id.
layoutPatternclassic, split, gallery, minimal, magazine or festival.
heroStyleimage, video, gradient, pattern or solid.
primaryColor … textColorprimaryColor, secondaryColor, accentColor, backgroundColor, textColor.
ctaLabelBuy-button label, up to 80 characters.
showOrganizer … showSocialShareVisibility toggles: organizer, schedule, venue map, countdown, social share.
faqsUp to 40 { question, answer } pairs.
seoTitle / seoDescription / seoImageSearch and share metadata.

Schedule & seating

READschedule_listAn event's running order sessions/talks/sets by day and time, with speaker and location.
FieldDescription
eventIdreqEvent id.
WRITEschedule_createAdd a session to the public running order (e.g. “Opening keynote, 9–10am, Main Stage”).
FieldDescription
eventIdreqEvent id.
sessionTitlereqe.g. “Opening keynote”.
startTime / endTimereqSession window; endTime after startTime.
dayNumberDay of a multi-day event, default 1.
speakerName / speakerBio / speakerAvatarSpeaker details.
locationDetailStage / room.
WRITEschedule_updatePartial update of a session reschedule or fix details.
FieldDescription
eventIdreqEvent id.
sessionIdreqSession id from schedule_list.
…any create fieldAll schedule_create fields, each optional.
WRITEschedule_deleteRemove a session from the running order.
FieldDescription
eventIdreqEvent id.
sessionIdreqSession id.
READsection_listSeating/capacity sections (GA floor, VIP deck, Balcony); ticket types map to one via sectionId.
FieldDescription
eventIdreqEvent id.
WRITEsection_createAdd a seating section; reference its id from a ticket type's sectionId to sell into it.
FieldDescription
eventIdreqEvent id.
namereqe.g. “VIP deck”.
capacityreqSection capacity.
WRITEsection_updatePartial update of a seating section.
FieldDescription
eventIdreqEvent id.
sectionIdreqSection id from section_list.
WRITEsection_deleteDelete a seating section fails if a ticket type still references it.

Reassign any ticket types off the section (ticket_type_update sectionId) first.

FieldDescription
eventIdreqEvent id.
sectionIdreqSection id.

Promo codes

READpromo_code_listPromo codes in the org, newest first optionally filtered to one event.
FieldDescription
eventIdFilter to one event; omit for all org codes.
WRITEpromo_code_createCreate a percentage or flat discount code, event-scoped or org-wide.
FieldDescription
codereq3–50 chars; stored upper-cased.
discountTypereqpercentage or flat.
discountValuereq0–100 for percentage; amount off for flat.
validFrom / validUntilreqActive window.
eventIdScope to one event; omit for org-wide.
maxUses / minOrderValue / applicableTypesOptional caps and restrictions.
WRITEpromo_code_updatePartial update extend the window, raise the cap, pause a code.

The code value can't change once it has been redeemed (CODE_LOCKED).

FieldDescription
idreqPromo code id.
…any create fieldAll promo_code_create fields, each optional.
WRITEpromo_code_deleteDelete an unused code, or disable one that has already been redeemed.
FieldDescription
idreqPromo code id.
READpromo_validatePreview whether a code applies to a cart read-only, does not consume a use.

Returns { valid, discount, reason? }. Pass the same code as order_create's promoCode to apply it.

FieldDescription
codereqThe code to check.
eventIdEvent id/slug to match scope.
ticketTypeIdsCart ticket-type ids, for applicableTypes codes.
subtotalCart subtotal, for the discount and minOrderValue.

Ticket types & tickets

READticket_type_listTicket types for an event name, price, currency, availability and sale window.
FieldDescription
eventIdreqEvent id.
WRITEticket_type_createAdd a ticket type the simplest path is “General Admission, $X, 100 quantity”.

Free tickets must have price=0 AND type=free.

FieldDescription
eventIdreqThe event to attach to.
namereqe.g. “General Admission”.
typereqgeneral, reserved, vip, early_bird, group, free, multi_day, season, at_door or upgrade.
pricereqUnit price excluding fees the platform fee is computed at checkout.
currencyreqISO 4217, e.g. USD, NGN.
quantityTotalreq-1 for unlimited.
saleStart / saleEndreqSale window; defaults to “now → event end” when omitted.
refundableDefault false.
refundDeadlineRequired when refundable=true; must be on or before the event start.
transferableDefault true.
WRITEticket_type_updatePartial update raise the price, extend the window, add quantity.

Quantity cannot drop below the number already sold; price changes never affect issued tickets.

FieldDescription
eventIdreqEvent id.
ticketTypeIdreqThe type to change.
…any create fieldAll ticket_type_create fields, each optional.
WRITEticket_transferSend a ticket to someone else they claim it from an emailed link.

The ticket only changes hands on claim; the initiator can revoke for 24h until then. Fails on non-transferable types.

FieldDescription
ticketIdreqThe ticket to transfer.
toEmailreqRecipient receives the claim link.
toNameRecipient name.
tokenOrder access token (from order_create) proving ownership required when not signed in as the holder. A matching holder email alone is not accepted as proof.
WRITEticket_mint_compMint complimentary tickets for speakers, press, VIPs or staff each recipient gets a real ticket by email.
FieldDescription
eventIdreqEvent id.
ticketTypeIdreqThe type to mint from comps draw down its remaining quantity.
recipientsreqList of { name, email } entries.
noteInternal note on the batch, e.g. “press list”.
WRITEevent_issueIssue tickets you sold ELSEWHERE into a buyer's wallet developer-handled payment, at the reduced 3% rate.

3% wallet fee per non-free ticket (free tickets are free); fails atomically with INSUFFICIENT_FUNDS if the wallet can't cover it fund the wallet first. Idempotent: a retry never double-issues.

FieldDescription
eventIdreqEvent public id; the API key must own its org.
itemsreq[{ ticketTypeId, quantity, attendeeName?, attendeeEmail? }].
buyer{ email?, name? } recipient; an email creates a passwordless wallet.
referenceYour own payment/order id, echoed back for reconciliation.
sendEmailEmail the buyer their tickets (default true when an email is given).

Check-in

WRITEcheckin_scanValidate a ticket QR or short code at the gate.

Denials are data, not errors: status comes back success or denied_duplicate / denied_cancelled / denied_expired / denied_wrong_event.

FieldDescription
eventIdreqThe event being scanned scopes the scan and authorizes the caller.
qrDataThe HMAC-signed QR payload (a bare short code also resolves through this field).
ticketCodeShort code fallback when the QR is unreadable folded into qrData. Pass one of qrData or ticketCode.
gateNameWhich gate, for per-gate stats.
deviceIdScanner identifier.
READcheckin_statsLive totals “how many people are in?” capacity %, entry rate, per-gate breakdown.
FieldDescription
eventIdreqEvent id.
gateNameFilter to one gate.
READcheckin_exportThe full attendee / check-in manifest as CSV door lists and post-event reconciliation.

Returns raw CSV text (name, email, ticket type, code, checked-in time, gate) save it to a file or paste it for the user.

FieldDescription
eventIdreqEvent id.

Growth & CRM

READattendee_listTicket holders for an event name, email, type, code, check-in status.

The source of ticketIds for attendee_tag. For a CSV download use checkin_export.

FieldDescription
eventIdreqEvent id.
cursorOpaque pagination cursor.
WRITEattendee_tagTag a set of tickets “vip”, “press”, “no-show” to power segments.

Additive existing tags stay. Tags drive attendee_broadcast’s tagFilter.

FieldDescription
orgIdreqOrganization id.
ticketIdsreqTickets to tag, from attendee_list.
tagreqShort label, e.g. “vip”.
WRITEattendee_broadcastEmail an event’s attendees, optionally narrowed to a tag.

Sends real email to real people agents should show the final subject and body and get explicit confirmation before calling. Returns the recipient count.

FieldDescription
eventIdreqEvent id.
subjectreqEmail subject.
bodyreqPlain text or simple HTML.
tagFilterOnly attendees whose ticket carries this tag.

Community

READreview_listPublished reviews for an organization or a single event, with aggregate rating.
FieldDescription
orgIdReviews across all the org’s events. Pass exactly one of orgId / eventId.
eventIdReviews for one event only.
cursorOpaque pagination cursor.
WRITEreview_replyPost the organizer’s public reply beneath a review one per review.

It is public agents should confirm the wording with the organizer before posting.

FieldDescription
reviewIdreqThe review to reply to.
bodyreqReply text.
WRITEreview_submitLeave a verified-attendee review ticketCode + email prove attendance, no login.
FieldDescription
ticketCodereqShort code on the ticket / confirmation email.
emailreqMust match the ticket holder.
ratingreq1–5 stars.
bodyreqReview text the reviewer’s own words, never invented.
authorNameDisplay name next to the review.
WRITEwaitlist_joinJoin a sold-out event’s waitlist the natural follow-up to TICKET_SOLD_OUT.

No payment at join time; offers are first-come within the offer window.

FieldDescription
eventIdreqEvent id.
emailreqWhere the offer email goes.
namereqBuyer name.
ticketTypeIdWait for a specific type.
READwaitlist_listWho’s waiting on an event since when, and each entry’s offer status.

Statuses: waiting, offered, accepted, expired. Check before waitlist_offer.

FieldDescription
eventIdreqEvent id.
cursorOpaque pagination cursor.
WRITEwaitlist_offerOffer tickets to the next N waiting people, in join order.

Each gets a time-limited purchase link by email real emails, so confirm the count with the organizer first.

FieldDescription
eventIdreqEvent id.
countreqHow many entries to offer to.
READfollower_countAn organization’s follower count plus a page of follower entries.

Followers are notified on new events useful for gauging announcement reach before a broadcast.

FieldDescription
orgIdreqOrganization id.
cursorOpaque pagination cursor.
WRITEorg_followSubscribe a buyer to an organizer so they're emailed about new events no login needed.

Every announcement email carries a one-click unsubscribe link.

FieldDescription
orgIdreqOrganization UUID, numeric id or slug.
emailreqWhere announcements go.
nameSubscriber name.
WRITEfollower_removeHard-delete a subscriber (the compliant response to a removal request) email/name are purged.

Organizer write access. Returns { removed: true }; the slot frees so they may follow again later.

FieldDescription
orgIdreqOrganization id.
followerIdreqSubscriber id from follower_count.

Buyer

READmy_tickets_listThe buyer’s tickets across all organizers “what tickets do I have?”.

Needs a buyer session token (user-delegated auth), not an organizer API key.

FieldDescription
cursorOpaque pagination cursor.
limitPage size, default 20.
READmy_profile_getThe signed-in buyer’s profile name, email, phone, verification flags, preferences.

Needs a buyer session token.

No arguments.

READmy_data_exportDownload everything on the account as one JSON profile, orders, tickets, refunds, reports, messages (GDPR export).

Buyer session token; use only when the user explicitly asks to export their data.

No arguments.

WRITErefund_requestSubmit a refund request on the buyer’s behalf the organizer approves or denies.

Eligibility depends on the type’s refundable flag and the organizer’s deadline.

FieldDescription
ticketIdreqThe ticket to refund.
reasonreqAt least 10 characters “flight cancelled by airline” beats “can’t make it”.
messageOptional message to the organizer.
WRITEorganizer_messageAsk the organizer of a ticket a question “is there parking?” in the per-ticket thread.

Rate-limited to 10 messages/hour per organizer to prevent spam.

FieldDescription
ticketIdreqThe ticket the question is about.
bodyreqUp to 5,000 characters.
WRITEreport_submitFile a report about an event or organizer only when the buyer explicitly reports an issue.

harassment and fraud route directly to platform admins; the rest go to the organizer first.

FieldDescription
categoryreqmisleading_info, did_not_happen, harassment, fraud, accessibility or other.
descriptionreqAt least 20 characters.
eventIdOne of eventId / organizationId identifies the subject.
organizationIdReport the organizer rather than one event.

Organization, analytics & wallet

READorganization_getAn organization's profile (name, verified, status, branding, contact) plus its per-currency wallet balances.

Returns { organization, wallets }.

FieldDescription
idreqOrganization id; must match an org-scoped API key's org.
READanalytics_eventHow an event is doing sold and remaining by type, revenue, sales over time, conversion, check-ins.
FieldDescription
eventIdreqEvent id.
READwallet_listThe organizer’s wallets one per organization + currency with available and pending balances.
FieldDescription
orgIdOrganization id. Required when authenticating with an org-scoped API key (the no-orgId form is portal-session only and returns API_KEY_ORG_FIXED otherwise).

Webhooks

READwebhook_listThe caller’s webhook subscriptions URL, events, status, masked secret.

No arguments.

WRITEwebhook_createSubscribe an HTTPS endpoint to platform events.

The response contains the full whsec_ signing secret exactly once surface it to the user prominently; it is masked on every later read.

FieldDescription
urlreqHTTPS endpoint that receives deliveries.
eventsreqEvent types from webhook_catalog, or ["*"] for all.
nameFriendly label, up to 120 characters.
WRITEwebhook_updateChange a subscription's URL, event list or name, or pause it (status disabled) without deleting.

The signing secret is unchanged use webhook_rotate_secret for that.

FieldDescription
idreqSubscription id.
url / events / nameAny subset to change.
statusactive or disabled.
WRITEwebhook_deleteDelete a subscription deliveries stop immediately, the secret is invalidated.

Cannot be undone recreating issues a new secret, so agents should confirm with the user first.

FieldDescription
idreqSubscription id.
WRITEwebhook_testFire a signed test event at the endpoint to verify the handler end to end.

Then check webhook_deliveries for the result.

FieldDescription
idreqSubscription id.
WRITEwebhook_rotate_secretIssue a new whsec_ signing secret (the old one stops verifying immediately).

Returns the new secret exactly once surface it and tell the user to update their verifier now.

FieldDescription
idreqSubscription id.
READwebhook_deliveriesRecent delivery attempts the tool for debugging “my webhook isn’t firing”.

Shows event type, response status, latency, retry count and error detail look for 4xx/5xx from the receiving endpoint.

FieldDescription
idreqSubscription id.
WRITEwebhook_replay_deliveryRe-send a past delivery to its endpoint recover from a downstream outage.
FieldDescription
idreqDelivery id (from webhook_deliveries), not the subscription id.
READwebhook_catalogEvery event type the platform can emit call before webhook_create to pick valid names.

No arguments.

Audit#

Autonomy is earned. The MCP server tags every call with an X-MCP-Client header, so a successful write made with an API key fires an agent.action webhook and is recorded in the key's API usage log the answer to "which agent did what" is always one query away.

webhook · agent.action
{
"id": "whe_01J…",
"type": "agent.action",
"created": "2026-06-10T15:21:47Z",
"data": {
"tool": "event_publish",
"method": "POST",
"path": "/api/v1/organizer/events/evt_…/publish",
"statusCode": 201,
"at": "2026-06-10T15:21:47Z"
}
}