The Performance Groups API coordinates assigned-seat inventory for a fixed run of two to eight compatible Events. Your existing checkout stays in control: you decide the package and price, take payment, create the order, and issue tickets. Use Performance Groups for one fixed multi-date purchase, not a recurring subscription or flexible season membership.
Every route on this page uses a matching sk_test_… or sk_live_… secret key.
Keep that key on your server. Browser access uses the short-lived group token
minted below and is consumed only by PerformanceGroupPicker.
Choose REST or a server SDK
The REST examples on this page are the canonical wire contract. Each official server SDK exposes the same trusted workflow through one resource; choose the package that matches your backend. Before adopting a package release, check the operation support matrix: Live means the published package was verified, while RC means the matching source has passed its release checks but a public package has not yet been verified.
| Backend | Resource |
|---|---|
| Node.js | seatlayer.performanceGroups |
| Python | seatlayer.performance_groups |
| PHP | $seatlayer->performanceGroups |
| Java | seatlayer.performanceGroups() |
| Go | client.PerformanceGroups |
| Ruby | client.performance_groups |
| .NET | client.PerformanceGroups |
The resource creates and manages the group, mints the buyer token, reads the
trusted hold, and confirms the booking. It never gives a server SDK access to
the browser-only /pub/performance-groups/* routes.
API map
| Task | Method and route |
|---|---|
| List or filter groups | GET /v1/performance-groups |
| Create a fixed run | POST /v1/performance-groups |
| Read one run | GET /v1/performance-groups/:groupKey |
| Discard an unused draft | DELETE /v1/performance-groups/:groupKey |
| Activate / close it | POST /:groupKey/activate · POST /:groupKey/close |
| Recover lifecycle progress | GET /:groupKey/lifecycle/:operationId |
| Mint / list / revoke browser sessions | /buyer-access-sessions |
| Inspect the opaque group hold | GET /:groupKey/holds/:operationId |
| Commit inventory and recover booking | POST /holds/:operationId/book · GET /bookings/:bookActionId |
The browser-only descriptor, chart, availability, hold, release, extension, and
operation routes are SDK implementation details. Use PerformanceGroupPicker;
do not call /pub/performance-groups/* from your application.
To list groups, use workspaceId, externalRef, state, limit, and
cursor as needed. DELETE succeeds only for a draft; once a group is active,
close it and let existing operations drain instead of trying to replace its dates.
Create a fixed run
POST /v1/performance-groups HTTP/1.1
Authorization: Bearer sk_test_••••••••
Idempotency-Key: production-opening-weekend
Content-Type: application/json
{
"name": "Opening weekend",
"externalRef": "run_2026_opening_weekend",
"eventKeys": ["ev_friday", "ev_saturday", "ev_sunday"]
}name is required and limited to 120 characters. externalRef is optional,
stable within the organization, and limited to 128 characters. eventKeys must
contain two to eight distinct compatible Events.
The server validates organization, workspace, mode, chart snapshot, inventory
model, venue, timezone, currency, sale ownership, start times, and assigned-seat
compatibility before it creates a draft group. 201 returns
{ performanceGroup }, including chronological performances and revision.
Use the same idempotency key when retrying a lost create response. 409 can
mean an Event already belongs to another group or the external reference is
already in use.
Every compatibility refusal answers error: "incompatible_performances" and
names the specific reason in code — currency_mismatch, chart_mismatch,
invalid_event_count, and so on. It is the one create failure in this API
where the two fields differ, so branch on error to recognise the umbrella and
read code for what to correct. The status follows the reason: 404 when a
performance is unknown, 422 for a malformed set, 409 for a field the
performances cannot safely share. Refusals raised by the route itself
(invalid_name, module_not_enabled, external_ref_exists) keep the usual
error === code shape.
Activate and close
POST /v1/performance-groups/pg_opening_weekend/activate
Authorization: Bearer sk_test_••••••••
Content-Type: application/json
{ "expectedRevision": 1 }Activation revalidates compatibility and locks the member Events against unsafe
chart or lifecycle changes. A final response contains the active group. A
recoverable 202 includes Location, Retry-After, the current group, and a
lifecycleOperation; poll that location until it is terminal.
Close uses the same body and recovery behavior:
POST /v1/performance-groups/pg_opening_weekend/close
Authorization: Bearer sk_test_••••••••
Content-Type: application/json
{ "expectedRevision": 2 }Closing stops new group holds, lets accepted holds finish or expire, then releases the member locks only after drain proof. There is no reopen. Do not use close as a shortcut to change the dates in a buyer’s existing offer.
Mint browser access
POST /v1/performance-groups/pg_opening_weekend/buyer-access-sessions
Authorization: Bearer sk_test_••••••••
Content-Type: application/json
{
"allowedOrigin": "https://tickets.example.com",
"includePublic": true,
"expiresInSeconds": 1800,
"maxQuantity": 4,
"buyerRef": "buyer_8372"
}allowedOrigin and includePublic are required. The token applies to the
whole active group and is checked on every browser request. expiresInSeconds
is 60 to 43,200; maxQuantity is one to 100 or omitted; buyer and partner
references are opaque values up to 120 characters.
For private sales, pass channelIdsByEvent with an array for each member Event:
{
"allowedOrigin": "https://members.example.com",
"includePublic": false,
"channelIdsByEvent": {
"ev_friday": ["chn_members"],
"ev_saturday": ["chn_members"],
"ev_sunday": ["chn_members"]
}
}The 201 response reveals token only once, alongside sessionId, expiresAt,
and performanceGroupKey. Store the session ID for audit/revocation, return
only token and expiry to the browser, and never automatically retry a response
whose token delivery is uncertain.
Use GET /v1/performance-groups/:groupKey/buyer-access-sessions?limit=50 to
list non-secret session metadata and
DELETE /v1/performance-groups/:groupKey/buyer-access-sessions/:sessionId to
revoke a session immediately.
Inspect the group hold
The browser handoff supplies operationId and holdId. The server-inspection
route is addressed by the operation identity:
GET /v1/performance-groups/pg_opening_weekend/holds/pghop_01J8…
Authorization: Bearer sk_test_••••••••The response contains { hold } with one group hold identity, its common expiry,
selection mode, group revision, currency, and chronological allocations. Each
allocation includes its Event key/name/time and authoritative inventory line
items. Child hold IDs never appear.
Inspect immediately before your payment decision. 404 means the group,
operation, or hold is not available to this tenant/mode; 409 performance_group_integrity_error is a support escalation, not a reason to
charge or retry with altered IDs.
Book one group hold
POST /v1/performance-groups/pg_opening_weekend/holds/pghop_01J8…/book
Authorization: Bearer sk_test_••••••••
Content-Type: application/json
{
"bookActionId": "pg-book:order_1842",
"bookingRef": "order_1842"
}bookActionId and bookingRef are both required stable identifiers. Reuse the
same pair for every retry of this commercial order. 200 with booking.state: "booked" is final. 202 with booking.state: "book_pending" includes a
Location and Retry-After; poll
GET /v1/performance-groups/:groupKey/bookings/:bookActionId until terminal.
409 book_failed is terminal and may require payment compensation or support
because a child performance can already have settled. Do not create a new action
ID to force another booking attempt.
Error and recovery rules
| Situation | Correct response |
|---|---|
403 module_not_enabled |
Performance Groups is not enabled for this account. Do not fall back to separate Event holds. |
403 buyer_access_mode_mismatch |
Use a test key for a test group and a live key for a live group. |
404 not_found |
Treat as unknown/cross-tenant/mode-mismatched; never reveal more detail to a buyer. |
409 lifecycle pending or revision conflict |
Reload the group and follow the existing lifecycle operation; do not overwrite a revision. |
incompatible_performances (404/409/422) |
Read code for the reason and correct the Event setup before creating a new group. |
202 lifecycle or booking |
Poll the supplied Location using Retry-After. |
| Lost browser hold response | Let PerformanceGroupPicker recover the same operation. |
| Lost server booking response | Retry only with the same bookActionId and bookingRef. |
Next: end-to-end integration and Performance Group picker.