Skip to main content

Backstage SDK

@ticketlayer/backstage is the TypeScript client for the Backstage API, generated from its OpenAPI document. It is the one Ticketlayer package on npm today.

Installation

npm install @ticketlayer/backstage
# or
pnpm add @ticketlayer/backstage

The package was previously published as @ticketlayer/backstage-sdk; that name is no longer updated.

Quick start

Server-side, with an organisation API key (see Keys and authentication):

import { BackstageClient } from '@ticketlayer/backstage';

const client = new BackstageClient({
baseUrl: 'https://api.staging.t9r.dev',
accessToken: process.env.TICKETLAYER_API_KEY, // tlak_...
organisationSlug: 'your-org-slug',
});

const { events, pagination } = await client.events.list({ limit: '20' });
const event = await client.events.create({ accountId: 'acc_...', name: 'Jazz Night', status: 'draft' });

In a staff application, pass the Stagedoor access token instead of the API key. The client sends Authorization: Bearer ... and X-Ticketlayer-Org on every request and refreshes an expired staff token when given a refresh token and onTokenRefresh.

What the client does

  • Response unwrapping. The API answers in JSend ({ status: 'success', data: {...} }); methods return data directly.
  • Method grouping by resource: client.events.*, client.orders.*, client.salesChannels.*, client.webhookEndpoints.*, client.embed.createSession(...) and so on, one method per operation in the reference. Nested resources hang off the parent: client.events(eventId).occurrences.list().
  • Typed errors. Failures throw BackstageAPIError with statusCode, code and message.
  • Dated version. Every request carries TL-Version set to the version the package was generated against (API_DATED_VERSION), so a release of the API never changes the shapes your code compiled against.
import { BackstageAPIError } from '@ticketlayer/backstage';

try {
await client.events.get('evt_missing');
} catch (err) {
if (err instanceof BackstageAPIError && err.statusCode === 404) {
// not found, or not visible to this credential (the API never says which)
}
}

Embedding Backstage widgets

@ticketlayer/backstage/embed mounts Backstage widgets (the events list, an event editor, the orders list, an order) in an iframe on your own page. Your server mints an embed session for one account with the organisation API key, and the widget runs as that account with the scopes you chose:

// Server
const { token, expiresAt } = await client.embed.createSession({
accountId: 'acc_...',
scopes: ['events.read', 'events.write', 'orders.read'],
});
// Page
import { createBackstageEmbed } from '@ticketlayer/backstage/embed';

const embed = createBackstageEmbed({
baseUrl: 'https://backstage.staging.t9r.dev',
session: token,
sessionProvider: async () => (await fetch('/api/ticketing/session').then((r) => r.json())).token,
});
embed.mount(document.getElementById('ticketing')!, { widget: 'events' });

Widgets: events, event ({ id, tab? }), orders, order ({ id }). The Backstage deployment must list your origin in its allowed frame ancestors for the frame to load.

Next steps