> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.voodoo.center/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.voodoo.center/_mcp/server.

# Размещение заказов

Размещение заказа — это единственный вызов `POST /api/v1/orders`. Он списывает
средства с баланса вашего аккаунта и сразу возвращает `201` со `status:
"pending"`. Выполнение происходит асинхронно — окончательный результат приходит
на ваш [webhook](/webhooks) и всегда доступен для чтения из
`GET /api/v1/orders/{id}`.

## Типы товаров

Каждый товар каталога имеет **тип продукта**, который определяет, что вы должны отправить:

| Тип продукта | Что это                                   | `quantity`                         | `fields`        |
| ------------ | ----------------------------------------- | ---------------------------------- | --------------- |
| `key`        | Коды подарочных карт / лицензионные ключи | Целое количество, по умолчанию `1` | Не используется |
| `topup`      | Пополнения баланса/валюты                 | Десятичная сумма, **обязательно**  | **Обязательно** |
| `service`    | Ручные/игровые сервисы                    | Пропустите (всегда `1`)            | **Обязательно** |

`item_id` товара, тип продукта, границы количества и определения полей вы
узнаёте из **экспорта каталога** — отдельного канала данных, а не части этого
API. API не предоставляет эндпоинта для просмотра каталога.

## Поля запроса

* **`item_id`** *(целое число, обязательно)* — числовой id товара из каталога.
* **`quantity`** *(число)* — см. таблицу типов товаров выше. Должно быть в
  пределах диапазона min/max товара.
  * `key`: целое количество (по умолчанию `1`).
  * `topup`: десятичная сумма (обязательно).
  * `service`: пропустите — оно всегда `1`.
* **`merchant_order_id`** *(строка, необязательно)* — ваш собственный
  идентификатор, **уникальный в пределах аккаунта**. Используйте его для
  **идемпотентности** и для связывания событий webhook с вашими записями.
* **`fields`** *(объект)* — обязательны только для товаров `topup` и `service`,
  индексированы по **именам полей** товара. Товары `key` не принимают `fields`.

### Значения полей: текст против выбора

Каждое поле товара является либо **текстовым** полем, либо полем **выбора**:

* **Текстовое поле** → отправляйте значение как **строку** (например, `"player_id":
  "123456789"`).
* **Поле выбора** → отправляйте **числовой id выбора**, а не метку (например,
  `"server": 17`, где `17` — это id выбора «Europe (EU-West)»).

В ответах отправленные `fields` возвращаются с рендерингом значений выбора как
их читабельных **отображаемых названий** (например, `"server": "Europe
(EU-West)"`), даже если вы отправили числовой id. Это только для отображения —
при создании продолжайте отправлять числовые id выбора.

## Создание заказа

```bash title="Товар типа key (подарочная карта / код)"
curl -X POST https://api.voodoo.center/api/v1/orders \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "item_id": 4090,
    "quantity": 2,
    "merchant_order_id": "po-10231"
  }'
```

```bash title="Товар типа top-up (поля; server — id выбора)"
curl -X POST https://api.voodoo.center/api/v1/orders \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "item_id": 4211,
    "quantity": 10,
    "merchant_order_id": "po-10232",
    "fields": { "player_id": "123456789", "server": 17 }
  }'
```

```bash title="Товар типа service (без количества)"
curl -X POST https://api.voodoo.center/api/v1/orders \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{
    "item_id": 5000,
    "merchant_order_id": "po-10233",
    "fields": { "account_email": "player@example.com" }
  }'
```

```python title="create_orders.py"
import httpx

BASE = "https://api.voodoo.center"
headers = {"Authorization": f"Bearer {access_token}"}

# Товар типа key — целое количество, без полей
key_order = httpx.post(f"{BASE}/api/v1/orders", headers=headers, json={
    "item_id": 4090,
    "quantity": 2,
    "merchant_order_id": "po-10231",
}).json()

# Товар типа top-up — десятичное количество + поля (server — числовой id выбора)
topup_order = httpx.post(f"{BASE}/api/v1/orders", headers=headers, json={
    "item_id": 4211,
    "quantity": 10,
    "merchant_order_id": "po-10232",
    "fields": {"player_id": "123456789", "server": 17},
}).json()

# Товар типа service — пропустите количество, отправьте поля
service_order = httpx.post(f"{BASE}/api/v1/orders", headers=headers, json={
    "item_id": 5000,
    "merchant_order_id": "po-10233",
    "fields": {"account_email": "player@example.com"},
}).json()

print(key_order["id"], key_order["status"])  # ... pending
```

