Docs sections
Events
An event is a date, a venue and tiers. Create it as a draft, publish it, and sales open.
A new event starts as a draft (draft). You can change a draft any way you like, but you can't sell tickets for it. Publishing (published) opens sales, and after that the tiers no longer change.
Event object
| Field | Type | Description |
|---|---|---|
id | string | Event UUID |
org_id | string | Organization UUID |
livemode | boolean | true for a live event, false for a test one |
title | string | Title, up to 200 characters |
starts_at, ends_at | string | Start and end, RFC 3339 in UTC |
timezone | string | IANA time zone, such as Europe/Moscow. The email and the ticket show times in it |
venue_name, venue_address | string | Venue and address, up to 300 characters |
status | string | draft (draft) or published (on sale) |
tariffs | array | Tiers, see below |
has_seats | boolean | The event has a tier with seats |
ticket_style | string | Ticket look: ticket (a white ticket with a tear-off line) or pass (a pass with a lime header) |
cover | string | Cover version. An empty string means no cover |
Tier
| Field | Type | Description |
|---|---|---|
id | string | Tier UUID. You pass it in an order |
code | string | Code: Latin letters, digits, _ and -, up to 32 characters. Unique within the event. Defaults to t1, t2… |
name | string | Name, up to 100 characters. Never repeats within the event, case-insensitive |
price_minor | string | Price in kopecks. A number or a string in requests, a string in responses |
currency | string | Three-letter currency code, RUB by default |
quota | integer | How many tickets to sell, 1 to 1,000,000. For a tier with seats it equals the number of seats |
per_order_limit | integer | How many tickets of the tier fit in one order. 0 means no limit |
seated | boolean | A tier with seats, see assigned seating |
seats | integer | Response only: how many seats the tier has |
Create an event
POST/v1/events
| Field | Type | Required | Description |
|---|---|---|---|
title | string | yes | Title |
starts_at | string | yes | Start, RFC 3339 |
ends_at | string | yes | End, later than the start |
timezone | string | yes | IANA time zone |
venue_name | string | no | Venue |
venue_address | string | no | Address, the guest gets directions to it |
ticket_style | string | no | ticket (default) or pass |
tariffs | array | no | Tiers: code, name, price_minor, currency, quota, per_order_limit, seated. A draft doesn't need tiers, publishing needs at least one |
Request
curl https://api.budu.events/v1/events \
-H "Authorization: Bearer $BUDU_KEY" \
-H "Idempotency-Key: event-jazz-2026" \
-H "Content-Type: application/json" \
-d '{
"title": "Джаз в саду",
"starts_at": "2026-12-12T16:00:00Z",
"ends_at": "2026-12-12T19:00:00Z",
"timezone": "Europe/Moscow",
"venue_name": "Площадка «Сад»",
"venue_address": "Москва, Садовая улица, 1",
"ticket_style": "ticket",
"tariffs": [
{
"code": "dance",
"name": "Танцпол",
"price_minor": 250000,
"quota": 300,
"per_order_limit": 6
}
]
}'Response 201
{
"id": "0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60",
"org_id": "0193d9a1-2b3c-7d4e-8f50-61728394a5b6",
"livemode": false,
"title": "Джаз в саду",
"starts_at": "2026-12-12T16:00:00Z",
"ends_at": "2026-12-12T19:00:00Z",
"timezone": "Europe/Moscow",
"venue_name": "Площадка «Сад»",
"venue_address": "Москва, Садовая улица, 1",
"status": "draft",
"tariffs": [
{
"id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71",
"code": "dance",
"name": "Танцпол",
"price_minor": "250000",
"currency": "RUB",
"quota": 300,
"per_order_limit": 6,
"seated": false,
"seats": 0
}
],
"has_seats": false,
"ticket_style": "ticket",
"cover": ""
}Errors: 400 invalid_request with the reason in message. For example: no title, the end before the start, an unknown time zone, a repeated tier code or name, a quota out of range. If a tier is at fault, its code is in details.code.
List events
GET/v1/events
Every event of the organization in the key's mode, by start time.
Request
curl https://api.budu.events/v1/events -H "Authorization: Bearer $BUDU_KEY"You get 200 with {"events": [...]}, each event an event object with every field.
Get an event
GET/v1/events/{id}
Request
curl https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60 \
-H "Authorization: Bearer $BUDU_KEY"You get 200 with the event object. Another organization's event or an event of the other mode gives 404 not_found.
Update an event
PATCH/v1/events/{id}
Only the fields you send change, the rest stay as they were. You can send title, starts_at, ends_at, timezone, venue_name, venue_address, ticket_style and tariffs. Any other field gives 400 invalid_request with the field name in details.field.
tariffsreplaces the draft's tiers as a whole. To keep a tier, pass itsid. A tier without anidis new, and a tier missing from the list is deleted together with its seats.- A published event's tiers don't change:
400 invalid_request. You can still change the title, times, venue and ticket look.
Request
curl -X PATCH https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60 \
-H "Authorization: Bearer $BUDU_KEY" \
-H "Content-Type: application/json" \
-d '{"venue_name": "Летняя сцена", "ticket_style": "pass"}'You get 200 with the updated event.
Publish
POST/v1/events/{id}/publish
Opens sales. You need at least one tier, and tiers with seats need their seats uploaded.
Request
curl -X POST https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60/publish \
-H "Authorization: Bearer $BUDU_KEY"You get 200 with the event in published status. Stock reaches sales within a few seconds. Until then an order gets 409 event_not_on_sale. Publishing again breaks nothing and answers the same.
Errors: 400 invalid_request: «Добавьте хотя бы один тариф» (add at least one tier), «Загрузите места для тарифа «…»» (upload the seats for the tier, details.tariff_id).
Availability
GET/v1/events/{id}/availability
How many tickets are left in each tier. Handy for showing "12 left" on your site or closing sales of a tier.
| Parameter | Description |
|---|---|
seats | 1: add seat states |
seats_after | id of the last seat on the previous page |
seats_limit | Seats per page, 1 to 5,000 |
sector | Only the seats of this sector |
Request
curl https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60/availability \
-H "Authorization: Bearer $BUDU_KEY"Response 200
{
"tariffs": [
{
"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71",
"quota": 300,
"sold": 212,
"available": 79,
"held": 9,
"seated": false
}
],
"seats": [],
"seats_last": false
}held counts tickets in active reservations: nobody has paid for them yet. available = quota − sold − held. Seat states are described in assigned seating.
Cover
PUT/v1/events/{id}/cover
The event's picture. The guest sees it as a band across the top of the ticket, on the page and in the email. The request body is the picture itself, not a form.
Request
curl -X PUT https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60/cover \
-H "Authorization: Bearer $BUDU_KEY" \
-H "Content-Type: image/jpeg" \
--data-binary @cover.jpg- JPEG, PNG or WebP. We check the format by the file's content, not by the header.
- Up to 5 MB and 25 megapixels, at least 640 px wide, landscape: 3:2 to 2:1. 16:9 works best, such as 1920×1080.
- The ticket shows the cover at 16:9: a 3:2 picture loses its top and bottom edges. Keep text and faces near the center.
- We store our own copy: a JPEG up to 1,200 px wide with no metadata. A transparent PNG background turns white.
- You can change the cover in any event status. The ticket page shows the new one right away, emails already sent keep the old one.
You get 200 with the event, with the new version in cover. Errors: 400 invalid_request with the reason in message. If the proportions or the size don't fit, details holds width and height.
DELETE/v1/events/{id}/cover
Removes the cover. You get 200 with the event, cover empty.