Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
[![Python](https://img.shields.io/pypi/pyversions/seatlayer.svg)](https://pypi.org/project/seatlayer/)
[![License: MIT](https://img.shields.io/badge/license-MIT-111827.svg)](LICENSE)

The official SeatLayer Python server SDK the trusted side of a reserved-seating
integration. Inspect what a hold really contains, price from server-owned seating-chart
data, and book with a stable `booking_ref`, while managing charts, events, inventory,
allocations, and webhooks through one typed ticketing API client.
SeatLayer's official Python server SDK is the trusted side of its reserved seating and seat
booking API. Inspect what a hold really contains, price from server-owned seating-chart data,
and book with a stable `booking_ref`, while managing charts, events, inventory, allocations,
and webhooks through one typed ticketing API client.

[`seatlayer` on PyPI](https://pypi.org/project/seatlayer/) ·
[SeatLayer server SDK documentation](https://docs.seatlayer.io/server-sdk/install/) ·
[Python server SDK guide](https://docs.seatlayer.io/server-sdk/python/) ·
[SeatLayer SDK and API overview](https://seatlayer.io/developers/) ·
[SeatLayer JavaScript seat map SDK](https://www.npmjs.com/package/@seatlayer/js) ·
[Server API reference](https://docs.seatlayer.io/server-api/events/)

> **Server-side only.** This package authenticates with your secret key. Never run it anywhere a
> ticket buyer can reach — browser surfaces get short-lived, origin-bound tokens that you mint here.

## Install
## Install the Python seat booking SDK

```bash
pip install seatlayer
Expand All @@ -36,7 +36,8 @@ from seatlayer import SeatLayer
seatlayer = SeatLayer(os.environ["SEATLAYER_SECRET_KEY"])

# 1. Provision a venue from the public template catalog as a new draft chart.
chart = seatlayer.templates.instantiate_template("tpl_arena")["meta"]
# Replace this placeholder with a template id from your catalog.
chart = seatlayer.templates.instantiate_template("your-published-template")["meta"]
seatlayer.charts.publish(chart["id"])

# 2. Create an event on it.
Expand Down Expand Up @@ -91,15 +92,19 @@ if os.environ.get("ENV") == "production" and seatlayer.mode != "live":
raise RuntimeError("Refusing to boot production against test-mode seating data.")
```

## The two selling flows
## Book reserved seats from Python

**Buyer picks seats in the browser.** Your frontend holds them; your backend confirms the price and
books. Never price from what the browser sent you — `retrieve_hold` is authoritative.

```python
hold = seatlayer.inventory.retrieve_hold(event_key, hold_id)
total = sum(item["unitPrice"] for item in hold["items"])
# … charge `total` in hold["currency"] …
currencies = {item["currency"] for item in hold["items"]}
if len(currencies) != 1:
raise ValueError("A hold must use one currency")
currency = currencies.pop()
total = sum(item["unitPrice"] * item.get("quantity", 1) for item in hold["items"])
# … charge `total` in `currency` …
seatlayer.inventory.book(event_key, hold_id=hold_id, booking_ref=charge.id)
```

Expand Down Expand Up @@ -197,12 +202,12 @@ The full set, all opt-in:
|---|---|
| `event:view` | Read the seat map and its live states |
| `event:block` | Block and unblock seats |
| `event:cancel` | Unbook paid seats and issue gateway refunds — destructive, moves money |
| `event:cancel` | Cancel a Platform/SDK booking by reference and return its inventory to sale; does not move gateway money |
| `event:reports` | Read sales and availability reports |
| `event:channels:view` | Read sales channels and their allocations |
| `event:channels:manage` | Create, pause and archive channels; rotate access links |
| `event:orders:read` | Read SeatLayer-managed orders |
| `event:refund` | Refund a SeatLayer-managed order |
| `event:refund` | Refund an eligible Managed Ticketing order through its connected gateway |
| `event:tickets:send` | Send SeatLayer-managed tickets |
| `event:door:view` | Read the door list |
| `event:door:checkin` | Check tickets in and out |
Expand Down Expand Up @@ -287,10 +292,15 @@ requests.

## Reliability

**Retries and idempotency.** Reads retry 408, 429 and 5xx responses with backoff. Only chart create,
chart copy, template instantiation, event create and workspace create opt into mutation retries: the SDK generates one
`Idempotency-Key` and reuses it for every attempt. All other mutations are single-attempt, even if
you supply a key.
**Retries and idempotency.** Reads retry 408, 429 and 5xx responses with backoff. Fourteen
mutations opt into exact header replay: `charts.create`, `charts.copy`,
`templates.instantiate_template`, `events.create`, `workspaces.create`,
`performance_groups.create`, `seasons.create_season`, `seasons.update_season`,
`seasons.delete_season`, `seasons.create_season_plan`, `seasons.duplicate_season_to_live`,
`seasons.create_season_holder_import`, `seasons.create_season_renewal_offers`, and
`seasons.create_season_amendment`. The SDK generates one `Idempotency-Key` and reuses it for every
attempt. All remaining SDK mutations are sent once; some have a server-side domain idempotency
contract, but the SDK does not retry them automatically.

**Booking safety.** Direct and box-office bookings have the server's exact-selection plus
`booking_ref` safeguard, but the SDK still sends them once. Holds, best-available operations,
Expand All @@ -300,7 +310,7 @@ before trying again.
```python
SeatLayer(
os.environ["SEATLAYER_SECRET_KEY"],
max_retries=3, # attempts for reads and the five replay-safe creates
max_retries=3, # attempts for reads and the 14 exact-header-replay mutations
timeout=30.0, # seconds, per attempt
)
```
Expand All @@ -316,6 +326,10 @@ seatlayer.request("POST", "/v1/events/ev_1/some-new-route", body={...})

## API surface

The client exposes these resources. Performance Groups cover runs, sessions, holds, and bookings;
Seasons cover catalogue, plan, sales, buyer-session, booking, renewal, occurrence, reporting,
outbox, and support operations.

| Resource | Methods |
| --- | --- |
| `charts` | `list` `list_all` `create` `retrieve` `update` `delete` `copy` `archive` `unarchive` `publish` |
Expand All @@ -326,6 +340,8 @@ seatlayer.request("POST", "/v1/events/ev_1/some-new-route", body={...})
| `sessions` | `create_manage_session` `revoke_manage_session` `create_designer_session` `revoke_designer_session` |
| `webhooks` | `list` `create` `update` `delete` `list_deliveries` |
| `workspaces` | `list` `create` `retrieve` `update` |
| `performance_groups` | `list` `create` `retrieve` `delete` `activate` `close` `retrieve_lifecycle` `create_buyer_access_session` `list_buyer_access_sessions` `revoke_buyer_access_session` `retrieve_hold` `book_hold` `retrieve_booking` |
| `seasons` | 48 operations for catalogue and Plan lifecycle, sales windows, buyer access and booking, holder imports, renewals, occurrence amendments, reports, audit, outbox, and support export |

Full reference: [SeatLayer server API events](https://docs.seatlayer.io/server-api/events/)

Expand Down Expand Up @@ -378,16 +394,16 @@ outcome before trying again.

### Can I use my own payment provider?

Yes. SeatLayer never processes payment. Inspect the hold, compute the charge from
the returned `items` and their authoritative `unitPrice` and `currency`, take the
money through whichever provider you already use — Stripe, Adyen, Razorpay, or your
own — and then book the hold with your order id as `booking_ref`. SeatLayer owns
seating state, holds, booking concurrency, and the inventory ledger; your platform
owns payments, commercial orders, tickets, delivery, and refunds.
Yes. This server SDK does not process payment in a Platform/SDK integration. Inspect the hold,
compute the charge from each returned item's authoritative `unitPrice`, `quantity`, and `currency`,
take the money through whichever provider you already use, and then book the hold with your order
id as `booking_ref`. SeatLayer owns seating state, holds, booking concurrency, and the inventory
ledger in this integration; your platform owns payments, commercial orders, tickets, delivery,
and refunds. Managed Ticketing is a separate product path with organizer-connected payments.

## Continue your Python integration

- [Follow the SeatLayer server SDK guide](https://docs.seatlayer.io/server-sdk/install/)
- [Follow the Python server SDK guide](https://docs.seatlayer.io/server-sdk/python/)
for installation, authentication, and the full hold-to-booking flow.
- [Handle errors, retries, and safe booking repeats](https://docs.seatlayer.io/server-sdk/reliability/)
before connecting a production order flow.
Expand Down
Loading