---
title: "Prices"
description: "Set an event's ticket-type prices and give single seats their own price from your server, with optimistic concurrency."
---

Prices belong to the event, not the chart. A chart's category prices are only
the defaults a new event starts with. Each event can change them, and can give
single seats their own price without moving them out of their category. The
best few seats in the middle of a row cost £90 while the rest of the row stays
at £75.

Your server uses the same writes as the dashboard, so an organizer and your
integration never overwrite each other: every price write names the revision
it read, and a stale one is refused.

## Which price a seat sells at

When a seat is held, SeatLayer prices it once, in this order:

1. A free event: every seat costs 0.
2. A release that box office staff pick at the counter.
3. **The seat's own price.**
4. The seat's channel price.
5. An open release (early bird, scheduled price).
6. The ticket type's price.
7. The event's category price.

On a SeatLayer-checkout event, a seat with no price at all is refused rather
than sold at 0. A price of 0 that you set is a price.

Existing holds and bookings keep the price they were made at. A change prices
new selections only.

## Ticket-type prices

<ApiEndpoint method="GET" path="/v1/events/:key/pricing" auth="Secret key or dashboard session" />

Returns `revision`, `currency` and the event's `catalog`: every category with
its price, or its ticket types with theirs, and whether each row is the
event's own or still follows the chart.

<ApiEndpoint method="PUT" path="/v1/events/:key/pricing" auth="Secret key or dashboard session" />

Send every category once, with the `revision` you read as `expectedRevision`.
A category with ticket types takes `tiers`; any other takes `price`.

```json title="Set Standard to 30 and Circle's two ticket types"
{
  "expectedRevision": 7,
  "categories": [
    { "key": "std", "price": 30 },
    { "key": "circle", "tiers": [{ "id": "adult", "price": 40 }, { "id": "child", "price": 20 }] }
  ]
}
```

## Seat prices

<ApiEndpoint method="GET" path="/v1/events/:key/seat-prices" auth="Secret key or dashboard session" />

Every seat with its own price, by seat label. Each seat also says its ticket
type (`categoryKey`) and, when the floor plan names them, its `section`, `row`
and `seat`:

```json title="Response"
{
  "revision": 8,
  "currency": "GBP",
  "count": 2,
  "seats": [
    { "label": "STALLS-C-F-1", "price": 90, "categoryKey": "stalls", "section": "Stalls C", "row": "F", "seat": "1" },
    { "label": "ARENA-B-E-3", "tiers": { "adult": 150, "child": 75 }, "categoryKey": "arena", "section": "Arena B", "row": "E", "seat": "3" }
  ]
}
```

<ApiEndpoint method="PATCH" path="/v1/events/:key/seat-prices" auth="Secret key or dashboard session" />

Send only the seats that change. `set` gives seats a price; `clear` puts seats
back on their ticket type's price. Clears apply first, then sets.

```json title="Six seats at 90, one cleared"
{
  "expectedRevision": 8,
  "set": [
    { "labels": ["STALLS-C-F-1", "STALLS-C-F-2", "STALLS-C-F-3", "STALLS-C-F-4", "STALLS-C-F-5", "STALLS-C-F-6"], "price": 90 }
  ],
  "clear": ["ARENA-B-E-1"]
}
```

A seat whose category has ticket types needs one price for each of them, as
`tiers`, so a child is never charged the adult price. The response returns the
new `revision`, the `count` of seats with their own price, and the `labels`
that changed.

<ApiEndpoint method="DELETE" path="/v1/events/:key/seat-prices" auth="Secret key or dashboard session" />

Clears every seat price on the event. The body is `{ "expectedRevision": 9 }`.

<Aside type="note" title="Limits">
  An event can give up to 10,000 seats their own price, and one request can
  name up to 10,000 seats. To price a whole area, change its ticket type's
  price or move it to another ticket type.
</Aside>

## Errors to handle

| Status | `code` | Meaning |
| --- | --- | --- |
| 409 | `pricing_revision_conflict` | Someone changed prices since you read them. Read again (`currentRevision`) and retry. |
| 409 | `event_not_mutable` | The event is archived or deleted. |
| 422 | `unknown_labels` | A label is not a seat on this event. Nothing was saved; `labels` names them. |
| 422 | `seat_price_needs_ticket_types` | A seat's price does not match its ticket types. `labels` names them. |
| 422 | `seat_prices_limit` | The event would have more than `limit` seats with their own price. |
| 422 | `invalid_seat_price` | A price is missing, negative, or above 1,000,000. |

## In the browser SDK

Seat prices you set here are what SeatLayer charges, and the buyer widget shows
them. A site that charges on its own checkout can also pass its own seat prices
to the widget with `pricing.objects`. See
[Currency and pricing](/customization/currency-and-pricing/).