sbTix.API v1
For platforms · For event sites · For booking apps

Sell tickets without sending your buyers away.

Two ways to integrate: a 2-line embed that drops a Buy-tickets button onto any HTML page, or a full Stripe-style REST API with bearer keys, idempotency, and HMAC-signed webhooks.

Attach to your site in 5 minutes → See a live partner demo

Contents

How to attach sbTix to your site

Whether you only need a Buy-tickets button on a marketing page or a full programmatic integration, this is the path. Should take about 5 minutes.

1

Sign up & create your event

Go to sbtix.net/demo/signup/ and create your account. From the dashboard, click + Create event and set up your event — name, date, venue, ticket tiers, prices. After publishing you'll see the event card on your dashboard; click it to copy the event slug (looks like konpa-all-stars-night-xyz4). You'll plug this slug into your partner site in step 3.

2

Get your API keys

From your dashboard, click API & Webhooks in the top nav (or go directly to dashboard/api/). Click + New publishable key for the embed widget — this one is safe to ship in front-end code. If you'll be calling the REST API from your backend too, also issue a + New secret key (keep this one server-side).

Heads up: Keys are shown once at creation time. Copy them into a password manager or your .env file immediately — you can't retrieve them later, only revoke + reissue.
3

Paste the embed on your partner site

On any page where you want a Buy-tickets button, paste exactly this:

<!-- 1. Load the embed (place once anywhere on the page) -->
<script src="https://sbtix.net/v1/embed.js" defer></script>

<!-- 2. Any element with this attribute opens the buy modal -->
<button data-sbtix-buy="YOUR_EVENT_SLUG">Buy tickets</button>

Replace YOUR_EVENT_SLUG with the slug from step 1. Click the button — sbTix opens a modal iframe right on your page, the visitor picks tiers and pays, and your page never reloads. That's it. No further coding required.

4

(Optional) Hook into completion events

If you want to fire your own analytics, redirect to a thank-you page, or write to your CRM when a sale completes:

window.addEventListener("sbtix:order_complete", e => {
  // e.detail.order  → { id, tickets[], total, buyer, … }
  // e.detail.event  → { slug, name, date, venue }
  gtag("event", "purchase", { value: e.detail.order.total });
  location.href = "/thank-you?order=" + e.detail.order.id;
});
5

(Optional) Register a webhook for your server

Front-end events only fire if a visitor reaches the confirmation screen. For reliability (refunds initiated from inside sbTix, server-side reconciliation), register a webhook URL from the API & Webhooks page. sbTix POSTs to that URL with an X-Sbtix-Signature header you verify with HMAC-SHA256 — see the webhooks section.

6

(Power users) Drive the REST API from your server

If you want to programmatically create events, list orders, issue refunds, or build a custom checkout UI that pings sbTix server-side, use the REST API with your secret key.

curl https://sbtix.net/v1/events \
  -H "Authorization: Bearer sbtix_sk_…"

Embed widget

The fastest integration. One script + one attribute = working Buy-tickets button. Visitors stay on your page; the buy flow renders in a sandboxed iframe modal.

HTML

<script src="https://sbtix.net/v1/embed.js" defer></script>
<button data-sbtix-buy="konpa-all-stars-night-xyz4"
        data-sbtix-key="sbtix_pk_…">Buy tickets</button>

JavaScript API

Method / EventDescription
sbtix.open(slug, opts?)Opens the buy modal. opts.key = publishable key.
sbtix.close()Closes the modal programmatically.
window event sbtix:openModal opened.
window event sbtix:readyIframe loaded the event data.
sbtix:order_completeOrder paid + confirmation shown. e.detail = { order, event }
sbtix:closeModal closed.

Authentication

Every REST API request needs an API key in the Authorization header.

Authorization: Bearer sbtix_sk_e51c9d6c…
Key typePrefixWhat it can doWhere it's safe
Secretsbtix_sk_Read + write everything for your org — events, orders, refunds, etc.Server-side only. Never ship in front-end code or commit to git.
Publishablesbtix_pk_Read public event data only (for the embed widget).Safe to embed in HTML.

Issue + revoke keys from dashboard/api/.

REST API reference Live

Base URL: https://sbtix.net/v1 · JSON only · UTF-8 · idempotent POSTs supported via Idempotency-Key.

Events

