Overview of Ticketlayer Ticketing Platform
TL-Version header; additive changes do not increment this version.website·Indexed 31 days ago
https://docs.ticketlayer.comA ticketing platform that allows developers to sell tickets on any website using a drop-in script tag or npm packages. Features include the Live SDK, Ticketlayer Elements for custom HTML tags, a Backstage API for server-side management, webhooks for order notifications, and a remote MCP server for AI agent integration.
TL-Version header; additive changes do not increment this version.Ticketlayer sends signed JSON envelopes to registered URLs when specific events occur within an organization. You can retrieve the full list of event types and descriptions via GET /v1/webhook-event-types.
| Event Type | Trigger Condition | Payload Type |
|---|---|---|
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 |
Ticketlayer provides a remote MCP (Model Context Protocol) server that allows AI agents to read catalogues, orders, customers, and analytics, and (with permission) create or update events. The agent operates using the user's own credentials and RBAC permissions.
Server Details:
https://mcp.staging.t9r.dev/mcp (Staging)mcpImportant Connectivity Note: The authorization server (Stagedoor) is currently only accessible from the Ticketlayer team tailnet. Users outside this network will be unable to complete the browser-based login/consent flow.
The purchase process follows these steps:
checkout:completed event. The merchant can then display <tl-order-confirmation> (via ?orderId= in URL) or <tl-order-tickets>.order.confirmed, ticket.issued).The Backstage API uses dated versions (e.g., 2026-06-13). Within a specific version, changes are strictly additive (new endpoints, optional parameters, or response fields); existing behavior remains unchanged. Breaking changes are only introduced in new dated versions.
Key versioning rules:
Deprecation and Sunset headers.Ticketlayer provides different credentials depending on where your code is executing and what it needs to access:
tlpk_): Used in browsers, mobile apps, and site builders. Used for reading sales channel data, creating carts, and starting checkouts via the Live API.tlak_): Used on your server. Used for administrative tasks on the Backstage API (events, orders, customers, webhooks, embed sessions) based on assigned scopes.tlsk_): Server-only siblings of publishable keys. Used by a backend to interact with the sales surface on a customer's behalf. These must never be exposed to a browser..env file to provide the API URL, checkout base URL, and your public publishable key.npm create vite@latest my-tickets -- --template react-ts
cd my-tickets
npm install @ticketlayer/live @ticketlayer/elements @ticketlayer/elements-reactVITE_LIVE_API_URL=https://live.staging.t9r.dev
VITE_CHECKOUT_BASE=https://hbo.staging.t9r.dev
VITE_TL_PUBLISHABLE_KEY=tlpk_...defineCustomElements() once after hydration and initialize the Live client using createLiveClient. Elements are available as React components via the @ticketlayer/elements-react package.npm install @ticketlayer/live @ticketlayer/elements @ticketlayer/elements-reactimport { 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_...' });
<TlEventList columns={3} onTlEventClick={(e) => console.log(e.detail.eventId)} />To sell tickets, you must first create an event in the Backstage admin area. An event requires at least one occurrence (date and time) and a price scheme (ticket types and prices). Once configured, the event must be set to 'on sale'.
For automation, use the following API endpoints:
POST /v1/eventsPOST /v1/events/{eventId}/occurrencesPOST /v1/events/{eventId}/price-schemesTo ensure a request comes from Ticketlayer, verify the Ticketlayer-Signature header using the signing secret provided during endpoint registration.
Verification Logic:
"<t>.<raw body>" (where <t> is the timestamp from the header), hex encoded.t is more than five minutes (300 seconds) from the current time.Implementation Example (Node.js/Express):
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);
}
// Express usage
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') {
// handle order.confirmed
}
res.sendStatus(204);
});npm install @ticketlayer/live @ticketlayer/elements @ticketlayer/elements-reactmain.tsx). Use createLiveClient to configure the connection and set up event listeners for checkout completion.import React from 'react';
import ReactDOM from 'react-dom/client';
import { createLiveClient } from '@ticketlayer/live';
import { defineCustomElements } from '@ticketlayer/elements-react';
import App from './App';
defineCustomElements();
createLiveClient({
baseUrl: import.meta.env.VITE_LIVE_API_URL,
publishableKey: import.meta.env.VITE_TL_PUBLISHABLE_KEY,
checkout: { mode: 'modal', embedBaseUrl: import.meta.env.VITE_CHECKOUT_BASE },
}).then((tl) => {
tl.on('checkout:completed', (order: { id: string }) => {
window.location.href = `/thanks?orderId=${encodeURIComponent(order.id)}`;
});
});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);