(null);
const orderId = new URLSearchParams(window.location.search).get('orderId');
if (orderId) return ; // reads ?orderId= itself
return (
) => setEventId(e.detail.eventId)} />
{eventId && (
)}
);
}
```
Every wrapper renders the matching custom element and turns each `tl*` event
into an `onTl*` prop with the `CustomEvent` as its argument. Attributes are
camelCased props (`eventId`, `occurrenceId`, `fullWidth`).
## Without the npm packages
Load the CDN build from `index.html` and write the tags directly. This is what
works today and is also the smallest thing an AI tool can generate correctly.
```html title="index.html"
```
```tsx title="src/App.tsx"
import { useEffect, useRef } from 'react';
export default function App() {
const list = useRef(null);
useEffect(() => {
const el = list.current;
const onClick = (e: Event) => console.log((e as CustomEvent<{ eventId: string }>).detail.eventId);
el?.addEventListener('tlEventClick', onClick);
return () => el?.removeEventListener('tlEventClick', onClick);
}, []);
return (
<>
>
);
}
```
TypeScript needs to know the tags exist:
```ts title="src/tl-elements.d.ts"
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
type TlProps = DetailedHTMLProps, HTMLElement> & Record;
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'tl-event-list': TlProps;
'tl-buy-tickets-button': TlProps;
'tl-cart-badge': TlProps;
'tl-cart-drawer': TlProps;
'tl-order-confirmation': TlProps;
}
}
}
```
Attributes on raw tags are strings (`columns="3"`), and events are attached
with `addEventListener` because React does not bind custom events on
intrinsic elements. The `checkout:completed` hook is the same as in the HTML
quickstart: `window.ticketlayer.ready.then((tl) => tl.on('checkout:completed', ...))`.
## Next
- [Elements reference](https://docs.ticketlayer.com/reference/elements/) for every wrapper, prop and event
- [Theming](https://docs.ticketlayer.com/reference/elements/#theming): set `--tl-*` tokens in your CSS
- [Webhooks](https://docs.ticketlayer.com/guides/integrations/webhooks) if you later add a server
---
# Keys and authentication
Source: https://docs.ticketlayer.com/guides/getting-started/authentication
Ticketlayer has three kinds of credential. Pick by where the code runs.
| Credential | Prefix | Where it runs | What it can do | Header |
|---|---|---|---|---|
| Publishable key | `tlpk_` | Browsers, mobile apps, site builders | Read what one sales channel sells, create a cart and start checkout through the [Live API](https://docs.ticketlayer.com/api/live/) | `Authorization: Bearer tlpk_...` (or `X-Channel-Key`) |
| Organisation API key | `tlak_` | Your server | Everything the key's scopes allow on the [Backstage API](https://docs.ticketlayer.com/api/backstage/): events, orders, customers, webhooks, embed sessions | `Authorization: Bearer tlak_...` plus `X-Ticketlayer-Org: ` |
| Staff access token | JWT | Backstage, staff tools, MCP agents | Whatever the signed-in person's role allows | `Authorization: Bearer ` plus `X-Ticketlayer-Org: ` |
A channel also has **secret keys** (`tlsk_`), server-only siblings of the
publishable key for a backend that talks to the sales surface on a customer's
behalf. They are shown once when created and must never reach a browser.
## Publishable keys (browser)
The Live SDK and the CDN loader take the key once and send it on every
request; you do not write the header yourself.
```html
```
```ts
import { createLiveClient } from '@ticketlayer/live';
const tl = await createLiveClient({ baseUrl: 'https://live.staging.t9r.dev', publishableKey: 'tlpk_...' });
```
Calling the Live API directly:
```bash
curl https://live.staging.t9r.dev/sales/listings \
-H "Authorization: Bearer tlpk_..."
```
Browsing needs nothing more. The first cart creates a Live session; the SDK
holds its id and sends it as `X-Live-Session` (or a cookie on a hosted
storefront). Customer sign-in is a magic link: `POST /sales/customer-auth/magic-link`,
then `POST /sales/customer-tokens` with the code; `` does both.
**Where to get one:** Backstage, Sales channels, the channel, Keys, Create key,
Publishable (browser). Self-serve sign-up is not built yet; see
[Get a key](https://docs.ticketlayer.com/guides/getting-started/welcome#3-get-a-key).
## Organisation API keys (server)
An organisation API key is created by a staff user in Backstage (or with
`POST /v1/api-keys` while signed in) with a name and a list of scopes such as
`events.write`, `orders.read`, `saleschannels.write`. The key material is
returned once.
```bash
curl https://api.staging.t9r.dev/v1/events \
-H "Authorization: Bearer tlak_..." \
-H "X-Ticketlayer-Org: your-org-slug"
```
With the SDK:
```ts
import { BackstageClient } from '@ticketlayer/backstage';
const backstage = new BackstageClient({
baseUrl: 'https://api.staging.t9r.dev',
accessToken: process.env.TICKETLAYER_API_KEY, // tlak_...
organisationSlug: 'your-org-slug',
});
const { events } = await backstage.events.list({ limit: '20' });
```
Rules the API applies to a `tlak_` bearer:
- The key is looked up by hash; revoked or expired keys get `401`.
- The `X-Ticketlayer-Org` header must name the key's own organisation.
- Each route checks the key's scopes; a missing scope is `404`, not `403`
(the platform never confirms that something exists to a caller who cannot
see it).
- Routes that are for signed-in people only (`/v1/me/*`, `/v1/api-keys`)
refuse API keys.
API keys also mint **embed sessions** (`POST /v1/embed/sessions`): short-lived
tokens pinned to one account that let you mount Backstage widgets in your own
app with `@ticketlayer/backstage/embed`. See the Backstage SDK
[getting started](https://docs.ticketlayer.com/reference/sdk/typescript/getting-started).
## Staff tokens (Stagedoor OAuth)
People sign in through **Stagedoor**, Ticketlayer's identity service, with
OAuth 2.1 (authorization code + PKCE). Backstage, the box office and the
[MCP server](https://docs.ticketlayer.com/guides/agents/mcp) all use it. A third-party app registers a
client with Stagedoor (MCP clients do this automatically through Dynamic
Client Registration), sends the person to `/oauth/authorize`, and exchanges
the code for an access token that carries the organisation they chose at
login. Tokens are short-lived and refreshed with the refresh token.
The API also documents `POST /v1/auth/login` (email and password). It exists
for first-party tooling; integrations should use API keys for servers and
Stagedoor for people.
## Environments
| | Staging | Production |
|---|---|---|
| Backstage API | `https://api.staging.t9r.dev/v1` | `https://api.ticketlayer.com/v1` (not yet deployed) |
| Live API | `https://live.staging.t9r.dev` | `https://live.ticketlayer.com` (not yet deployed) |
| Hosted checkout | `https://hbo.staging.t9r.dev` | `https://checkout.ticketlayer.com` (not yet deployed) |
| CDN | `https://cdn.staging.t9r.dev` | `https://cdn.ticketlayer.com` (not yet deployed) |
Staging's Backstage and Stagedoor are on the team tailnet; the API, Live API,
hosted checkout and CDN are public.
## Versioning
Every request may carry `TL-Version: 2026-06-13` (the dated API version). The
SDKs send it for you; a request without it gets the organisation's default,
so generated code keeps working across releases. See
[API versions](https://docs.ticketlayer.com/api/backstage/versions).
---
# Webhooks
Source: https://docs.ticketlayer.com/guides/integrations/webhooks
Register a URL and Ticketlayer POSTs a signed JSON envelope to it whenever
one of the events below happens in your organisation. Payloads are
constructed field by field from a fixed, versioned view (never a raw database
row), so what is documented here is exactly what arrives.
## Event types
| Type | When | Payload |
|---|---|---|
| `order.created` | A new order was started | Order |
| `order.confirmed` | An order was paid and confirmed | Order |
| `order.cancelled` | An order was cancelled | Order |
| `order.refunded` | An order was refunded | Order |
| `customer.created` | A new customer was created | Customer |
| `event.created` | A new event was created | Event |
| `ticket.issued` | Tickets (passes) were issued for an order | Tickets issued |
| `ticket.redeemed` | A ticket was scanned and redeemed | Ticket redeemed |
`GET /v1/webhook-event-types` returns this list with descriptions, which is
what the Backstage subscription UI shows.
## Payloads
Money is in integer minor units with an ISO 4217 `currency` (`"totalAmount": 2500,
"currency": "GBP"` is 25.00 GBP). Instants are ISO 8601 strings. Every
nullable field is present as `null` rather than omitted.
**Order** (`order.*`)
```json
{
"id": "ord_01J...",
"orderNumber": "TL-10432",
"status": "confirmed",
"currency": "GBP",
"totalAmount": 5400,
"subtotalAmount": 5000,
"customerId": "cus_01J...",
"accountId": "acc_01J...",
"createdAt": "2026-09-13T19:04:11.000Z",
"lineItemCount": 2
}
```
**Customer** (`customer.created`)
```json
{
"id": "cus_01J...",
"email": "ada@example.com",
"firstName": "Ada",
"lastName": "Lovelace",
"accountId": "acc_01J...",
"createdAt": "2026-09-13T19:04:11.000Z"
}
```
**Event** (`event.created`)
```json
{
"id": "evt_01J...",
"name": "Jazz Night",
"status": "draft",
"accountId": "acc_01J...",
"venueId": "vnu_01J...",
"timezone": "Europe/London",
"createdAt": "2026-09-13T19:04:11.000Z"
}
```
**Tickets issued** (`ticket.issued`)
```json
{
"orderId": "ord_01J...",
"accountId": "acc_01J...",
"passCount": 2,
"passes": [
{ "id": "pas_01J...", "ticketTypeId": "tkt_01J...", "occurrenceId": "occ_01J...", "status": "issued" },
{ "id": "pas_01K...", "ticketTypeId": "tkt_01J...", "occurrenceId": "occ_01J...", "status": "issued" }
]
}
```
**Ticket redeemed** (`ticket.redeemed`)
```json
{
"redemptionId": "red_01J...",
"passId": "pas_01J...",
"entitlementId": "ent_01J...",
"accountId": "acc_01J..."
}
```
## The delivery
Each delivery is one `POST` with a JSON body:
```json
{
"id": "whd_01J...",
"type": "order.confirmed",
"version": "2026-06-13",
"createdAt": "2026-09-13T19:04:12.000Z",
"data": { "id": "ord_01J...", "orderNumber": "TL-10432", "...": "..." }
}
```
| Header | Value |
|---|---|
| `Content-Type` | `application/json` |
| `User-Agent` | `Ticketlayer-Webhooks/1.0` |
| `Ticketlayer-Signature` | `t=,v1=` |
| `Ticketlayer-Event-Type` | The event type, same as `type` in the body |
| `Ticketlayer-Event-Id` | The id of the source event; stable across retries of the same event |
| `Ticketlayer-Delivery-Id` | The id of this delivery attempt series, same as `id` in the body |
Respond with any `2xx` within 15 seconds. Anything else, or a timeout, is
retried with backoff; the delivery is marked failed when retries are
exhausted. Deliveries and their responses are listed at
`GET /v1/webhook-deliveries` and in Backstage.
Use `Ticketlayer-Event-Id` to deduplicate: a retry carries the same value.
## Verify the signature
The signing secret is returned once when the endpoint is created. The
signature is an HMAC-SHA256 of `"."` with that secret, hex
encoded; reject deliveries whose `t` is more than five minutes from now.
```ts
import crypto from 'node:crypto';
export function verifyTicketlayerSignature(rawBody: string, header: string, secret: string, toleranceSeconds = 300): boolean {
const parts = Object.fromEntries(header.split(',').map((kv) => kv.split('=').map((s) => s.trim())));
const t = Number(parts.t);
const v1 = parts.v1;
if (!t || !v1) return false;
if (Math.abs(Math.floor(Date.now() / 1000) - t) > toleranceSeconds) return false;
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const a = Buffer.from(v1, 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
```
Compute the HMAC over the **raw** request body, before any JSON parsing or
re-serialisation.
```ts title="Express"
app.post('/webhooks/ticketlayer', express.raw({ type: 'application/json' }), (req, res) => {
const raw = req.body.toString('utf8');
if (!verifyTicketlayerSignature(raw, req.get('Ticketlayer-Signature') ?? '', process.env.TL_WEBHOOK_SECRET!)) {
return res.status(400).send('bad signature');
}
const envelope = JSON.parse(raw);
if (envelope.type === 'order.confirmed') {
// envelope.data is the Order payload above
}
res.sendStatus(204);
});
```
## Register an endpoint
With an organisation API key or a staff token:
```bash
curl -X POST https://api.staging.t9r.dev/v1/webhook-endpoints \
-H "Authorization: Bearer tlak_..." \
-H "X-Ticketlayer-Org: your-org-slug" \
-H "Content-Type: application/json" \
-d '{
"accountId": "acc_01J...",
"url": "https://hooks.example.com/ticketlayer",
"description": "Orders to the CRM",
"eventTypes": ["order.confirmed", "ticket.issued"]
}'
```
The response carries the endpoint and, once only, its `secret`. Omit
`eventTypes` to receive every type. Endpoints are per account (the
organisation's sub-unit that owns the events); the same URL can be registered
for several accounts.
Operations: [create](https://docs.ticketlayer.com/api/backstage/webhook-endpoints/createwebhookendpoint),
[list](https://docs.ticketlayer.com/api/backstage/webhook-endpoints/listwebhookendpoints),
[get](https://docs.ticketlayer.com/api/backstage/webhook-endpoints/getwebhookendpoint),
[update](https://docs.ticketlayer.com/api/backstage/webhook-endpoints/updatewebhookendpoint) (URL,
description, event types, `enabled`/`disabled`),
[delete](https://docs.ticketlayer.com/api/backstage/webhook-endpoints/deletewebhookendpoint) and
[test](https://docs.ticketlayer.com/api/backstage/webhook-endpoints/testwebhookendpoint), which sends a
signed sample delivery.
## Payload versions
Webhook payloads are a public contract. Each endpoint pins the payload version
current when it was created (`2026-06-13` today) and keeps receiving that
shape: when a payload changes in a breaking way a new dated version is added
with a transform back to the previous one, and deliveries are transformed down
to the endpoint's pinned version before sending. The version is stamped in
every envelope as `version`.
## Local development
Run a tunnel (for example `ngrok http 3000`) and register the tunnel URL as
the endpoint. The test operation above is the quickest way to see a
delivery without buying a ticket.
---
# Connect an AI agent (MCP)
Source: https://docs.ticketlayer.com/guides/agents/mcp
Ticketlayer ships a **remote [MCP](https://modelcontextprotocol.io) server** so you
can point your own AI agent - Claude Desktop, Claude Code, an MCP Inspector
session, or anything that speaks MCP - at your Ticketlayer account and have it
read your catalogue, orders and customers, **query your analytics**, and (with the
right permission) create and update events.
The agent acts **as you**. Every tool call carries your own credential to the same
permissioned API the dashboard uses, so an agent can never do more than your own
role allows, and never sees another organisation's data.
| | |
|---|---|
| **Endpoint** | `https://mcp.staging.t9r.dev/mcp` (staging; production is not deployed yet) |
| **Transport** | Streamable HTTP |
| **Auth** | OAuth 2.1 - Dynamic Client Registration + PKCE |
| **Connect scope** | `mcp` |
## Where it runs today
The staging server is at `https://mcp.staging.t9r.dev/mcp` and is public.
Its authorization server, **Stagedoor** (`stagedoor.staging.t9r.dev`), is
published only on the Ticketlayer team tailnet, and the OAuth flow below has to
reach it from your browser. So today:
- from a machine on the tailnet, every client below connects and authenticates;
- from anywhere else, the client registers and starts the login, and the
browser redirect to Stagedoor does not resolve, so the connection cannot
complete.
Production, where Stagedoor is public, is not stood up yet. An API-key mode
for the MCP server (so a server-side agent can connect without the browser
flow) is planned in the platform plan and not built. When you run the stack
locally with `tt dev`, the endpoint is `https://mcp.staging.t9r.dev/mcp`.
## How it works
```
your agent ──OAuth 2.1 (register → log in → consent)──▶ stagedoor (identity)
│ issues access token
│ Streamable HTTP + Bearer token (org chosen at login)
▼
Ticketlayer MCP server ──forwards your token──▶ Ticketlayer API
· validates the token + `mcp` scope · your RBAC permissions
· org taken from the token · scope limits writes
```
1. Your MCP client discovers the server's metadata at
`/.well-known/oauth-protected-resource/mcp` and finds the authorization server.
2. It **registers itself** automatically (Dynamic Client Registration - no
pre-configuration, no client secret) and starts an OAuth login.
3. You log in, **choose which organisation** the agent may act for, and **consent**
to the scopes it requested.
4. The agent receives an access token and calls tools. The MCP server validates the
token and forwards it to the Ticketlayer API under your organisation and your
permissions.
The organisation is baked into the signed token, never chosen by the agent - so an
agent connected to one org can't reach another.
## Connect your client
The server URL is `https://mcp.staging.t9r.dev/mcp`. Every client below discovers
auth and runs the login/consent flow in your browser the first time - there is no
API key to paste and nothing to pre-register. (Read the note above about the
tailnet first: the browser step needs to reach Stagedoor.)
### Claude Code (CLI)
Add the server, then authenticate from inside a session:
```bash
# Add it (available in the current project)
claude mcp add --transport http ticketlayer https://mcp.staging.t9r.dev/mcp
# …or make it available across all your projects
claude mcp add --scope user --transport http ticketlayer https://mcp.staging.t9r.dev/mcp
```
```text
# Start Claude Code, then run the /mcp command:
claude
> /mcp
# Select "ticketlayer" → Authenticate. Your browser opens to log in + consent;
# the token is stored and refreshed automatically.
```
Manage it:
```bash
claude mcp list # shows connection / auth status
claude mcp get ticketlayer # details for one server
claude mcp remove ticketlayer # remove it
```
To share it with a repo, commit a project-scoped `.mcp.json` at the repo root
(use `--scope project` when adding, or write the file directly):
```json
{
"mcpServers": {
"ticketlayer": {
"type": "http",
"url": "https://mcp.staging.t9r.dev/mcp"
}
}
}
```
### Claude Desktop
Settings → **Connectors** → **Add custom connector** → name it `ticketlayer`
and paste `https://mcp.staging.t9r.dev/mcp`. Claude Desktop registers itself and
opens the browser for login + consent. (Custom connectors require a paid plan.)
If you prefer a config file, or your Claude Desktop only supports stdio
servers, bridge through `mcp-remote` in `claude_desktop_config.json`
(Settings → Developer → Edit Config):
```json
{
"mcpServers": {
"ticketlayer": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.staging.t9r.dev/mcp"]
}
}
}
```
### Cursor
Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):
```json
{
"mcpServers": {
"ticketlayer": {
"url": "https://mcp.staging.t9r.dev/mcp"
}
}
}
```
Then open **Settings → MCP** and authenticate the server.
### VS Code (GitHub Copilot)
```bash
code --add-mcp '{"name":"ticketlayer","type":"http","url":"https://mcp.staging.t9r.dev/mcp"}'
```
…or commit `.vscode/mcp.json` (note VS Code uses the `servers` key):
```json
{
"servers": {
"ticketlayer": {
"type": "http",
"url": "https://mcp.staging.t9r.dev/mcp"
}
}
}
```
### MCP Inspector (to test)
```bash
npx @modelcontextprotocol/inspector
```
Open it, choose transport **Streamable HTTP**, enter
`https://mcp.staging.t9r.dev/mcp`, and **Connect** - it walks you through the OAuth
flow and lets you call tools by hand.
### Any other (stdio-only) client
For a client that only speaks stdio, bridge to the remote server with
[`mcp-remote`](https://www.npmjs.com/package/mcp-remote) (it handles the OAuth
flow for you):
```json
{
"mcpServers": {
"ticketlayer": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.staging.t9r.dev/mcp"]
}
}
}
```
### Codex CLI
Add to `~/.codex/config.toml`:
```toml
[mcp_servers.ticketlayer]
url = "https://mcp.staging.t9r.dev/mcp"
```
Once connected (any client), ask things like *"list my upcoming events"* or
*"how many orders did the jazz night take?"*.
## Scopes & permissions
Access is bounded **twice**: by the OAuth scopes you consent to, and by your own
role (RBAC). An agent gets the **intersection** of the two.
| Scope | Grants |
|---|---|
| `mcp` | Connect, and **read** across your catalogue, orders and customers |
| `events.write` | **Create and update events** |
| `orders.read`, `customers.read` | Granular read access (alternative to broad `mcp`) |
- **Reads** work with the `mcp` scope alone.
- **Writes** require the matching write scope (e.g. `events.write`). If your token
doesn't carry it, the write tool returns a clear error telling you to reconnect
and grant it - your agent can prompt you to re-authorise.
- Admin operations and sensitive actions are **never** reachable through an agent
token, regardless of your role.
## Tools
**Read (run automatically):** events, occurrences, price schemes, venues and
layouts, inventory and reservations, orders and order passes, customers, sales
channels and listings, accounts, your own profile/permissions, and **analytics**
(see below).
**Write (require approval + a write scope):**
| Tool | Action |
|---|---|
| `createEvent` | Create a new event |
| `updateEvent` | Update an event's details or status |
Write tools are marked **destructive**, so your MCP client asks you to confirm each
one before it runs - that confirmation is the human-in-the-loop gate. Pricing and
seating-layout edits are not yet exposed as agent tools.
## Analytics & reporting
The agent can answer data questions ("how did the jazz night sell?", "revenue by
channel last month") through **Insights** - the governed Reporting layer that
serves the same numbers your dashboards show. These are read tools, available with
the `mcp` scope; no writes, no approval needed.
The pattern is always two steps:
1. **`getReportsMeta`** - discover the available data models, **measures** and
**dimensions**. Always call this first; you can only query members it lists.
2. **`runReportsQuery`** - run an ad-hoc query built from those members.
`runReportsQuery` takes a query object:
```json
{
"query": {
"measures": ["sales_line_items.grossRevenue", "sales_line_items.ticketsSold"],
"dimensions": ["sales_line_items.eventName"],
"order": { "sales_line_items.grossRevenue": "desc" },
"limit": 10
}
}
```
…with optional `timeDimensions` (e.g.
`[{ "dimension": "orders.createdAt", "dateRange": "last 30 days", "granularity": "day" }]`)
and `filters`. Other read tools cover saved reports and dashboards
(`listSavedReports` / `runSavedReport`, `listDashboards` / `getDashboard`,
`listReportTemplates`) and pre-baked rollups (`getReportsSummary`,
`getReportsTimeseries`, `getReportsInventory`).
Two conventions to read results correctly:
- **Money is in integer minor units** (`"grossRevenue": "229350"` = £2,293.50) and
carries a **currency** dimension - never sum across currencies.
- **Timestamps are ISO 8601 UTC**; render in the venue/org timezone for display.
Everything is **tenant-scoped automatically** - a query only ever sees your own
organisation's data, enforced server-side in the Reporting layer.
## Security model
- **You can't exceed yourself.** Tools call the same permissioned routes the UI
uses, with your token. RBAC, the `404`-not-`403` rule, and the platform's
field-stripped views all apply unchanged.
- **One org per connection.** The org is carried in the signed token; switching orgs
means logging in again.
- **Least privilege.** Agent tokens are capped to their granted scopes, so even an
organisation owner's agent only does what it was consented to do.
- **No raw data path.** The MCP server holds no database connection and no model
key - it only forwards your authenticated calls.
## Limitations (today)
- Read-first: only `createEvent` / `updateEvent` writes are exposed.
- One organisation per token.
- Self-registered (DCR) agents are public PKCE clients with `https` or loopback
redirect URIs only.
---
# Sell tickets on your website
Source: https://docs.ticketlayer.com/scenarios/sell-tickets-on-website
The whole path, in order. Each step links to the page with the detail.
## 1. Have something to sell
In Backstage create an **event** with at least one **occurrence** (a date and
time) and a **price scheme** (the ticket types and prices). Set it on sale.
With the API this is `POST /v1/events`, `POST /v1/events/{eventId}/occurrences`
and `POST /v1/events/{eventId}/price-schemes`; an [MCP agent](https://docs.ticketlayer.com/guides/agents/mcp)
can do the first two from a sentence.
## 2. Create a sales channel and a key
A **sales channel** is one place you sell: your website, a partner site, the
box office. Create one of type website in Backstage (Sales channels, New),
**list** the event on it, and under Keys create a **Publishable (browser)**
key. That `tlpk_` value is all the page needs.
There is no self-serve sign-up yet, so the organisation itself comes from the
Ticketlayer team; see [Get a key](https://docs.ticketlayer.com/guides/getting-started/welcome#3-get-a-key).
## 3. Put the elements on the page
Plain HTML or a site builder: the [HTML quickstart](https://docs.ticketlayer.com/guides/quickstarts/html).
React: the [Vite quickstart](https://docs.ticketlayer.com/guides/quickstarts/vite-react) or the
[Next.js quickstart](https://docs.ticketlayer.com/guides/quickstarts/nextjs). The minimum is the loader
script and two tags:
```html
```
Match your brand with the `--tl-*` [theme tokens](https://docs.ticketlayer.com/reference/elements/#theming),
or set a theme on the channel in Backstage and the SDK applies it.
## 4. Checkout
Checkout is hosted. When the customer presses Checkout in the cart, the SDK
opens the hosted box office's `/embed/checkout` in an iframe modal, hands it
the session so it sees the same cart, and the iframe collects contact
details and payment on its own origin. Your page never sees card data. The
iframe talks back over `postMessage`; the SDK turns that into
`checkout:completed`, `checkout:error` and a close.
## 5. Confirm on your page
Listen for the completion and show the order:
```js
window.ticketlayer.ready.then((tl) =>
tl.on('checkout:completed', (order) => {
location.href = '/thanks?orderId=' + encodeURIComponent(order.id);
}),
);
```
On `/thanks`, `` reads `?orderId=` and renders the
reference, the lines, the totals and the tickets with QR codes and PDF links.
The customer also gets a confirmation email with the PDF passes.
## 6. Confirm on your server
Register a [webhook endpoint](https://docs.ticketlayer.com/guides/integrations/webhooks) for
`order.confirmed` and `ticket.issued`. Verify `Ticketlayer-Signature`, then
update your CRM, mailing list or spreadsheet from the envelope. For
server-side reads (all orders for an event, a customer's history) use an
organisation API key with the [Backstage API](https://docs.ticketlayer.com/api/backstage/).
## 7. Returning customers
`` signs a customer in with a magic link (no passwords), and
`` lists their orders with the tickets. ``
redeems presale and promo codes against the cart. All three are on the
[Elements reference](https://docs.ticketlayer.com/reference/elements/).
---
# SDKs
Source: https://docs.ticketlayer.com/reference/sdk
Ticketlayer ships two official TypeScript SDKs, one per API surface. Both are
generated from the same OpenAPI documents that power the API reference, so
their types always match the contract, and each sends the dated API version
(`TL-Version`) it was generated against.
## Which packages are on npm today
| Package | What | npm |
|---|---|---|
| `@ticketlayer/backstage` | Backstage API client (servers, staff tools, embed loader) | **Published**, 0.1.x |
| `@ticketlayer/live` | Live API client for browsers, React Native and servers (`/server`) | Not yet: publishes when its release workflow runs |
| `@ticketlayer/elements` | The `tl-*` web components | Not yet: same |
| `@ticketlayer/elements-react` | React wrappers for the elements | Not yet: same |
`@ticketlayer/backstage-sdk` was the old name of the Backstage package and is
no longer maintained; use `@ticketlayer/backstage`. Until the three Live
packages publish, the browser path that works is the CDN build
(`cdn.staging.t9r.dev/v1/ticketlayer.js`); see the
[HTML quickstart](https://docs.ticketlayer.com/guides/quickstarts/html).
## [Backstage SDK](https://docs.ticketlayer.com/reference/sdk/backstage) - `@ticketlayer/backstage`
The server-side SDK for the **Backstage API**: events, venues, inventory,
sales channels, orders, customers, payments, webhooks, organisations and the
full admin surface. Use it in Node.js backends and internal tooling with an
organisation API key, or in staff apps with a Stagedoor token. It also
carries `@ticketlayer/backstage/embed`, the loader for Backstage widgets in
your own app.
```bash
npm install @ticketlayer/backstage
```
See the [getting started guide](https://docs.ticketlayer.com/reference/sdk/typescript/getting-started) and the
[full reference](https://docs.ticketlayer.com/reference/sdk/backstage).
## [Live SDK](https://docs.ticketlayer.com/reference/sdk/live) - `@ticketlayer/live`
The buyer-facing SDK for the **Live API**: sessions, listings, the cart, the
hosted checkout modal, customer sign-in and orders. It runs in the browser
and React Native, publishes itself on `window.Ticketlayer` for the
[Elements](https://docs.ticketlayer.com/reference/elements/), and has a stateless server entry
(`@ticketlayer/live/server`) for Next.js and edge runtimes.
```bash
npm install @ticketlayer/live
```
See the [Next.js quickstart](https://docs.ticketlayer.com/guides/quickstarts/nextjs) and the
[full reference](https://docs.ticketlayer.com/reference/sdk/live).
## Reference is auto-generated
These reference pages are generated from each package's TypeScript source
with TypeDoc (`npm run docs:sdk:gen` in the docs repository) and refreshed
whenever the SDKs are rebuilt.
---
# API versions
Source: https://docs.ticketlayer.com/api/backstage/versions
The Backstage API uses **dated versions** - each version is named after the day it was
released, for example `2026-06-13`. The current version is **`2026-06-13`**.
Within a version the API only ever changes additively: new endpoints, new optional
parameters and new response fields may appear, but existing behaviour never changes.
Breaking changes are only ever introduced in a new dated version, so an integration
pinned to a version keeps working unchanged.
## How versioning works
- **Pin with the `TL-Version` header.** Send the version date on every request to pin
the API behaviour your integration expects. Responses echo the version that served
the request in a `TL-Version` response header.
- **Organisations are pinned at signup.** When an organisation is created it is pinned
to the then-current version. Requests that omit `TL-Version` use the organisation's
pinned version, so existing integrations are never broken by a new release.
- **SDK majors pin a version.** Each major release of an official SDK hardcodes the
version it speaks (the current TypeScript SDK sends `2026-06-13`). Upgrading
the SDK is how most integrations move between API versions.
- **Additive changes only within a version.** We may add endpoints, optional request
fields and response fields at any time without releasing a new version. Your
integration should ignore response fields it does not recognise.
- **Twelve-month deprecation windows.** When a version is deprecated you have at least
12 months before it is sunset. While deprecated, responses include
[`Deprecation`](https://datatracker.ietf.org/doc/html/rfc9745) and
[`Sunset`](https://datatracker.ietf.org/doc/html/rfc8594) headers telling you when
the version stops being served.
### Pinning a version
```bash
curl https://api.ticketlayer.com/v1/events \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "TL-Version: 2026-06-13"
```
### Discovering versions at runtime
The full version list, including deprecation and sunset dates, is available from the
API itself:
```bash
curl https://api.ticketlayer.com/v1/meta/versions
```
## Version status
| Version | Status | Summary | Deprecated | Sunset |
|---------|--------|---------|------------|--------|
| **`2026-06-13`** | Current | Baseline dated version - all prior behaviour, no transforms. | - | - |
## Version history
### 2026-06-13
Current
Baseline dated version - all prior behaviour, no transforms.
No breaking changes - this is the baseline dated version.
## See also
- [API changelog](./changelog) - additive changes and fixes within versions
- [Backstage API introduction](https://docs.ticketlayer.com/api/backstage/)
---
# Elements reference
## Elements
Source: https://docs.ticketlayer.com/reference/elements
Elements are web components (custom HTML tags prefixed `tl-`) that list events,
take a customer through ticket selection, cart and checkout, and show the
tickets they bought. They work in plain HTML, in Webflow or any site builder
that lets you add a script tag, and in React through the generated wrappers in
`@ticketlayer/elements-react`.
Every element binds to the Live client the page publishes on
`window.Ticketlayer`. Elements take no API key of their own: create the client
once (the CDN loader does this from its `data-*` attributes, or call
`createLiveClient()` from `@ticketlayer/live`) and the elements find it.
### Get them onto the page
**CDN, no build step.** One script tag loads the Live SDK, the Elements bundle
and the hosted checkout modal. The tags below then just work.
```html
```
See the [HTML quickstart](https://docs.ticketlayer.com/guides/quickstarts/html) for the attributes each
environment needs today.
**npm, for React and bundlers.**
```bash
npm install @ticketlayer/live @ticketlayer/elements @ticketlayer/elements-react
```
```tsx
import { createLiveClient } from '@ticketlayer/live';
import { defineCustomElements, TlEventList } from '@ticketlayer/elements-react';
defineCustomElements(); // once, after hydration
await createLiveClient({ baseUrl: 'https://live.staging.t9r.dev', publishableKey: 'tlpk_...' });
console.log(e.detail.eventId)} />
```
Note (Package status):
`@ticketlayer/live`, `@ticketlayer/elements` and `@ticketlayer/elements-react`
are built in their repositories but are not on the public npm registry yet;
they publish once their release workflows run. Until then use the CDN build,
which staging serves at `cdn.staging.t9r.dev`. See the
[Vite quickstart](https://docs.ticketlayer.com/guides/quickstarts/vite-react) for the workaround in the meantime.
### Elements
### Discovery
List and present events.
| Element | React | What it does |
|---|---|---|
| [``](./tl-event-card) | `TlEventCard` | |
| [``](./tl-event-list) | `TlEventList` | |
| [``](./tl-occurrence-selector) | `TlOccurrenceSelector` | A smart occurrence selector component that fetches and displays event occurrences from the Ticketlayer API. |
### Purchase
Choose a date, pick tickets, open the buy flow.
| Element | React | What it does |
|---|---|---|
| [``](./tl-buy-modal) | - | |
| [``](./tl-buy-tickets-button) | `TlBuyTicketsButton` | |
| [``](./tl-buy-tickets-wrapper) | `TlBuyTicketsWrapper` | |
| [``](./tl-promo-code) | `TlPromoCode` | tl-promo-code - an input plus Apply button that redeems a presale or promo code for the current cart (POST /sales/presale-codes/redeem through the SDK). |
| [``](./tl-seat-map) | `TlSeatMap` | |
| [``](./tl-ticket-selector) | `TlTicketSelector` | |
### Cart
Show and edit what the customer is about to buy.
| Element | React | What it does |
|---|---|---|
| [``](./tl-cart) | `TlCart` | |
| [``](./tl-cart-badge) | `TlCartBadge` | |
| [``](./tl-cart-drawer) | `TlCartDrawer` | |
### Checkout
Hand off to the hosted checkout and confirm the order.
| Element | React | What it does |
|---|---|---|
| [``](./tl-checkout-wrapper) | `TlCheckoutWrapper` | |
| [``](./tl-order-confirmation) | `TlOrderConfirmation` | tl-order-confirmation - the "thank you" page block: order reference, customer email, event and date, ticket lines, totals, then the tickets themselves (tl-order-tickets, each with a Download PDF link) |
### Tickets
Render issued tickets with QR codes and PDF downloads.
| Element | React | What it does |
|---|---|---|
| [``](./tl-order-tickets) | `TlOrderTickets` | tl-order-tickets - renders all the tickets for an order as scannable QR cards with PDF download. |
| [``](./tl-ticket) | `TlTicket` | tl-ticket - a single event ticket: a scannable QR (the redemption token), ticket name / seat / holder, and a PDF download. |
### Account
Sign in with a magic link and show past orders.
| Element | React | What it does |
|---|---|---|
| [``](./tl-login) | `TlLogin` | tl-login - magic-link sign-in. |
| [``](./tl-my-orders) | `TlMyOrders` | tl-my-orders - the signed-in customer's orders (GET /sales/my-orders through the SDK): event, date, ticket count, total and status per row. |
### Events
Every element emits `CustomEvent`s whose names start with `tl` and whose
payload is on `event.detail`. In HTML:
```html
```
In React each event is a prop named `onTl...`:
` ...} />`.
### Theming
Elements read CSS custom properties prefixed `--tl-`. The Live SDK injects the
values of the channel's theme (configured in Backstage) when
`applyTheme` is on, which it is by default; set any token yourself on
`:root` or on a wrapper to override. The defaults below come from the
Elements global stylesheet and apply when nothing else sets the token.
### General
| Token | Default |
|---|---|
| `--tl-font-family` | `system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif` |
| `--tl-font-family-mono` | `ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace` |
### Colours
| Token | Default |
|---|---|
| `--tl-primary` | `#6366f1` |
| `--tl-primary-foreground` | `#ffffff` |
| `--tl-secondary` | `#f3f4f6` |
| `--tl-secondary-foreground` | `#111827` |
| `--tl-background` | `#ffffff` |
| `--tl-foreground` | `#111827` |
| `--tl-muted` | `#f9fafb` |
| `--tl-muted-foreground` | `#6b7280` |
| `--tl-border` | `#e5e7eb` |
| `--tl-success` | `#10b981` |
| `--tl-success-foreground` | `#ffffff` |
| `--tl-warning` | `#f59e0b` |
| `--tl-warning-foreground` | `#ffffff` |
| `--tl-error` | `#ef4444` |
| `--tl-error-foreground` | `#ffffff` |
### Shape
| Token | Default |
|---|---|
| `--tl-radius-sm` | `0.25rem` |
| `--tl-radius-md` | `0.5rem` |
| `--tl-radius-lg` | `0.75rem` |
### Spacing
| Token | Default |
|---|---|
| `--tl-spacing-1` | `0.25rem` |
| `--tl-spacing-2` | `0.5rem` |
| `--tl-spacing-3` | `0.75rem` |
| `--tl-spacing-4` | `1rem` |
| `--tl-spacing-6` | `1.5rem` |
| `--tl-spacing-8` | `2rem` |
```css
:root {
--tl-primary: #0f766e;
--tl-primary-foreground: #ffffff;
--tl-radius-md: 0.25rem;
--tl-font-family: 'Inter', system-ui, sans-serif;
}
```
Elements render in shadow DOM, so ordinary CSS selectors from the page do not
reach inside them; the tokens are the styling contract.
##
Source: https://docs.ticketlayer.com/reference/elements/tl-buy-modal
| | |
|---|---|
| HTML tag | `` |
| React | No wrapper: this element is mounted by the SDK, not placed in markup |
| Category | Purchase |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------------- | --------------- | ----------------------------------------------------------------- | --------------------- | ----------- |
| `eventId` _(required)_ | `event-id` | Event to sell tickets for. | `string` | `undefined` |
| `occurrenceId` | `occurrence-id` | Optionally open straight to ticket selection for this occurrence. | `string \| undefined` | `undefined` |
### Events
| Event | Description | Type |
| ------------ | ----------- | ----------------------------------- |
| `tlCheckout` | | `CustomEvent` |
| `tlClose` | | `CustomEvent` |
| `tlError` | | `CustomEvent<{ message: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Renders: [``](./tl-occurrence-selector), [``](./tl-ticket-selector)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-buy-tickets-button
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlBuyTicketsButton } from '@ticketlayer/elements-react'` |
| Category | Purchase |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------------- | --------------- | ------------------------------------------------- | -------------------------------------------------------- | ------------- |
| `currency` | `currency` | Currency code for price formatting | `string` | `'GBP'` |
| `disabled` | `disabled` | Disabled state | `boolean` | `false` |
| `eventId` _(required)_ | `event-id` | Event ID to purchase tickets for | `string` | `undefined` |
| `fullWidth` | `full-width` | Full width button | `boolean` | `false` |
| `label` | `label` | Button label override (default depends on state) | `string \| undefined` | `undefined` |
| `occurrenceId` | `occurrence-id` | Optional pre-selected occurrence ID | `string \| undefined` | `undefined` |
| `price` | `price` | Price to display (in minor units e.g. pence) | `number \| undefined` | `undefined` |
| `pricePrefix` | `price-prefix` | Show price prefix text | `string` | `'From'` |
| `size` | `size` | Button size | `"lg" \| "md" \| "sm"` | `'md'` |
| `state` | `state` | Button state - determines colour, label, and icon | `"available" \| "comingSoon" \| "soldOut" \| "waitlist"` | `'available'` |
| `variant` | `variant` | Button variant | `"outline" \| "primary" \| "secondary"` | `'primary'` |
### Events
| Event | Description | Type |
| --------- | --------------------------------------------------- | ----------------------------------------------------------------------- |
| `tlClick` | Emitted when button is clicked (before modal opens) | `CustomEvent<{ eventId: string; occurrenceId?: string \| undefined; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
##
Source: https://docs.ticketlayer.com/reference/elements/tl-buy-tickets-wrapper
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlBuyTicketsWrapper } from '@ticketlayer/elements-react'` |
| Category | Purchase |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------------- | --------------- | ----------------------------------------------------------- | --------------------- | ----------- |
| `disabled` | `disabled` | Whether the wrapper is disabled | `boolean` | `false` |
| `eventId` _(required)_ | `event-id` | The event ID to purchase tickets for | `string` | `undefined` |
| `occurrenceId` | `occurrence-id` | Optional specific occurrence ID (skips occurrence selector) | `string \| undefined` | `undefined` |
### Events
| Event | Description | Type |
| ------------- | -------------------------------------------- | ----------------------------------- |
| `tl-close` | Emitted when the modal closes | `CustomEvent` |
| `tl-complete` | Emitted when purchase completes successfully | `CustomEvent` |
| `tl-error` | Emitted when an error occurs | `CustomEvent<{ message: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Slots
| Slot | Description |
| ---- | --------------------------------------- |
| | Content to display (typically a button) |
##
Source: https://docs.ticketlayer.com/reference/elements/tl-cart-badge
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlCartBadge } from '@ticketlayer/elements-react'` |
| Category | Cart |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| ----------- | ------------ | ---------------------------------------------------------------- | ---------------------- | ----------- |
| `badgeOnly` | `badge-only` | Badge only mode - only shows the count bubble, no icon or button | `boolean` | `false` |
| `icon` | `icon` | Custom icon (emoji or text). If not provided, uses cart SVG | `string \| undefined` | `undefined` |
| `showEmpty` | `show-empty` | Show the badge even when count is 0 | `boolean` | `false` |
| `size` | `size` | Size variant | `"lg" \| "md" \| "sm"` | `'md'` |
### Events
| Event | Description | Type |
| --------- | --------------------------------- | ------------------------------------- |
| `tlClick` | Emitted when the badge is clicked | `CustomEvent<{ itemCount: number; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
##
Source: https://docs.ticketlayer.com/reference/elements/tl-cart-drawer
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlCartDrawer } from '@ticketlayer/elements-react'` |
| Category | Cart |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| --------- | --------- | ---------------------------------------------------------------------- | ------------------- | ------------- |
| `heading` | `heading` | Heading shown at the top of the panel. | `string` | `'Your cart'` |
| `open` | `open` | Controlled open state (also driven by the `ui:cart-requested` intent). | `boolean` | `false` |
| `side` | `side` | Edge the panel slides in from. | `"left" \| "right"` | `'right'` |
### Events
| Event | Description | Type |
| --------- | ----------- | ------------------- |
| `tlClose` | | `CustomEvent` |
| `tlOpen` | | `CustomEvent` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Renders: [``](./tl-cart)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-cart
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlCart } from '@ticketlayer/elements-react'` |
| Category | Cart |
| Runs in | web (browser DOM), native (planned React Native set) |
### Properties
| Property | Attribute | Description | Type | Default |
| -------------------- | ---------------------- | --------------------------------- | --------- | ------------ |
| `checkoutLabel` | `checkout-label` | Checkout button label | `string` | `'Checkout'` |
| `compact` | `compact` | Compact mode - hides some details | `boolean` | `false` |
| `showCheckoutButton` | `show-checkout-button` | Show checkout button | `boolean` | `true` |
| `showRemoveButtons` | `show-remove-buttons` | Show remove item buttons | `boolean` | `true` |
### Events
| Event | Description | Type |
| --------------- | -------------------------------- | ------------------------------------ |
| `tlCartUpdated` | Emitted when cart is updated | `CustomEvent<{ cart: TlCartData; }>` |
| `tlCheckout` | Emitted when checkout is clicked | `CustomEvent<{ cart: TlCartData; }>` |
| `tlError` | Emitted on error | `CustomEvent<{ message: string; }>` |
| `tlItemRemoved` | Emitted when item is removed | `CustomEvent<{ itemId: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Used by: [``](./tl-cart-drawer)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-checkout-wrapper
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlCheckoutWrapper } from '@ticketlayer/elements-react'` |
| Category | Checkout |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| ---------- | ---------- | ------------------------------- | --------- | ------- |
| `disabled` | `disabled` | Whether the wrapper is disabled | `boolean` | `false` |
### Events
| Event | Description | Type |
| ------------- | -------------------------------------------- | ----------------------------------- |
| `tl-close` | Emitted when the modal closes | `CustomEvent` |
| `tl-complete` | Emitted when checkout completes successfully | `CustomEvent` |
| `tl-error` | Emitted when an error occurs | `CustomEvent<{ message: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Slots
| Slot | Description |
| ---- | ------------------------------------------------ |
| | Content to display (typically a checkout button) |
##
Source: https://docs.ticketlayer.com/reference/elements/tl-event-card
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlEventCard } from '@ticketlayer/elements-react'` |
| Category | Discovery |
| Runs in | web (browser DOM), native (planned React Native set) |
### Properties
| Property | Attribute | Description | Type | Default |
| --------- | ---------- | ----------------------------------------------------------------------------------------------------------------------- | ------------------------------- | ----------- |
| `event` | -- | Event data to display (tl-event-list passes this) | `TlEventCardEvent \| undefined` | `undefined` |
| `eventId` | `event-id` | Load the event from the SDK by id when no `event` is given, so a single card works standalone (e.g. on a Webflow page). | `string \| undefined` | `undefined` |
### Events
| Event | Description | Type |
| --------- | ------------------------------------------------ | ----------------------------------- |
| `tlClick` | Emitted when the card is clicked | `CustomEvent<{ eventId: string; }>` |
| `tlError` | Emitted when the event could not be loaded by id | `CustomEvent<{ message: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Used by: [``](./tl-event-list)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-event-list
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlEventList } from '@ticketlayer/elements-react'` |
| Category | Discovery |
| Runs in | web (browser DOM), native (planned React Native set) |
### Properties
| Property | Attribute | Description | Type | Default |
| ---------- | ---------- | --------------------------------------- | --------------------- | ----------- |
| `category` | `category` | Category filter | `string \| undefined` | `undefined` |
| `columns` | `columns` | Columns for grid layout (1, 2, 3, or 4) | `number` | `3` |
| `limit` | `limit` | Maximum number of events to display | `number` | `12` |
### Events
| Event | Description | Type |
| -------------- | ------------------------------------- | ----------------------------------- |
| `tlEventClick` | Emitted when an event card is clicked | `CustomEvent<{ eventId: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Renders: [``](./tl-event-card)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-login
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlLogin } from '@ticketlayer/elements-react'` |
| Category | Account |
| Runs in | web (browser DOM), native (planned React Native set) |
tl-login - magic-link sign-in. The customer enters an email, we ask the SDK
to send a link (POST /sales/customer-auth/magic-link), then either the link
lands back on this page with `?code=` or the customer types the code from
the email; both exchange through the SDK (POST /sales/customer-tokens). No
password is ever handled here.
States: enter email -> check your inbox (resend, enter code) -> signed in
(email + sign out).
```html
```
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------- | ------------------ | ------------------------------------------------------------------------ | --------- | ----------- |
| `allowCodeEntry` | `allow-code-entry` | Offer a "enter the code" path alongside the emailed link (default true). | `boolean` | `true` |
| `heading` | `heading` | Heading for the email step. | `string` | `'Sign in'` |
### Events
| Event | Description | Type |
| ----------------- | ----------- | ----------------------------------- |
| `tlAuthChanged` | | `CustomEvent` |
| `tlError` | | `CustomEvent<{ message: string; }>` |
| `tlMagicLinkSent` | | `CustomEvent<{ email: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Used by: [``](./tl-my-orders)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-my-orders
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlMyOrders } from '@ticketlayer/elements-react'` |
| Category | Account |
| Runs in | web (browser DOM), native (planned React Native set) |
tl-my-orders - the signed-in customer's orders (GET /sales/my-orders through
the SDK): event, date, ticket count, total and status per row. Clicking a
row expands it to show the order's tickets (tl-order-tickets). Shows
tl-login inline when nobody is signed in.
```html
```
### Properties
| Property | Attribute | Description | Type | Default |
| -------------- | --------------- | ------------------------------------- | -------- | -------------------------------------------------------------------------- |
| `columns` | `columns` | Columns for the expanded ticket grid. | `number` | `2` |
| `emptyMessage` | `empty-message` | Copy for the empty state. | `string` | `"When you buy tickets they'll show up here, ready to view and download."` |
### Events
| Event | Description | Type |
| --------------- | ----------- | ----------------------------------- |
| `tlError` | | `CustomEvent<{ message: string; }>` |
| `tlOrderSelect` | | `CustomEvent<{ orderId: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Renders: [``](./tl-order-tickets), [``](./tl-login)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-occurrence-selector
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlOccurrenceSelector } from '@ticketlayer/elements-react'` |
| Category | Discovery |
| Runs in | web (browser DOM) |
A smart occurrence selector component that fetches and displays event occurrences from the Ticketlayer API.
### Features
- **Automatic data fetching** - Fetches occurrences via the Ticketlayer SDK
- **Adaptive display modes** - Automatically chooses list, slots, or calendar view based on occurrence count
- **Loading & error states** - Built-in spinner and error handling with retry
- **Responsive** - Works on mobile and desktop with auto-adjusting layouts
- **Themeable** - Fully customizable via CSS custom properties
### Usage
```tsx
import { TlOccurrenceSelector } from '@ticketlayer/elements-react';
console.log('Selected:', e.detail.occurrence)}
/>
```
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------------- | -------------- | --------------------------------------------------------------------- | ---------------------------------------------- | ----------- |
| `displayMode` | `display-mode` | Force a specific display mode (auto-detected if not set) | `"calendar" \| "list" \| "slots" \| undefined` | `undefined` |
| `eventId` _(required)_ | `event-id` | Event ID to fetch occurrences for | `string` | `undefined` |
| `orientation` | `orientation` | Layout orientation (auto = horizontal on desktop, vertical on mobile) | `"auto" \| "horizontal" \| "vertical"` | `'auto'` |
| `theme` | -- | Theme configuration | `TlOccurrenceSelectorTheme \| undefined` | `undefined` |
### Events
| Event | Description | Type |
| ---------- | -------------------------------------- | -------------------------------------------- |
| `tlSelect` | Emitted when an occurrence is selected | `CustomEvent<{ occurrence: TlOccurrence; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Used by: [``](./tl-buy-modal)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-order-confirmation
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlOrderConfirmation } from '@ticketlayer/elements-react'` |
| Category | Checkout |
| Runs in | web (browser DOM), native (planned React Native set) |
tl-order-confirmation - the "thank you" page block: order reference,
customer email, event and date, ticket lines, totals, then the tickets
themselves (tl-order-tickets, each with a Download PDF link).
Finds its order three ways, in priority order:
1. the `order-id` prop
2. the URL (`?orderId=`), the contract the hosted box office confirmation
page uses; `?redirect_status=` from a Stripe return is honoured too
3. the SDK's `checkout:completed` event, for a page that mounts this before
the customer pays
```html
```
### Properties
| Property | Attribute | Description | Type | Default |
| --------------- | ---------------- | -------------------------------------------------------------------------------------- | --------------------- | ----------- |
| `columns` | `columns` | Columns for the ticket grid. | `number` | `2` |
| `customerEmail` | `customer-email` | Email to show when the order view carries none (a host that collected it at checkout). | `string \| undefined` | `undefined` |
| `orderId` | `order-id` | The order to show. Falls back to `?orderId=` in the page URL. | `string \| undefined` | `undefined` |
| `showTickets` | `show-tickets` | Mount tl-order-tickets under the summary (default true). | `boolean` | `true` |
### Events
| Event | Description | Type |
| --------------- | ----------- | -------------------------------------- |
| `tlError` | | `CustomEvent<{ message: string; }>` |
| `tlOrderLoaded` | | `CustomEvent<{ order: TlOrderData; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Renders: [``](./tl-order-tickets)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-order-tickets
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlOrderTickets } from '@ticketlayer/elements-react'` |
| Category | Tickets |
| Runs in | web (browser DOM), native (planned React Native set) |
tl-order-tickets - renders all the tickets for an order as scannable QR
cards with PDF download. Fetches the order through the SDK (order-access
gated by the session), so it works on a confirmation page or in an account.
```html
```
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------------- | ---------- | -------------------------------- | -------- | ----------- |
| `columns` | `columns` | Columns in the grid (default 2). | `number` | `2` |
| `orderId` _(required)_ | `order-id` | The order whose tickets to show. | `string` | `undefined` |
### Related elements
Renders: [``](./tl-ticket)
Used by: [``](./tl-my-orders), [``](./tl-order-confirmation)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-promo-code
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlPromoCode } from '@ticketlayer/elements-react'` |
| Category | Purchase |
| Runs in | web (browser DOM) |
tl-promo-code - an input plus Apply button that redeems a presale or promo
code for the current cart (POST /sales/presale-codes/redeem through the
SDK). Redemption unlocks gated pricing on the customer; the SDK re-reads the
cart and publishes cart:updated, so tl-cart and badges re-render on their own.
The API has no un-redeem, so the applied state offers only "use a different
code", which clears the input for another redemption.
```html
```
### Properties
| Property | Attribute | Description | Type | Default |
| ------------- | -------------- | ------------------- | -------- | ------------------------- |
| `buttonLabel` | `button-label` | Apply button label. | `string` | `'Apply'` |
| `placeholder` | `placeholder` | Input placeholder. | `string` | `'Promo or presale code'` |
### Events
| Event | Description | Type |
| ---------------- | ----------- | ----------------------------------- |
| `tlError` | | `CustomEvent<{ message: string; }>` |
| `tlPromoApplied` | | `CustomEvent` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
##
Source: https://docs.ticketlayer.com/reference/elements/tl-seat-map
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlSeatMap } from '@ticketlayer/elements-react'` |
| Category | Purchase |
| Runs in | web (browser DOM) |
### Properties
| Property | Attribute | Description | Type | Default |
| --------------------------- | --------------- | ------------------------------------------ | -------- | ------------------------------------ |
| `apiUrl` | `api-url` | API URL for the seat map data | `string` | `'https://api.ticketlayer.com'` |
| `hboUrl` | `hbo-url` | Base URL for the hosted seat map (HBO URL) | `string` | `'https://checkout.ticketlayer.com'` |
| `height` | `height` | Height of the seat map | `string` | `'600px'` |
| `occurrenceId` _(required)_ | `occurrence-id` | Occurrence ID to show seat map for | `string` | `undefined` |
| `width` | `width` | Width of the seat map | `string` | `'100%'` |
### Events
| Event | Description | Type |
| --------------- | ---------------------------------------- | -------------------------------------------------------- |
| `tlCartChange` | Emitted when cart seats change | `CustomEvent<{ seatIds: string[]; }>` |
| `tlError` | Emitted when an error occurs | `CustomEvent<{ error: string; }>` |
| `tlLoad` | Emitted when seat map is loaded | `CustomEvent<{ seatMapId: string; }>` |
| `tlReady` | Emitted when seat map is ready | `CustomEvent` |
| `tlSeatAdded` | Emitted when a seat is added to cart | `CustomEvent<{ seatId: string; ticketTypeId: string; }>` |
| `tlSeatRemoved` | Emitted when a seat is removed from cart | `CustomEvent<{ seatId: string; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
##
Source: https://docs.ticketlayer.com/reference/elements/tl-ticket-selector
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlTicketSelector } from '@ticketlayer/elements-react'` |
| Category | Purchase |
| Runs in | web (browser DOM), native (planned React Native set) |
### Properties
| Property | Attribute | Description | Type | Default |
| --------------------------- | --------------- | ----------------------- | --------- | --------------- |
| `buttonLabel` | `button-label` | Button label | `string` | `'Add to Cart'` |
| `eventId` _(required)_ | `event-id` | Event ID | `string` | `undefined` |
| `occurrenceId` _(required)_ | `occurrence-id` | Occurrence ID | `string` | `undefined` |
| `showButton` | `show-button` | Show add to cart button | `boolean` | `true` |
### Events
| Event | Description | Type |
| ------------------ | ------------------------------------ | ------------------------------------------------------------------------- |
| `tlAddToCart` | Emitted when items are added to cart | `CustomEvent<{ items: AddToCartItem[]; }>` |
| `tlError` | Emitted on error | `CustomEvent<{ message: string; }>` |
| `tlQuantityChange` | Emitted when quantity changes | `CustomEvent<{ ticketTypeId: string; quantity: number; total: number; }>` |
Events are `CustomEvent`s; the payload is on `event.detail`. In HTML, listen with `element.addEventListener('tlXxx', handler)`; in React the wrapper exposes each one as an `onTlXxx` prop.
### Related elements
Used by: [``](./tl-buy-modal)
##
Source: https://docs.ticketlayer.com/reference/elements/tl-ticket
| | |
|---|---|
| HTML tag | `` |
| React | `import { TlTicket } from '@ticketlayer/elements-react'` |
| Category | Tickets |
| Runs in | web (browser DOM), native (planned React Native set) |
tl-ticket - a single event ticket: a scannable QR (the redemption token),
ticket name / seat / holder, and a PDF download. Greys out + stamps
Used/Void when redeemed or cancelled.
### Properties
| Property | Attribute | Description | Type | Default |
| ---------------------- | ---------- | ------------------------------------------------------- | -------------- | ----------- |
| `orderId` _(required)_ | `order-id` | Order id this ticket belongs to (for the PDF download). | `string` | `undefined` |
| `ticket` _(required)_ | -- | The ticket to render. | `TlTicketData` | `undefined` |
### Related elements
Used by: [``](./tl-order-tickets)
---
# API operation index
## Backstage API
Base URL: https://api.ticketlayer.com/v1 (staging: https://api.staging.t9r.dev/v1). OpenAPI document: https://docs.ticketlayer.com/openapi/backstage.json. Reference pages: https://docs.ticketlayer.com/api/backstage/.
### Meta
- GET /meta/versions - List API versions (listApiVersions)
### Authentication
- POST /auth/login - User login (login)
- POST /auth/refresh - Refresh access token (refresh)
- POST /auth/redeem - Redeem invitation (redeem)
- POST /auth/federate - Federate user to organisation (federate)
### Me
- GET /me - Get current user (getCurrentUser)
- GET /me/organisations - Get my organisations (getMyOrganisations)
- GET /me/roles - Get my roles (getMyRoles)
- GET /me/permissions - Get my permissions (getMyPermissions)
### Organisations
- GET /organisations/{id} - Get organisation (getOrganisation)
- PATCH /organisations/{id} - Update organisation (updateOrganisation)
### Accounts
- GET /accounts - List accounts (listAccounts)
- POST /accounts - Create account (createAccount)
- GET /accounts/{id} - Get account (getAccount)
- PATCH /accounts/{id} - Update account (updateAccount)
- DELETE /accounts/{id} - Delete account (deleteAccount)
### Identity Providers
- GET /identity-providers - List identity providers (listIdentityProviders)
- GET /identity-providers/{id} - Get identity provider (getIdentityProvider)
- PATCH /identity-providers/{id} - Update identity provider (updateIdentityProvider)
### User Invitations
- POST /users/invitations - Create user invitation (createUserInvitation)
- GET /users/invitations - List user invitations (listUserInvitations)
- GET /users/invitations/{id} - Get user invitation (getUserInvitation)
- DELETE /users/invitations/{id} - Cancel user invitation (cancelUserInvitation)
- POST /users/invitations/{id}/resend - Resend user invitation (resendUserInvitation)
### Roles
- GET /roles - List roles (listRoles)
- POST /roles - Create role (createRole)
- GET /roles/{id} - Get role (getRole)
- PATCH /roles/{id} - Update role (updateRole)
- DELETE /roles/{id} - Delete role (deleteRole)
### User Account Roles
- GET /user-accounts - List all role assignments (listUserAccountRoles)
- POST /user-accounts - Assign role to user (assignRole)
- PUT /user-accounts - Update user roles on account (updateUserAccountRoles)
- DELETE /user-accounts/{id} - Remove role assignment (removeRoleAssignment)
- GET /user-accounts/user/{userId} - List role assignments for user (listUserAccountRolesByUser)
- GET /user-accounts/account/{accountId} - List role assignments for account (listUserAccountRolesByAccount)
### Partners
- POST /partners/accounts - Provision a partner customer account (createPartnerAccount)
### API Keys
- POST /api-keys - Create an organisation API key (createApiKey)
- GET /api-keys - List organisation API keys (listApiKeys)
- DELETE /api-keys/{id} - Revoke an organisation API key (revokeApiKey)
### Embed Sessions
- POST /embed/sessions - Mint an embed session (createEmbedSession)
- GET /embed/sessions/current - Describe the current embed session (getCurrentEmbedSession)
### Events
- GET /events - List events (listEvents)
- POST /events - Create event (createEvent)
- GET /events/{id} - Get event (getEvent)
- PATCH /events/{id} - Update event (updateEvent)
- DELETE /events/{id} - Delete event (deleteEvent)
### Event Occurrences
- GET /events/{eventId}/occurrences - List occurrences for event (listEventOccurrences)
- POST /events/{eventId}/occurrences - Create event occurrence (createEventOccurrence)
- GET /events/{eventId}/occurrences/{occurrenceId} - Get event occurrence (getEventOccurrence)
- PATCH /events/{eventId}/occurrences/{occurrenceId} - Update event occurrence (updateEventOccurrence)
- DELETE /events/{eventId}/occurrences/{occurrenceId} - Delete event occurrence (deleteEventOccurrence)
### Event Price Schemes
- GET /events/{eventId}/price-schemes - List price schemes for event (listEventPriceSchemes)
- POST /events/{eventId}/price-schemes - Create price scheme for event (createEventPriceScheme)
- GET /events/{eventId}/price-schemes/{priceSchemeId} - Get price scheme (getEventPriceScheme)
- PATCH /events/{eventId}/price-schemes/{priceSchemeId} - Update price scheme (updateEventPriceScheme)
- DELETE /events/{eventId}/price-schemes/{priceSchemeId} - Delete price scheme (deleteEventPriceScheme)
### Venues
- GET /venues - List venues (listVenues)
- POST /venues - Create venue (createVenue)
- GET /venues/{id} - Get venue (getVenue)
- PATCH /venues/{id} - Update venue (updateVenue)
- DELETE /venues/{id} - Delete venue (deleteVenue)
### Venue Layouts
- GET /venues/{id}/layouts - List layouts for venue (listVenueLayouts)
- POST /venues/{id}/layouts - Create venue layout (createVenueLayout)
- GET /venues/{id}/layouts/{layoutId} - Get venue layout (getVenueLayout)
- PATCH /venues/{id}/layouts/{layoutId} - Update venue layout (updateVenueLayout)
- DELETE /venues/{id}/layouts/{layoutId} - Delete venue layout (deleteVenueLayout)
### Venue Layout Areas
- POST /venues/{id}/layouts/{layoutId}/areas - Add area to venue layout (addAreaToVenueLayout)
- PATCH /venues/{id}/layouts/{layoutId}/areas/{areaId} - Update venue layout area (updateVenueLayoutArea)
- DELETE /venues/{id}/layouts/{layoutId}/areas/{areaId} - Delete venue layout area (deleteVenueLayoutArea)
### Venue Layout Categories
- POST /venues/{id}/layouts/{layoutId}/categories - Add category to venue layout (addCategoryToVenueLayout)
- PATCH /venues/{id}/layouts/{layoutId}/categories/{categoryId} - Update venue layout category (updateVenueLayoutCategory)
- DELETE /venues/{id}/layouts/{layoutId}/categories/{categoryId} - Delete venue layout category (deleteVenueLayoutCategory)
### Venue Layout Seats
- POST /venues/{id}/layouts/{layoutId}/areas/{areaId}/seats - Add seat to area (addSeatToArea)
- POST /venues/{id}/layouts/{layoutId}/areas/{areaId}/seats/bulk - Bulk add seats to area (bulkAddSeatsToArea)
- POST /venues/{id}/layouts/{layoutId}/areas/{areaId}/seats/generate - Generate seats for area (generateSeatsForArea)
- PUT /venues/{id}/layouts/{layoutId}/areas/{areaId}/seats/sync - Sync seats in area (syncSeatsInArea)
- PATCH /venues/{id}/layouts/{layoutId}/areas/{areaId}/seats/{seatId} - Update seat in area (updateSeatInArea)
- DELETE /venues/{id}/layouts/{layoutId}/areas/{areaId}/seats/{seatId} - Delete seat from area (deleteSeatFromArea)
### Billing
- GET /billing/packages - List credit packages (listCreditPackages)
- GET /organisations/{organisationId}/billing/can-sell - Check if organisation can sell (checkCanSell)
- GET /billing/balance - Get credit balance (getCreditBalance)
- GET /billing/transactions - List credit transactions (listCreditTransactions)
- POST /billing/purchases - Purchase credits (createCreditPurchase)
- GET /billing/invoices - List invoices (listInvoices)
- GET /billing/invoices/{invoiceId} - Get invoice (getInvoice)
- GET /billing/payments - List billing payments (listBillingPayments)
- POST /billing/subscriptions - Create subscription (createSubscription)
- GET /billing/subscriptions - List subscriptions (listSubscriptions)
- DELETE /billing/subscriptions/{subscriptionId} - Cancel subscription (cancelSubscription)
- GET /billing/auto-topup - Get auto top-up configuration (getAutoTopup)
- PUT /billing/auto-topup - Update auto top-up configuration (updateAutoTopup)
- GET /billing/payment-methods - List payment methods (listPaymentMethods)
- POST /billing/payment-methods - Save payment method (savePaymentMethod)
- POST /billing/setup-intent - Create setup intent (createSetupIntent)
- DELETE /billing/payment-methods/{paymentMethodId} - Delete payment method (deletePaymentMethod)
- PUT /billing/payment-methods/{paymentMethodId}/default - Set default payment method (setDefaultPaymentMethod)
- GET /billing/ai/packages - List AI credit packages (listAiCreditPackages)
- GET /billing/ai/balance - Get AI credit balance (getAiBalance)
- GET /billing/ai/transactions - List AI credit transactions (listAiCreditTransactions)
- POST /billing/ai-topup - Top up AI credits (createAiTopup)
### Inventory
- POST /inventory - Create inventory (createInventory)
- GET /inventory - List inventory (listInventory)
- GET /inventory/{id} - Get inventory (getInventory)
- DELETE /inventory/{id} - Delete inventory (deleteInventory)
- PATCH /inventory/{id}/capacity - Update inventory capacity (updateInventoryCapacity)
- GET /inventory/{id}/audit-log - Get inventory audit log (getInventoryAuditLog)
### Inventory Seats
- POST /inventory/{id}/seats - Bulk import seats (bulkImportSeats)
- GET /inventory/{id}/seats - List inventory seats (listInventorySeats)
### Inventory Reservations
- POST /inventory/reserve - Reserve inventory (reserveInventory)
- POST /inventory/check-availability - Check availability (checkAvailability)
- GET /inventory/reservations - List reservations (listReservations)
- GET /inventory/reservations/{id} - Get reservation (getReservation)
- POST /inventory/reservations/{id}/confirm - Confirm reservation (confirmReservation)
- POST /inventory/reservations/{id}/release - Release reservation (releaseReservation)
- PATCH /inventory/reservations/{id}/extend - Extend reservation (extendReservation)
### Inventory Holds
- POST /inventory/holds - Create hold (createHold)
- POST /inventory/holds/{id}/release - Release hold (releaseHold)
### Customers
- POST /customers - Create customer (createCustomer)
- GET /customers - List customers (listCustomers)
- GET /customers/{customerId} - Get customer (getCustomer)
- PATCH /customers/{customerId} - Update customer (updateCustomer)
- POST /customers/{customerId}/block - Block customer (blockCustomer)
- POST /customers/{customerId}/unblock - Unblock customer (unblockCustomer)
### Orders
- POST /orders - Create order (createOrder)
- GET /orders - List orders (listOrders)
- GET /orders/{orderId} - Get order (getOrder)
- PATCH /orders/{orderId} - Update order (updateOrder)
- GET /orders/number/{orderNumber} - Get order by number (getOrderByNumber)
- POST /orders/{orderId}/cancel - Cancel order (cancelOrder)
- POST /orders/{orderId}/status - Transition order status (transitionOrderStatus)
- POST /orders/{orderId}/validate - Validate order (validateOrder)
- POST /orders/{orderId}/items - Add line item (addOrderLineItem)
- PATCH /orders/{orderId}/items/{itemId} - Update line item (updateOrderLineItem)
- DELETE /orders/{orderId}/items/{itemId} - Remove line item (removeOrderLineItem)
- POST /orders/{orderId}/payment - Initiate payment (initiateOrderPayment)
- GET /orders/{orderId}/payment/status - Get payment status (getOrderPaymentStatus)
- GET /orders/{orderId}/passes/{passId}/ticket.pdf - Download a pass as a PDF ticket (getOrderPassPdf)
- POST /orders/{orderId}/resend-confirmation - Resend order confirmation email (resendOrderConfirmation)
- GET /orders/{orderId}/passes - Get order passes (getOrderPasses)
- POST /orders/{orderId}/passes/{passId}/print - Print a pass to a device (printPass)
### Payments
- POST /payments - Create payment (createPayment)
- GET /payments - List payments (listPayments)
- GET /payments/{paymentId} - Get payment (getPayment)
- POST /payments/{paymentId}/cancel - Cancel payment (cancelPayment)
- POST /payments/{paymentId}/refunds - Create refund (createPaymentRefund)
- GET /payments/{paymentId}/refunds - List refunds (listPaymentRefunds)
### Payment Providers
- POST /payment-providers - Create payment provider (createPaymentProvider)
- GET /payment-providers - List payment providers (listPaymentProviders)
- GET /payment-providers/default - Get default payment provider (getDefaultPaymentProvider)
- GET /payment-providers/{providerId} - Get payment provider (getPaymentProvider)
- PATCH /payment-providers/{providerId} - Update payment provider (updatePaymentProvider)
- DELETE /payment-providers/{providerId} - Delete payment provider (deletePaymentProvider)
- POST /payment-providers/ticketlayer-pay/enable - Enable Ticketlayer Pay (enableTicketlayerPay)
- GET /payment-providers/ticketlayer-pay - Ticketlayer Pay status (getTicketlayerPay)
- POST /payment-providers/ticketlayer-pay/onboarding-session - Account Session for embedded Ticketlayer Pay onboarding (createTicketlayerPayOnboardingSession)
- POST /payment-providers/ticketlayer-pay/onboarding-link - Hosted onboarding link for Ticketlayer Pay (createTicketlayerPayOnboardingLink)
- POST /payment-providers/stripe-connect - Link the organisation's own Stripe account (linkStripeConnect)
- GET /payment-providers/stripe-connect - The organisation's Stripe Connect provider (getStripeConnect)
- GET /payment-providers/{providerId}/accounts - Per-Account routing rows on a Stripe Connect provider (listPaymentProviderAccounts)
- GET /payment-providers/{providerId}/accounts/{accountId} - One Account's routing on a Stripe Connect provider (getPaymentProviderAccount)
- PUT /payment-providers/{providerId}/accounts/{accountId} - Set how an Account charges through a Stripe Connect provider (setPaymentProviderAccountMode)
- POST /payment-providers/{providerId}/accounts/{accountId}/onboarding-session - Account Session for embedded onboarding of an Account's connected account (createPaymentProviderAccountOnboardingSession)
- POST /payment-providers/{providerId}/accounts/{accountId}/onboarding-link - Hosted onboarding link for an Account's connected account (createPaymentProviderAccountOnboardingLink)
### Sales Channels
- POST /sales-channels - Create sales channel (createSalesChannel)
- GET /sales-channels - List sales channels (listSalesChannels)
- GET /sales-channels/{channelId} - Get sales channel (getSalesChannel)
- PATCH /sales-channels/{channelId} - Update sales channel (updateSalesChannel)
- DELETE /sales-channels/{channelId} - Delete sales channel (deleteSalesChannel)
### Keys
- POST /sales-channels/{channelId}/keys - Issue channel key (issueSalesChannelKey)
- GET /sales-channels/{channelId}/keys - List channel keys (listSalesChannelKeys)
- POST /sales-channels/{channelId}/keys/{keyId}/revoke - Revoke channel key (revokeSalesChannelKey)
### Listings
- POST /sales-channels/{channelId}/listings - List event on channel (createSalesChannelListing)
- GET /sales-channels/{channelId}/listings - List channel listings (listSalesChannelListings)
- DELETE /sales-channels/{channelId}/listings/{listingId} - Remove channel listing (deleteSalesChannelListing)
### Carts
- POST /sales-channels/{channelId}/carts - Create staff cart (createStaffCart)
- GET /sales-channels/{channelId}/carts/{cartId} - Get staff cart (getStaffCart)
- POST /sales-channels/{channelId}/carts/{cartId}/items - Add staff cart item (addStaffCartItem)
- DELETE /sales-channels/{channelId}/carts/{cartId}/items/{itemId} - Remove staff cart item (removeStaffCartItem)
- POST /sales-channels/{channelId}/carts/{cartId}/checkout - Checkout staff cart (checkoutStaffCart)
### Presale Codes
- POST /presale-codes - Create presale code (createPresaleCode)
- GET /presale-codes - List presale codes (listPresaleCodes)
- POST /presale-codes/{codeId}/deactivate - Deactivate presale code (deactivatePresaleCode)
### Fee Profiles
- POST /fee-profiles - Create fee profile (createFeeProfile)
- GET /fee-profiles - List fee profiles (listFeeProfiles)
- GET /fee-profiles/{profileId} - Get fee profile (getFeeProfile)
- PATCH /fee-profiles/{profileId} - Update fee profile (updateFeeProfile)
- DELETE /fee-profiles/{profileId} - Delete fee profile (deleteFeeProfile)
### Sales Listings
- GET /sales/listings - List active listings (listSalesListings)
### Sales Customer Auth
- POST /sales/customer-auth/magic-link - Request magic link (requestSalesMagicLink)
### Sales Customer Tokens
- POST /sales/customer-tokens - Exchange identity proof for customer token (createSalesCustomerToken)
- POST /sales/customer-tokens/refresh - Refresh a customer token (refreshSalesCustomerToken)
### Sales Carts
- POST /sales/carts - Create cart (createSalesCart)
- GET /sales/carts/{cartId} - Get cart (getSalesCart)
- POST /sales/carts/{cartId}/items - Add cart item (addSalesCartItem)
- DELETE /sales/carts/{cartId}/items/{itemId} - Remove cart item (removeSalesCartItem)
- POST /sales/carts/{cartId}/checkout - Checkout cart (checkoutSalesCart)
### Sales My Orders
- GET /sales/my-orders - List my orders (listMySalesOrders)
### Sales Orders
- GET /sales/orders/{orderId} - Get order (getSalesOrder)
- GET /sales/orders/{orderId}/passes/{passId}/ticket.pdf - Download a ticket PDF (getSalesOrderTicketPdf)
### Sales Order Payments
- POST /sales/orders/{orderId}/payments - Create order payment (createSalesOrderPayment)
### Sales Refund Requests
- POST /sales/orders/{orderId}/refund-requests - Request refund or exchange (createSalesOrderRefundRequest)
### Sales Customers
- POST /sales/customers - Create customer (createSalesCustomer)
- GET /sales/customers/{customerId} - Get customer (getSalesCustomer)
- PATCH /sales/customers/{customerId} - Update customer (updateSalesCustomer)
### Sales Presale Codes
- POST /sales/presale-codes/redeem - Redeem presale code (redeemSalesPresaleCode)
### Sales
- GET /sales/channel - Resolve a channel by domain (resolveSalesChannel)
- GET /sales/events/{eventId} - Get event catalogue detail (getSalesEvent)
- GET /sales/theme - Get channel theme (getSalesTheme)
### Themes
- GET /themes - List themes (listThemes)
- POST /themes - Create theme (createTheme)
- GET /themes/{id} - Get theme (getTheme)
- PATCH /themes/{id} - Update theme (updateTheme)
- DELETE /themes/{id} - Delete theme (deleteTheme)
- GET /themes/{id}/resolved - Get resolved theme (getResolvedTheme)
### Entitlements
- POST /passes/{barcode}/redeem - Redeem a pass (redeemPass)
### Ticket Templates
- GET /ticket-templates - List ticket templates (listTicketTemplates)
- POST /ticket-templates - Create ticket template (createTicketTemplate)
- GET /ticket-templates/{id} - Get ticket template (getTicketTemplate)
- PATCH /ticket-templates/{id} - Update ticket template (updateTicketTemplate)
- DELETE /ticket-templates/{id} - Delete ticket template (deleteTicketTemplate)
### Scan Configs
- POST /scan-configs - Create a scan configuration (createScanConfig)
- GET /scan-configs - List scan configurations (listScanConfigs)
- GET /scan-configs/{configId} - Get a scan configuration (getScanConfig)
- PATCH /scan-configs/{configId} - Update a scan configuration (updateScanConfig)
- DELETE /scan-configs/{configId} - Delete a scan configuration (deleteScanConfig)
- PUT /scan-configs/{configId}/devices - Assign scanner devices to a configuration (setScanConfigDevices)
### Scan
- GET /scan/config - Get the device scan scope (getScanConfigForDevice)
- GET /scan/manifest - Get the offline validation dataset (getScanManifest)
- POST /scan/operations - Submit scan operations (submitScanOperations)
### Scans
- GET /scans - List scans (staff reporting) (listScans)
- POST /redemptions/{redemptionId}/reverse - Reverse a redemption (reverseRedemption)
### Assets
- GET /assets - List assets (listAssets)
- POST /assets - Upload an asset (uploadAsset)
- GET /assets/{id} - Get an asset (getAsset)
- DELETE /assets/{id} - Delete an asset (deleteAsset)
### Device Pairing
- POST /devices/pairing - Start device pairing (startDevicePairing)
- GET /devices/pairing/{pairingId} - Poll device pairing status (getDevicePairing)
- POST /devices/pairing/claim - Claim a device pairing (claimDevicePairing)
- POST /devices/pairing/{pairingId}/confirm - Confirm device adoption (confirmDevicePairing)
- POST /devices/pairing/{pairingId}/reject - Reject device adoption (rejectDevicePairing)
### Device Auth
- POST /devices/token - Mint a device token (issueDeviceToken)
- GET /devices/jwks - Device JWKS (getDeviceJwks)
### Device Self
- GET /devices/me - Get own device record (getDeviceMe)
- POST /devices/me/heartbeat - Send a device heartbeat (deviceHeartbeat)
- PUT /devices/me/peripherals - Declare peripherals (declareDevicePeripherals)
- GET /devices/me/commands - Long-poll for commands (fetchDeviceCommands)
- POST /devices/me/commands/{commandId}/progress - Report command progress (reportCommandProgress)
- POST /devices/me/commands/{commandId}/result - Report command result (reportCommandResult)
- POST /devices/me/events - Upload device events (ingestDeviceEvents)
- GET /devices/me/certificate - Get local TLS certificate (getDeviceCertificate)
### Devices
- GET /devices/printers - List printers (listPrinters)
- GET /devices/media-catalog - Print capability & standard-media catalog (getDeviceMediaCatalog)
- GET /devices - List devices (listDevices)
- GET /devices/{deviceId} - Get device (getDevice)
- PATCH /devices/{deviceId} - Update device (updateDevice)
- DELETE /devices/{deviceId} - Delete device (deleteDevice)
- POST /devices/{deviceId}/revoke - Revoke device (revokeDevice)
- PUT /devices/{deviceId}/roles - Assign device roles (assignDeviceRoles)
- POST /devices/{deviceId}/credentials/rotate - Rotate device credential (rotateDeviceCredential)
- POST /devices/{deviceId}/commands - Dispatch a command (dispatchDeviceCommand)
- GET /devices/{deviceId}/commands - List device commands (listDeviceCommands)
- GET /devices/commands/{commandId} - Get a command (getDeviceCommand)
- GET /devices/{deviceId}/events - List device events (listDeviceEvents)
- POST /devices/{deviceId}/local-tokens - Mint a Local Command Token (mintLocalToken)
### Locations
- POST /locations - Create location (createLocation)
- GET /locations - List locations (listLocations)
- GET /locations/{locationId} - Get location (getLocation)
- PATCH /locations/{locationId} - Update location (updateLocation)
- DELETE /locations/{locationId} - Delete location (deleteLocation)
### Reports
- GET /reports/summary - Sales summary KPIs (getReportsSummary)
- GET /reports/timeseries - Sales over time (getReportsTimeseries)
- GET /reports/inventory - Inventory sell-through (getReportsInventory)
- GET /reports/meta - Semantic model (getReportsMeta)
- POST /reports/query - Run an ad-hoc query (runReportsQuery)
- GET /reports/saved - List saved reports (listSavedReports)
- POST /reports/saved - Create a saved report (createSavedReport)
- GET /reports/saved/{id} - Get a saved report (getSavedReport)
- PATCH /reports/saved/{id} - Update a saved report (updateSavedReport)
- DELETE /reports/saved/{id} - Delete a saved report (deleteSavedReport)
- POST /reports/saved/{id}/run - Run a saved report (runSavedReport)
- GET /reports/dashboards - List dashboards (listDashboards)
- POST /reports/dashboards - Create a dashboard (createDashboard)
- GET /reports/dashboards/{id} - Get a dashboard (getDashboard)
- PATCH /reports/dashboards/{id} - Update a dashboard (updateDashboard)
- DELETE /reports/dashboards/{id} - Delete a dashboard (deleteDashboard)
- GET /reports/templates - List standard templates (listReportTemplates)
- POST /reports/templates/{key}/install - Install a template (installReportTemplate)
### Webhook Endpoints
- POST /webhook-endpoints - Create a webhook endpoint (createWebhookEndpoint)
- GET /webhook-endpoints - List webhook endpoints (listWebhookEndpoints)
- GET /webhook-endpoints/{endpointId} - Get a webhook endpoint (getWebhookEndpoint)
- PATCH /webhook-endpoints/{endpointId} - Update a webhook endpoint (updateWebhookEndpoint)
- DELETE /webhook-endpoints/{endpointId} - Delete a webhook endpoint (deleteWebhookEndpoint)
- POST /webhook-endpoints/{endpointId}/test - Send a test delivery (testWebhookEndpoint)
### Webhook Event Types
- GET /webhook-event-types - List subscribable webhook event types (listWebhookEventTypes)
### Webhook Deliveries
- GET /webhook-inbound - List recent inbound webhook events (ingress log) (listInboundWebhooks)
- GET /webhook-deliveries - List webhook deliveries (listWebhookDeliveries)
- GET /webhook-deliveries/{deliveryId} - Get a webhook delivery (getWebhookDelivery)
### Integrations
- GET /integrations - List the integration marketplace (listIntegrations)
- GET /integrations/connected-apps - List connected OAuth apps for the org (listConnectedApps)
- GET /integrations/{id} - Get an integration (getIntegration)
- DELETE /integrations/{id}/connection - Revoke a connected app (revokeIntegrationConnection)
## Live API
Base URL: https://live.ticketlayer.com (staging: https://live.staging.t9r.dev). OpenAPI document: https://docs.ticketlayer.com/openapi/live.json. Reference pages: https://docs.ticketlayer.com/api/live/.
### Session
- POST /session - Bootstrap a Live session (createLiveSession)
- GET /session - Get the current session (getLiveSession)
- DELETE /session - Destroy the current session (deleteLiveSession)
- POST /session/order-access - Attach an order access token to the session (attachLiveOrderAccess)
### Queue
- GET /queue/status - Get waiting-room status (getLiveQueueStatus)
- POST /queue/join - Join the waiting room (joinLiveQueue)
### Sales Listings
- GET /sales/listings - List active listings (listSalesListings)
### Sales Customer Auth
- POST /sales/customer-auth/magic-link - Request magic link (requestSalesMagicLink)
### Sales Customer Tokens
- POST /sales/customer-tokens - Exchange identity proof for customer token (createSalesCustomerToken)
- POST /sales/customer-tokens/refresh - Refresh a customer token (refreshSalesCustomerToken)
### Sales Carts
- POST /sales/carts - Create cart (createSalesCart)
- GET /sales/carts/{cartId} - Get cart (getSalesCart)
- POST /sales/carts/{cartId}/items - Add cart item (addSalesCartItem)
- DELETE /sales/carts/{cartId}/items/{itemId} - Remove cart item (removeSalesCartItem)
- POST /sales/carts/{cartId}/checkout - Checkout cart (checkoutSalesCart)
### Sales My Orders
- GET /sales/my-orders - List my orders (listMySalesOrders)
### Sales Orders
- GET /sales/orders/{orderId} - Get order (getSalesOrder)
- GET /sales/orders/{orderId}/passes/{passId}/ticket.pdf - Download a ticket PDF (getSalesOrderTicketPdf)
### Sales Order Payments
- POST /sales/orders/{orderId}/payments - Create order payment (createSalesOrderPayment)
### Sales Refund Requests
- POST /sales/orders/{orderId}/refund-requests - Request refund or exchange (createSalesOrderRefundRequest)
### Sales Customers
- POST /sales/customers - Create customer (createSalesCustomer)
- GET /sales/customers/{customerId} - Get customer (getSalesCustomer)
- PATCH /sales/customers/{customerId} - Update customer (updateSalesCustomer)
### Sales Presale Codes
- POST /sales/presale-codes/redeem - Redeem presale code (redeemSalesPresaleCode)
### Sales
- GET /sales/channel - Resolve a channel by domain (resolveSalesChannel)
- GET /sales/events/{eventId} - Get event catalogue detail (getSalesEvent)
- GET /sales/theme - Get channel theme (getSalesTheme)