EN
Разделы документации

Заказы

Заказ выпускает билеты. Отправьте его одним запросом после оплаты или придержите билеты резервом на время оплаты.

Есть два способа продать билет.

  • Один запрос после оплаты. Покупатель оплатил у вас, сайт отправляет POST /v1/orders и получает билеты. Подходит, если билетов с запасом и вы готовы вернуть деньги, когда билеты закончатся за время оплаты.
  • Резерв на время оплаты. Сайт резервирует билеты до оплаты (POST /v1/reservations), покупатель платит, сайт подтверждает резерв (POST /v1/reservations/{id}/confirm). Если оплата не прошла, резерв отменяют (DELETE /v1/reservations/{id}) или он истекает сам. Так продают места в зале и тарифы, которые могут закончиться.

В обоих случаях билеты выпускаются, а письмо гостю уходит сразу после подтверждения.

Объект заказа

ПолеТипОписание
idstringUUID заказа
org_idstringUUID организации
livemodebooleanБоевой заказ или тестовый
event_idstringUUID события
statusstringСтатус, см. ниже
buyerobjectПокупатель: email, first_name, last_name, phone. Он же владелец билетов
itemsarrayСостав: {tariff_id, qty, seat}. Билеты без мест сгруппированы по тарифу, каждое место отдельной позицией с qty: 1 и seat (id места)
hold_expires_atstringДо какого момента держится резерв, RFC 3339
payment_refstringВаш номер платежа, если передали
ticketsarrayБилеты: {id, url, tariff_id, holder_first_name, holder_last_name, status, seat}. Пусто, пока билеты не выпущены
seatsarrayМеста заказа {id, sector, row, number, label} в порядке позиций
reasonstringПочему заказ нельзя подтвердить. seat_taken: место ушло другому заказу, деньги нужно вернуть
sourcestringОткуда заказ: api, manual (выдан вручную) или import (из списка гостей)

tickets[].url — ссылка на страницу билета: https://budu.events/t/…. Её можно сразу показать покупателю. Подробнее в разделе билеты.

Статусы

СтатусЧто значит
reservedБилеты в резерве до hold_expires_at, оплаты ещё нет
confirmingПодтверждение идёт. Отменить заказ уже нельзя
paidПродажа зафиксирована, билеты выпускаются. Обычно это доли секунды
issuedБилеты выпущены, письмо отправлено
expiredРезерв истёк. Подтверждение ещё возможно, если билеты остались
cancelledРезерв отменён
failedПодтвердить не удалось: состав не совпал с резервом. Создайте новый заказ

Заказ в paid или issued больше не становится expired или cancelled. Отменить проданное можно только по билету: POST /v1/tickets/{id}/cancel.

Создать заказ

POST/v1/orders

Резерв и подтверждение одним запросом. Отправляйте после оплаты.

ПолеТипОбязательноОписание
event_idstringдаUUID опубликованного события
itemsarrayдаПозиции: {"tariff_id", "qty"} или {"seat"} для места. Всего до 20 билетов
buyer.emailstringдаПочта: на неё уйдёт письмо с билетами
buyer.first_name, buyer.last_namestringдаИмя и фамилия: они напечатаны на билете
buyer.phonestringнетТелефон, хранится в заказе
payment_refstringнетВаш номер платежа, вернётся в заказе

Запрос

curl https://api.budu.events/v1/orders \
  -H "Authorization: Bearer $BUDU_KEY" \
  -H "Idempotency-Key: order-1042" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60",
    "items": [{"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71", "qty": 2}],
    "buyer": {
      "email": "maria@example.ru",
      "first_name": "Мария",
      "last_name": "Соколова"
    },
    "payment_ref": "pay-77812"
  }'

Ответ 201

{
  "id": "0193e0c5-1f20-7c3e-b6a1-9d4e2f7a8b10",
  "org_id": "0193d9a1-2b3c-7d4e-8f50-61728394a5b6",
  "livemode": false,
  "event_id": "0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60",
  "status": "issued",
  "buyer": {
    "email": "maria@example.ru",
    "first_name": "Мария",
    "last_name": "Соколова",
    "phone": ""
  },
  "items": [
    {"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71", "qty": 2, "seat": ""}
  ],
  "hold_expires_at": "2026-10-22T12:15:04Z",
  "payment_ref": "pay-77812",
  "tickets": [
    {
      "id": "0193e0c5-1f6b-7e02-a3c9-5b8d1e4f9f0a",
      "url": "https://budu.events/t/Vw3kqP7nX2bLmR9tYc4sHa",
      "tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71",
      "holder_first_name": "Мария",
      "holder_last_name": "Соколова",
      "status": "valid",
      "seat": null
    },
    {
      "id": "0193e0c5-1f6b-7e02-a3c9-5b8d1e4fa21c",
      "url": "https://budu.events/t/9pLmZ2xQw8RkT4vNb6CyJe",
      "tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71",
      "holder_first_name": "Мария",
      "holder_last_name": "Соколова",
      "status": "valid",
      "seat": null
    }
  ],
  "seats": [],
  "reason": "",
  "source": "api"
}