Успешное создание возвращает `201` с заказом в состоянии `pending`:

```json title="201 Created"
{
  "id": "0190f8a1-6b2c-7e33-9a10-4c1d2e3f5a6b",
  "item": 4211,
  "item_name": "Sample Game Top-up",
  "item_product_type": "topup",
  "quantity": 10,
  "delivered_quantity": 0,
  "price": 12.50,
  "refund_amount": 0,
  "fields": { "player_id": "123456789", "server": "Europe (EU-West)" },
  "status": "pending",
  "error": "",
  "error_message": "",
  "codes": [],
  "merchant_order_id": "po-10232",
  "source": "api",
  "created_by": { "id": "0190f8a0-1111-7000-8000-000000000001", "email": "integrations@merchant.example" },
  "created_at": "2026-07-05T12:00:00Z",
  "completed_at": null
}
```

## Жизненный цикл заказа

Заказ начинается в состоянии `pending`, может ненадолго перейти в `processing`,
а затем завершается одним из трёх терминальных статусов:

| Терминальный статус | Значение                                  | Ключевые поля                                   |
| ------------------- | ----------------------------------------- | ----------------------------------------------- |
| `completed`         | Доставлено полностью                      | `codes` (товары типа key), `delivered_quantity` |
| `partial`           | Доставлена часть единиц                   | `delivered_quantity`, `refund_amount`           |
| `failed`            | Ничего не доставлено, списание возвращено | `error`, `error_message`, `refund_amount`       |

* **`codes`** — строки доставленных ключей, для товаров типа `key`.
* **`refund_amount`** — сумма, возвращённая за недоставленные единицы для заказа
  `partial` или `failed`.
* **`error` / `error_message`** — устанавливаются, когда `status` равен `failed`
  (например, `error: "OUT_OF_STOCK"`).

Товар, которого **нет в наличии на момент создания**, отклоняется сразу как
ошибка валидации `400` («Item is not available»). Если запас или выполнение дают
сбой **после** принятия заказа, заказ завершается терминальным
`status: "failed"` (отображается на вашем webhook) — а не HTTP-ошибкой. См.
[Ошибки](/errors).

## Чтение заказа

Получите текущее состояние любого из своих заказов с помощью
`GET /api/v1/orders/{id}`:

```bash title="Получение заказа"
curl https://api.voodoo.center/api/v1/orders/0190f8a1-6b2c-7e33-9a10-4c1d2e3f5a6b \
  -H "Authorization: Bearer <access_token>"
```

```python title="get_order.py"
order_id = "0190f8a1-6b2c-7e33-9a10-4c1d2e3f5a6b"
order = httpx.get(
    f"{BASE}/api/v1/orders/{order_id}",
    headers={"Authorization": f"Bearer {access_token}"},
).json()
print(order["status"], order["codes"])
```

```json title="Выполненный заказ с ключами"
{
  "id": "0190f8a1-6b2c-7e33-9a10-4c1d2e3f5a6b",
  "item": 4090,
  "item_name": "Sample Gift Card 10 USD",
  "item_product_type": "key",
  "quantity": 2,
  "delivered_quantity": 2,
  "price": 18.00,
  "refund_amount": 0,
  "fields": {},
  "status": "completed",
  "error": "",
  "error_message": "",
  "codes": ["ABCD-1234-EFGH-5678", "IJKL-9012-MNOP-3456"],
  "merchant_order_id": "po-10231",
  "source": "api",
  "created_by": { "id": "0190f8a0-1111-7000-8000-000000000001", "email": "integrations@merchant.example" },
  "created_at": "2026-07-05T12:00:00Z",
  "completed_at": "2026-07-05T12:00:07Z"
}
```

`GET /api/v1/orders/{id}` возвращает `404` (`code: "not_found"`) для заказа,
который не существует **или** не принадлежит вашему аккаунту. В API нет
эндпоинта для получения списка заказов — просматривайте заказы в дашборде.

## Webhook против опроса

Предпочитайте [webhook](/webhooks): Voodoo Center отправляет терминальное событие
на ваш URL, как только заказ завершается — опрос не нужен. Опрос
`GET /api/v1/orders/{id}` — это приемлемый запасной вариант (например, если
доставка webhook была пропущена), но webhook — это путь с меньшей задержкой и
меньшей нагрузкой.

Получайте и проверяйте события терминального статуса.

Валидация, недостаточный баланс и асинхронные сбои.