Skip to content

API and webhooks

Tikit has a REST API and signed webhooks for organisers who want to connect their own systems, an accounting tool or Zapier. Everything here is under Developers in your dashboard. A key or an endpoint can never do more than the person who made it, and buyers' details stay with the owner.

The full list of routes is on the reference page. The machine-readable version is at /api/v1/openapi.

Getting a key

  1. Open Developers and choose Create key.
  2. Name it, pick Test or Live, and tick only what it needs.
  3. A live key asks for a code we email you. If your account has two-step sign-in or a passkey, sign in with that first.
  4. Copy the key. We show it once and keep only a fingerprint, so a lost key means a new key.

A test key reads fixed sample data (an event called Sandbox Sessions, with made-up buyers on example.com) and anything you write with it is not saved. Real payments are never involved. A live key works on your real events and orders.

You can add an IP allow-list and pick a rate limit when you make a key. Rotating a key gives you a new one with the same settings, and the old one keeps working for 24 hours.

Authentication

Send the key in the Authorization header, and only there:

Authorization: Bearer tk_live_...

A key in a URL is never read. The API sends no CORS headers, because a browser must never hold a key. Call it from a server.

Scopes

| Scope | What it gives | | --- | --- | | events:read | Events, tiers, and sold and check-in counts. No buyer details. | | orders:read | Orders and their status. Amounts only if the person who made the key can see money. Never names, emails or phones. | | attendees:read | Buyer and holder names, emails and phones. Only the owner can give a key this. | | guests:write | Give guests complimentary tickets and take them back. | | webhooks:write | Subscribe and unsubscribe webhook URLs, which is what Zapier needs. |

A key acts as the person who made it. If that person is removed from your team, or loses a permission, their keys stop working or shrink at once. Only someone with access to the whole organiser can make keys, and the owner can give a key buyers' details.

No ticket codes or QR data are ever returned, and an order that uses live QR tickets has its reference masked.

Rate limits and IP allow-lists

Each key has a limit per minute: 60, 120, 300 or 600. Past it you get 429 rate_limited and a Retry-After header. If a key has an allow-list, a request from any other address gets 403 ip_not_allowed.

Errors

Every error is {"error": {"code": "...", "message": "..."}} with a message written for a person.

| Code | Status | Meaning | | --- | --- | --- | | invalid_key | 401 | The key is wrong, revoked or expired. We don't say which. | | key_owner_lost_access | 401 | The person who made the key can no longer manage keys. | | insufficient_scope | 403 | The key needs another scope. | | ip_not_allowed | 403 | The request came from an address the key doesn't allow. | | organiser_suspended | 403 | Writes are paused while the organiser is suspended. | | not_found | 404 | Not found, or not yours. | | rate_limited | 429 | Slow down and retry after the time in Retry-After. | | bad_request | 400 | Something in the request was wrong. |

Pagination

List routes take limit (1 to 100, default 25) and cursor. A response has nextCursor; pass it back as cursor for the next page. It is null on the last page. Orders and events come newest first. Check-ins come oldest first.

Comps

POST /events/{id}/guests gives a guest tickets. It needs an Idempotency-Key header, so a retry can't give them twice. Send the same key and you get the same entry back.

Webhooks

Webhooks send a signed JSON message to your server when something happens. Add an endpoint under Developers, pick the events, and we send a test event first. The events:

Each message looks like this:

{
  "id": "evt_9f2c...",
  "type": "order.paid",
  "apiVersion": "2026-10-01",
  "createdAt": "2026-10-05T10:00:00.000Z",
  "livemode": true,
  "organiserId": "...",
  "data": { "order": { "id": "...", "status": "paid" } }
}

Amounts appear only if the person who made the endpoint can see money, and buyer details only if the owner switched them on. A ticket code is never sent.

Versions

Within an apiVersion we only ever add fields. Anything that would break a parser ships as a new version, and your endpoint stays on the one it was made with.

Verifying the signature

Every request carries a Tikit-Signature header like t=1700000000,v1=ab12.... Rebuild t + . + the raw body, sign it with your endpoint's secret using HMAC-SHA256, and compare in constant time. Reject anything older than 5 minutes.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(header, rawBody, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return header
    .split(",")
    .filter((p) => p.startsWith("v1="))
    .some((p) => {
      const got = Buffer.from(p.slice(3));
      const want = Buffer.from(expected);
      return got.length === want.length && timingSafeEqual(got, want);
    });
}

Use the raw body, not a re-serialised copy.

Retries and switching off

Answer with any 2xx. We don't follow redirects. If you answer anything else, or don't answer in 10 seconds, we try again after 1 minute, 10 minutes, 1 hour and 6 hours, then give up on that event. After 15 failed attempts in a row we turn the endpoint off and email you. A 410 Gone turns it off at once, so an endpoint that no longer exists unsubscribes itself.

Use the Tikit-Event-Id header (or the id in the body) to ignore an event you've already handled. You can resend any delivery from the endpoint's delivery page, where payloads are shown with personal details blanked.

Rolling a secret

Roll secret makes a new signing secret. For 24 hours we sign with both, so you can switch over without dropping events.

Where it goes

Webhook URLs must be https on the standard port, and can't point at Tikit or at a private address. If you switch on buyer details, those details leave Tikit for your server: you are responsible for where they go and how they are kept, under POPIA.

Zapier

Tikit doesn't have a published Zapier app yet, but a Zap can use a Tikit API key today.

Hook URLs are secrets, so we show only the end of them.

Last updated 5 October 2026. These pages describe Tikit as it is today.