RU
Docs sections

Orders

An order issues tickets. Send it in one request after payment, or hold the tickets with a reservation while the buyer pays.

There are two ways to sell a ticket.

  • One request after payment. The buyer paid on your site, your site sends POST /v1/orders and gets the tickets. This fits when there are plenty of tickets and you're ready to refund if they sell out while the buyer pays.
  • A reservation during payment. Your site reserves the tickets before payment (POST /v1/reservations), the buyer pays, your site confirms the reservation (POST /v1/reservations/{id}/confirm). If payment fails, you cancel the reservation (DELETE /v1/reservations/{id}) or it expires on its own. Use this for assigned seats and for tiers that may sell out.

Either way, the tickets are issued and the guest's email goes out right after confirmation.

Order object

FieldTypeDescription
idstringOrder UUID
org_idstringOrganization UUID
livemodebooleanA live order or a test one
event_idstringEvent UUID
statusstringStatus, see below
buyerobjectBuyer: email, first_name, last_name, phone. Also the ticket holder
itemsarrayContents: {tariff_id, qty, seat}. Tickets without seats are grouped by tier, each seat is its own item with qty: 1 and seat (the seat id)
hold_expires_atstringWhen the reservation runs out, RFC 3339
payment_refstringYour payment number, if you passed one
ticketsarrayTickets: {id, url, tariff_id, holder_first_name, holder_last_name, status, seat}. Empty until the tickets are issued
seatsarrayThe order's seats {id, sector, row, number, label} in item order
reasonstringWhy the order can't be confirmed. seat_taken: a seat went to another order, refund the buyer
sourcestringWhere the order came from: api, manual (issued by hand) or import (from a guest list)

tickets[].url is the link to the ticket page: https://budu.events/t/…. You can show it to the buyer right away. More in tickets.

Statuses

StatusMeaning
reservedTickets are held until hold_expires_at, no payment yet
confirmingConfirmation is in progress. The order can no longer be cancelled
paidThe sale is recorded and tickets are being issued. This usually takes a fraction of a second
issuedTickets are issued and the email is sent
expiredThe reservation expired. Confirming is still possible if tickets are left
cancelledThe reservation was cancelled
failedConfirmation failed: the contents didn't match the reservation. Create a new order

An order in paid or issued never becomes expired or cancelled. You can undo a sale only ticket by ticket: POST /v1/tickets/{id}/cancel.

Create an order

POST/v1/orders

Reservation and confirmation in one request. Send it after payment.

FieldTypeRequiredDescription
event_idstringyesUUID of a published event
itemsarrayyesItems: {"tariff_id", "qty"} or {"seat"} for a seat. Up to 20 tickets in total
buyer.emailstringyesEmail: the ticket email goes there
buyer.first_name, buyer.last_namestringyesFirst and last name: printed on the ticket
buyer.phonestringnoPhone, stored with the order
payment_refstringnoYour payment number, returned in the order

Request

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"
  }'

Response 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"
}

If the tickets take longer than a couple of seconds to issue, the response is 202:

Response 202

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

The sale is already recorded, the tickets get issued on their own and the email goes out as usual. The ticket links appear in GET /v1/orders/{id}: read the order once a second until the status turns issued.

ErrorWhen
400 invalid_requestNo buyer, a bad email, no first or last name, empty contents, no such tier (details.tariff_id)
404 not_foundNo such event or seat
409 event_not_on_saleThe event isn't published, or sales are still opening after publishing
409 sold_outThe tier is sold out (details.tariff_id)
409 seat_takenThe seat is already taken (details.seat_id, details.seat)
422 limit_exceededMore than 20 tickets, or more than the tier's per_order_limit (details.tariff_id)
500 internal with details.order_idThe connection to the stock store broke off in the middle of the sale. We finish the order ourselves: check it with GET /v1/orders/{id}

Reserve

POST/v1/reservations

The same fields as an order, plus one more:

FieldTypeRequiredDescription
hold_ttl_secondsintegernoHow long to hold the reservation, 60 to 1,800 seconds. 900 by default, that is 15 minutes

A reservation doesn't need payment_ref: you pass it when you confirm.

Request

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
  }'

You get 201 with the order in reserved status and hold_expires_at. While the reservation lasts, nobody else can buy these tickets and seats. The errors are the same as for an order.

Confirm a reservation

POST/v1/reservations/{id}/confirm

Call it after payment. The body is optional: {"payment_ref": "pay-77813"}.

Request

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"}'
SituationResponse
The reservation is alive, tickets are issued200, the order in issued status with tickets
The sale is recorded, tickets are still being issued202 {"status": "processing", "order_id"}. The tickets appear on their own
The reservation expired, but tickets are still leftthe hold is taken again, then as in the first two rows
The reservation expired and the tickets are gone409 reservation_expired: refund the buyer
A seat from the order went to another order409 seat_taken with details.order_id, details.seat_id, details.seat. This is final: the order becomes expired with reason: "seat_taken", refund the buyer
The reservation was cancelled400 invalid_request «Резерв отменён — создайте новый» (reservation cancelled, create a new one)
The order is already confirmed with a different payment_ref409 idempotency_conflict, the earlier payment in details.payment_ref

Confirming is safe to repeat: a repeat returns the same order and the same tickets.

A successful confirm wins. If two confirms, or a confirm and the reservation's expiry, overlap and the sale got recorded, the order becomes paid and the tickets get issued. We don't roll back a sale. So don't cancel the payment because your HTTP client timed out: repeat the confirm with the same Idempotency-Key or read the order. 409 reservation_expired and 409 seat_taken come only when the sale didn't happen.

Cancel a reservation

DELETE/v1/reservations/{id}

Frees the reservation's tickets and seats when payment fails. A confirmed order can't be cancelled this way.

Request

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

You get 200 with the order in cancelled status. Cancelling again answers the same. Errors: 400 invalid_request «Заказ уже оплачивается — отменить резерв нельзя» (payment is in progress, status confirming) and «Заказ уже оплачен — отменяйте билеты по отдельности» (already paid, cancel tickets one by one; paid, issued).

Get an order

GET/v1/orders/{id}

Request

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

You get 200 with the order. This is always 200, even while tickets are being issued: then the status is paid and tickets doesn't hold every ticket yet.