# Выдача без оплаты

Билеты для гостей, партнёров и прессы: по одному запросом или списком гостей в CSV до 2 000 строк.

Ручная выдача проходит через тот же резерв, что и продажа: квоты, места, `sold_out` и `seat_taken` работают одинаково. Оплаты нет, владелец билетов становится покупателем заказа, `source` заказа будет `manual` или `import`.

## Выдать билеты {#issue}

`POST /v1/events/{id}/issue`

`Idempotency-Key` обязателен: повтор после обрыва связи не выдаст второй комплект.

| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
| `items` | array | да | Позиции, как в заказе: `{"tariff_id", "qty"}` или `{"seat"}` |
| `holder.email` | string | да | Почта владельца: на неё уйдёт письмо с билетами |
| `holder.first_name`, `holder.last_name` | string | да | Имя и фамилия на билете |
| `holder.phone` | string | нет | Телефон |

```bash Запрос
curl https://api.budu.events/v1/events/0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60/issue \
  -H "Authorization: Bearer $BUDU_KEY" \
  -H "Idempotency-Key: press-kommersant-1" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [{"tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71", "qty": 2}],
    "holder": {
      "email": "press@example.ru",
      "first_name": "Ольга",
      "last_name": "Миронова"
    }
  }'
```

Ответ `201` с [заказом](https://budu.events/docs/orders/#order-object) и билетами, `source: "manual"`. Пока билеты выпускаются, ответ `202 {"status": "processing", "order_id"}`. Ошибки те же, что у [заказа](https://budu.events/docs/orders/#create), и `400`, если нет `Idempotency-Key`.

## Загрузить список гостей {#import}

`POST /v1/events/{id}/imports`

Тело — файл CSV, `Content-Type: text/csv`. Одна строка — один гость и его билеты.

```csv
first_name,last_name,email,tariff,seat,qty
Ольга,Миронова,press@example.ru,Танцпол,,2
Игорь,Белов,igor@example.ru,Партер,П-1-1,
```

| Столбец | Обязательно | Описание |
|---|---|---|
| `first_name`, `last_name`, `email` | да | Гость |
| `tariff` | если тарифов больше одного | Название или код тарифа |
| `seat` | для тарифа с местами | Место: подпись, `external_id` или `id`. Строка с местом — один билет |
| `qty` | нет | Сколько билетов, от 1 до 20. Пусто: 1 |

- Заголовки можно писать по-русски: `имя`, `фамилия`, `почта`, `тариф`, `место`, `количество`.
- Разделитель `,` или `;`, UTF-8, BOM и переводы строк Windows допускаются.
- До 2 000 строк и 1 МБ.
- Если два тарифа называются одинаково, укажите код.

`?dry_run=1` проверяет файл и считает билеты, ничего не выдавая. Ответ `200`:

```json Ответ 200
{
  "id": "",
  "event_id": "0193e0b2-4a7c-7d10-9e3f-2c5a8b1d4e60",
  "status": "",
  "lines": 2,
  "tickets": 3,
  "issued": 0,
  "failed": 0,
  "errors": [],
  "tariffs": [
    {
      "tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c71",
      "tickets": 2,
      "available": 79
    },
    {
      "tariff_id": "0193e0b2-4a7d-7a21-8c44-6e2f9a0b3c73",
      "tickets": 1,
      "available": 140
    }
  ],
  "warnings": [],
  "created_at_ms": "0",
  "finished_at_ms": "0",
  "repeated_file": false,
  "guests_with_tickets": 0
}
```

Без `dry_run` загрузка запускается: ответ `201`, `status: "running"` и `id` загрузки. Билеты выдаются в фоне, письма уходят гостям по мере выдачи.

- Ошибки в файле: `400 invalid_request`, список в `details.errors: [{line, message}]`. Ничего не выдано.
- Тот же список для того же события: `200` с прежней загрузкой и `repeated_file: true`. Второй раз билеты не выдаются. Файл сравнивается по строкам, так что пересохранённый в Excel файл считается тем же.
- `guests_with_tickets` и `warnings` предупреждают, но не останавливают: например, у части гостей уже есть билеты на это событие, или свободных билетов меньше, чем в файле.

## Ход загрузки {#import-get}

`GET /v1/imports/{id}`

```bash Запрос
curl https://api.budu.events/v1/imports/0193e0d1-7c00-7e5f-a1b2-c3d4e5f60718 \
  -H "Authorization: Bearer $BUDU_KEY"
```

`status`: `running` или `done`. `issued` и `failed` — сколько строк выдано и сколько не удалось из `lines`. В `errors` строки, которые не удалось выдать, с причиной и гостем: `{line, message, first_name, last_name, email}`. Первые 100, все — с `?errors=all`.

## Загрузки события {#import-list}

`GET /v1/events/{id}/imports`

Последние 20 загрузок события, новые сверху: `{"imports": [...]}`.
