Draft API. Endpoints may change before general availability.
API basics
Eight rules that apply to every request. Read this once and the rest of the API will feel predictable.
1. Making a request
Send everything to https://api.eventtickets.dev/v1. Put your secret key in the Authorization header, and send JSON bodies with Content-Type: application/json. Every response is JSON.
Every request
curl https://api.eventtickets.dev/v1/events \ -H "Authorization: Bearer sk_test_..."
Keep keys on your server. Anyone with your key can act as your account, so never put it in a web page, an app, or a public code repository. If one leaks, revoke it in Developers and make a new one.
2. Test mode and live mode
Your account has two separate sets of data. A sk_test_ key only sees test events, orders and tickets; a sk_live_ key only sees live ones. Every object has "livemode": true or false so you can tell them apart. Build and try everything with a test key, then swap the key.
3. Money and dates
Amounts are whole numbers in the smallest unit of the currency. For pounds that's pence: 1200 is £12.00 and 50 is 50p. There are no decimals anywhere.
Dates are ISO 8601 with a timezone, like 2026-11-14T22:00:00Z (the Z means UTC). We always reply in UTC.
4. Key permissions
A key can have full access, or only the permissions you tick when you create it. Give your website the least it needs: a site that only sells tickets needs events:read and checkout:write. A :write permission includes reading the same things.
- events:read / write
- Events and their days, ticket types, prices, add-ons and series.
- checkout:write
- Start checkouts and look them up.
- orders:read / write
- Orders. Write lets the key refund and resend tickets.
- tickets:read / write
- Tickets. Write lets the key issue and cancel guest-list tickets.
- coupons:read / write
- Discount codes.
- webhooks:read / write
- Webhook endpoints.
- branding:read / write
- Your branding: colours and wording on checkout and confirmation, contact email and ticket email style.
5. When something goes wrong
Errors always have the same shape: a short code for your program, a message written for people, and param when one field is the problem. The message is safe to log, and usually tells you how to fix it.
400 Bad Request
{
"error": {
"code": "invalid_request",
"message": "Choose between 1 and 10 tickets.",
"param": "quantity"
}
}- 400 invalid_request
- Something in the request is missing or wrong. Check param and message.
- 401 unauthorized
- No key, a mistyped key, or a revoked key.
- 403 forbidden
- The key doesn't have the permission this needs.
- 404 resource_missing
- No such object, or it belongs to the other mode (test vs live).
- 409 conflict
- Allowed in general, but not right now. For example, refunding an unpaid order.
- 422 idempotency_key_reused
- You reused an Idempotency-Key with a different request.
- 429 rate_limited
- Too many requests. Wait for Retry-After seconds.
- 500 api_error
- Our fault. Retry with the same Idempotency-Key.
6. Safe retries
Networks fail. If a request times out you can't tell whether it worked, and sending it again could, say, refund twice. To make a retry safe, add an Idempotency-Key header to POST requests: any unique string, such as your own order number.
If we've seen that key in the last 24 hours, we don't do the work again. We send back the first answer, with the header Idempotent-Replayed: true.
Retrying is now harmless
curl https://api.eventtickets.dev/v1/orders/ord_9c1e4b7a2d3f5e60/refund \ -X POST \ -H "Authorization: Bearer $EVENTTICKETS_KEY" \ -H "Idempotency-Key: refund-ord_9c1e4b7a2d3f5e60"
7. Lists and paging
Anything that returns many objects gives you a page, newest first. Ask for up to 100 with limit (default 20). If has_more is true, ask again with starting_after set to the id of the last object you got.
Fetch every order, a page at a time (Node.js)
let after;
do {
const url = new URL("https://api.eventtickets.dev/v1/orders");
url.searchParams.set("limit", "100");
if (after) url.searchParams.set("starting_after", after);
const page = await fetch(url, { headers: { Authorization: `Bearer ${key}` } }).then((r) => r.json());
for (const order of page.data) console.log(order.id, order.amount_total);
after = page.has_more ? page.data.at(-1).id : undefined;
} while (after);8. Rate limits
Each live key can make 300 requests a minute, and each test key 100. Every response tells you where you are with X-RateLimit-Remaining and X-RateLimit-Reset. Go over and you get a 429 with a Retry-After header saying how many seconds to wait.