Docs sections
Assigned seating
Tickets for specific seats: a tier with seats, the seat map as a CSV file, and ordering a seat by its label or your own ID.
A seat always belongs to one tier, that is, one price category. One event can mix tiers with seats and tiers with a quota: for example, stalls by seat and a dance floor without seats. A seat sells once, even when two people buy it in the same second.
Set up an event with seats
- Create an event with a
"seated": truetier. Don't pass a quota for such a tier: it equals the number of its seats. - Upload the seats as a CSV file:
POST /v1/events/{id}/seats. You can check the file first with?dry_run=1. - Publish the event. A tier with seats can't be published without its seats.
Seats change only on a draft. An upload replaces every seat of the event.
CSV format
csv
sector,row,number,label,external_id,tariff
Партер,1,1,П-1-1,hall-0001,parter
Партер,1,2,,hall-0002,parter
"Балкон, левая сторона",1,1,Б-1-1,hall-0101,balcony| Column | Required | Description |
|---|---|---|
sector | yes | Sector, up to 50 characters |
row | yes | Row, up to 20 characters |
number | yes | Seat number, up to 20 characters |
label | no | Seat label, unique within the event, up to 100 characters. Empty means sector-row-number, in the example's second line Партер-1-2 |
external_id | no | Your own seat ID, for example from the hall plan. Unique within the event and never equal to any label |
tariff | if there are several tiers with seats | Code or name of the tier with seats |
- The first line is the header. Case and spaces around names don't matter, columns go in any order. Any other column is an error.
- The separator is
,or;(Excel with Russian settings saves with;). RFC 4180 quotes, a BOM and Windows line breaks are fine. - UTF-8 only. In Excel, save as "CSV UTF-8".
- Empty lines are skipped. Control characters inside values are not allowed.
- Line order is the order of seats in the hall: lists and availability return seats in it.
- Up to 50,000 seats and 5 MB per file.
Upload seats
POST/v1/events/{id}/seats
The request body is the file itself, with Content-Type: text/csv. The file is accepted whole or not at all. ?dry_run=1 checks and counts the seats without writing anything.
Request
curl "https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60/seats?dry_run=1" \
-H "Authorization: Bearer $BUDU_KEY" \
-H "Content-Type: text/csv" \
--data-binary @hall.csvResponse 200
{
"total": 3,
"per_tariff": [
{"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c73", "count": 2},
{"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c74", "count": 1}
],
"errors": [],
"sample": [
{
"id": "0193e0b3-0a11-7f00-8d2b-41c6e9a7b001",
"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c73",
"sector": "Партер",
"row": "1",
"number": "1",
"label": "П-1-1",
"external_id": "hall-0001",
"position": 1
}
]
}sample holds the first 20 seats for a preview. If the file has errors, the response is 400 invalid_request, nothing is written, and the errors are in details.errors:
Response 400
{
"error": {
"code": "invalid_request",
"message": "В файле мест есть ошибки — места не загружены",
"details": {
"errors": [
{"line": 3, "message": "Место «П-1-1» повторяется: строки 2 и 3"}
]
}
}
}line is the file's line number, with the header as line 1. line: 0 refers to the file as a whole. The response holds up to 100 errors.
You don't need an Idempotency-Key here: repeating the same file gives the same result. After publishing, an upload answers 400 «Места можно загрузить только до публикации» (seats can be uploaded only before publishing).
List seats
GET/v1/events/{id}/seats
| Parameter | Description |
|---|---|
limit | Seats per page, 1 to 5,000, 1,000 by default |
after | id of the last seat on the previous page |
sector | Only this sector |
Request
curl "https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60/seats?limit=2" \
-H "Authorization: Bearer $BUDU_KEY"Response 200
{
"seats": [
{
"id": "0193e0b3-0a11-7f00-8d2b-41c6e9a7b001",
"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c73",
"sector": "Партер",
"row": "1",
"number": "1",
"label": "П-1-1",
"external_id": "hall-0001",
"position": 1
},
{
"id": "0193e0b3-0a11-7f00-8d2b-41c6e9a7b002",
"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c73",
"sector": "Партер",
"row": "1",
"number": "2",
"label": "Партер-1-2",
"external_id": "hall-0002",
"position": 2
}
],
"last": false,
"sectors": ["Партер", "Балкон, левая сторона"]
}Seats come in file order. For the next page pass after=<id of the last seat> until last turns true. sectors comes on the first page only.
Seat states
GET /v1/events/{id}/availability?seats=1 adds a page of seat states to availability: seats: [{seat_id, tariff_id, sector, label, state}] and seats_last. You page through them the same way, with the seats_after and seats_limit parameters.
state | Meaning |
|---|---|
free | Free |
held | Held by an order's reservation. Frees up if the reservation is cancelled or expires |
sold | Sold. Turns free again if the ticket is cancelled and returned to sale |
Order a seat
In POST /v1/orders and POST /v1/reservations an item with a seat looks like {"seat": "<reference>"} instead of {"tariff_id", "qty"}:
json
{
"event_id": "0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60",
"items": [
{"seat": "П-1-1"},
{"seat": "hall-0002"},
{"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71", "qty": 2}
],
"buyer": {
"email": "anna@example.ru",
"first_name": "Анна",
"last_name": "Петрова"
}
}- A seat reference is its
id,external_idorlabel. We check them in that order. - A seat's
qtyis0or1. You can leave outtariff_id, and if you give it, it must match the seat's tier. - A tier with seats can't be ordered by quantity:
400«Для этого тарифа выберите места» (choose seats for this tier). - A seat counts as one ticket toward the limit of 20 per order and the tier's
per_order_limit. - In orders and tickets a seat comes as a
seat: {id, sector, row, number, label}object. The guest sees "Sector · Row · Seat" on the ticket, in the email and in the calendar entry.
Errors: 409 seat_taken if another order holds the seat or it's sold (details.seat_id, details.seat). 404 not_found if the event has no such seat (details.seat). 409 event_not_on_sale with «Продажа мест ещё не открыта» (seat sales aren't open yet) if only a few seconds have passed since publishing and the seats are still being loaded into sales.