GET/v1/events
List active events for your org. Query params: limit (max 100, default 20), archived=1, deleted=1.
POST/v1/events
Create an event.
curl -X POST https://sbtix.net/v1/events \
  -H "Authorization: Bearer sbtix_sk_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Konpa All-Stars Night",
    "date": "2026-06-15",
    "date_label": "Saturday, June 15 · 9 PM",
    "venue": "Brick City Lounge, Newark NJ",
    "tiers": [
      { "name": "General Admission", "price": 25, "capacity": 200 },
      { "name": "VIP",               "price": 75, "capacity": 30  }
    ],
    "fees": { "pct": 1, "flat": 0.5, "mode": "buyer" }
  }'
GET/v1/events/{slug}
Fetch a single event. Works with a publishable key too — that's what the embed uses.
PATCH/v1/events/{slug}
Update any of: name, date, date_label, venue, description, image, tiers, fees, no_refund, sales_suspended.
DELETE/v1/events/{slug}
Past events archive (preserve money figures); future events soft-delete to the 180-day bin. Add ?permanent=1 for a hard delete.

Orders

GET/v1/orders?event={slug}
List orders for one of your events.
POST/v1/orders
Create an order. Server-side checkout — handy when you collect payment outside of sbTix and want to record the tickets.
curl -X POST https://sbtix.net/v1/orders \
  -H "Authorization: Bearer sbtix_sk_…" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "event": "konpa-all-stars-night-xyz4",
    "buyer": { "name": "Yves Fabien", "email": "[email protected]" },
    "items": [{ "tierIndex": 0, "qty": 2 }]
  }'
GET/v1/orders/{id}?event={slug}
Fetch a single order incl. tickets.
POST/v1/orders/{id}/refund
Refund the whole order or specific tickets. Body: { "event": "<slug>", "tids": ["TICKET_ID", …] }. Omit tids to refund every live ticket. Returns the updated order with status: "partially_refunded" or "refunded".

Idempotency

Every POST accepts an Idempotency-Key header. Send the same key with the same body twice in 24 hours and sbTix returns the cached response — no duplicate orders, even if your server retries on a network blip.

-H "Idempotency-Key: bd9c…uuid"

The replayed response carries X-Sbtix-Idempotent-Replayed: true so you can tell it apart in your logs.

Webhooks

sbTix POSTs JSON to your URL whenever something interesting happens. Register endpoints + grab the signing secret from dashboard/api/.

Events

EventWhen it fires
order.paidPaid order created (any channel — embed, hosted, API).
order.rsvpFree-event RSVP claimed.
order.compOrganizer issued a comp ticket.
order.refundedAny refund — full or partial.
event.created / updated / deleted / archivedEvent lifecycle changes.
*Catch-all — receive every event type.

Payload shape

{
  "id": "evt_4z9c…",
  "type": "order.paid",
  "created": 1717340821,
  "livemode": false,
  "data": { // the order, in v1 public shape
    "id": "ORD-XYZAB123",
    "event": "konpa-all-stars-night-xyz4",
    "buyer": { "name": "Yves Fabien", "email": "[email protected]" },
    "tickets": [{ "id": "X7W3…", "tier": "GA", "price": 25 }],
    "total": 51.25,
    "status": "paid"
  }
}

Verifying signatures

Every webhook carries X-Sbtix-Signature: t=<timestamp>,v1=<hex>. Compute HMAC-SHA256 of {timestamp}.{raw-body} using your endpoint's signing secret and compare.

const crypto = require("crypto");
app.post("/webhooks/sbtix", express.raw({type:"application/json"}), (req, res) => {
  const sig = req.headers["x-sbtix-signature"];
  const [t, v1] = sig.split(",").map(p => p.split("=")[1]);
  const expected = crypto.createHmac("sha256", WEBHOOK_SECRET)
    .update(t + "." + req.body)
    .digest("hex");
  if (expected !== v1) return res.sendStatus(400);
  const event = JSON.parse(req.body);
  // event.type, event.data.…
  res.sendStatus(200);
});

Errors & rate limits

All errors return JSON of the shape { "error": { "type": "…", "message": "…" } }.

HTTPTypeMeaning
400invalid_requestMalformed body / missing param.
401authentication_required / invalid_api_keyMissing or unknown key.
403insufficient_scopePublishable key tried to call a secret-only endpoint.
403sales_suspended / event_pastOrder rejected — sales paused or event already happened.
404not_foundEvent / order doesn't exist or isn't yours.
409conflictPast event delete blocked — archive instead.
410event_closedEvent was deleted.
429rate_limitedSlow down. Retry-After header gives seconds.

Rate limits default to 120 req/min per secret key and 240/min per publishable key. Every response includes RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset headers.

See the embed on a live partner demo →