Если билеты не успели выпуститься за пару секунд, ответ будет 202:

Ответ 202

{"status": "processing", "order_id": "0193e0c5-1f20-7c3e-b6a1-9d4e2f7a8b10"}

Продажа уже зафиксирована, билеты выпустятся сами, письмо уйдёт как обычно. Ссылки на билеты появятся в GET /v1/orders/{id}: читайте заказ раз в секунду, пока статус не станет issued.

ОшибкаКогда
400 invalid_requestНет покупателя, неверная почта, нет имени или фамилии, пустой состав, нет такого тарифа (details.tariff_id)
404 not_foundНет события или места
409 event_not_on_saleСобытие не опубликовано, или продажа ещё открывается после публикации
409 sold_outБилеты тарифа закончились (details.tariff_id)
409 seat_takenМесто уже занято (details.seat_id, details.seat)
422 limit_exceededБольше 20 билетов или больше per_order_limit тарифа (details.tariff_id)
500 internal с details.order_idСвязь с хранилищем остатков оборвалась посреди продажи. Заказ мы завершим сами: проверьте его через GET /v1/orders/{id}

Зарезервировать

POST/v1/reservations

Те же поля, что у заказа, и ещё одно:

ПолеТипОбязательноОписание
hold_ttl_secondsintegerнетСколько держать резерв, от 60 до 1 800 секунд. По умолчанию 900, то есть 15 минут

payment_ref в резерве не нужен: его передают при подтверждении.

Запрос

curl https://api.budu.events/v1/reservations \
  -H "Authorization: Bearer $BUDU_KEY" \
  -H "Idempotency-Key: cart-5531" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60",
    "items": [{"seat": "П-1-1"}, {"seat": "П-1-2"}],
    "buyer": {
      "email": "anna@example.ru",
      "first_name": "Анна",
      "last_name": "Петрова"
    },
    "hold_ttl_seconds": 600
  }'

Ответ 201 с заказом в статусе reserved и hold_expires_at. Пока резерв жив, эти билеты и места никто другой не купит. Ошибки те же, что у заказа.

Подтвердить резерв

POST/v1/reservations/{id}/confirm

Вызывайте после оплаты. Тело необязательно: {"payment_ref": "pay-77813"}.

Запрос

curl https://api.budu.events/v1/reservations/0193e0c5-2a40-7b11-9c3d-4e5f6a7b8c90/confirm \
  -H "Authorization: Bearer $BUDU_KEY" \
  -H "Idempotency-Key: pay-77813" \
  -H "Content-Type: application/json" \
  -d '{"payment_ref": "pay-77813"}'
СитуацияОтвет
Резерв жив, билеты выпущены200, заказ в статусе issued с билетами
Продажа зафиксирована, билеты ещё выпускаются202 {"status": "processing", "order_id"}. Билеты появятся сами
Резерв истёк, но билеты ещё естьрезерв берётся заново, дальше как в первых двух строках
Резерв истёк, и билеты разобрали409 reservation_expired: верните деньги покупателю
Место из заказа ушло другому заказу409 seat_taken с details.order_id, details.seat_id, details.seat. Это окончательно: заказ становится expired с reason: "seat_taken", верните деньги
Резерв отменён400 invalid_request «Резерв отменён — создайте новый»
Заказ уже подтверждён с другим payment_ref409 idempotency_conflict, в details.payment_ref прежний платёж

Подтверждение безопасно повторять: повтор вернёт тот же заказ и те же билеты.

Успешное подтверждение побеждает. Если два подтверждения или подтверждение и истечение резерва пересеклись, а продажа успела зафиксироваться, заказ станет paid, и билеты выпустятся. Проданное мы не откатываем. Поэтому не отменяйте платёж из-за таймаута своего HTTP-клиента: повторите подтверждение с тем же Idempotency-Key или прочитайте заказ. 409 reservation_expired и 409 seat_taken приходят, только если продажа не состоялась.

Отменить резерв

DELETE/v1/reservations/{id}

Освобождает билеты и места резерва, если оплата не прошла. Подтверждённый заказ так не отменить.

Запрос

curl -X DELETE https://api.budu.events/v1/reservations/0193e0c5-2a40-7b11-9c3d-4e5f6a7b8c90 \
  -H "Authorization: Bearer $BUDU_KEY"

Ответ 200 с заказом в статусе cancelled. Повторная отмена отвечает так же. Ошибки: 400 invalid_request «Заказ уже оплачивается — отменить резерв нельзя» (статус confirming) и «Заказ уже оплачен — отменяйте билеты по отдельности» (paid, issued).

Получить заказ

GET/v1/orders/{id}

Запрос

curl https://api.budu.events/v1/orders/0193e0c5-1f20-7c3e-b6a1-9d4e2f7a8b10 \
  -H "Authorization: Bearer $BUDU_KEY"

Ответ 200 с заказом. Здесь всегда 200, даже пока билеты выпускаются: тогда статус paid, и в tickets ещё не все билеты.