WardenCoredocs
APIЭндпоинты

Паки

Каталог паков, прямая выдача пака игроку и история выдач.

Читайте каталог паков, выдавайте пак напрямую игроку (бесплатно — коины не списываются) и смотрите историю выдач по всем источникам (выдачи через API, погашения клейм-кодов, покупки в магазине, ручные админ-выдачи).

Ссылки на пак

У пака два названия: nameслаг каталога (starter, стабильный, под него пишут скрипты) — и display_nameчеловекочитаемый заголовок (Starter Pack, его видят игроки).

Где бы пак ни встречался — в самом каталоге, в результате выдачи, в строке леджера, в клейм-коде — это одна и та же форма { id, name, display_name }. Для пака, который всё ещё есть в каталоге, оба названия заполнены. id — главный: используйте его в GET /v1/packs/{id}, чтобы получить полную запись.

Единственное исключение — строка истории выдач, чей пак уже удалён: у неё оба названия равны null. Сама выдача в леджере остаётся, исчезает только запись каталога, на которую она ссылалась.

GET /v1/packs

Список каталога паков.

Скоуп: packs:read.

ПараметрТипСмысл
enabledtrue | falseТолько включённые / выключенные паки.
category_idintegerТолько паки этой категории.
searchstringПоиск по имени пака.
cursorstringНепрозрачный курсор из предыдущего next_cursor.
limitinteger (1–100)Размер страницы. По умолчанию 50.
{
  "data": [
    {
      "id": 5,
      "name": "starter",
      "display_name": "Starter Pack",
      "description": "Помощь новичкам.",
      "category": { "id": 2, "name": "Bundles" },
      "price": 100,
      "enabled": true,
      "shop_enabled": true,
      "buy_limit": { "count": 0, "window_minutes": 0 },
      "image_url": "/api/packs/5/image?raw=1",
      "created_at": "2026-01-01 12:00:00",
      "updated_at": "2026-01-02 09:30:00"
    }
  ],
  "has_more": false,
  "next_cursor": null,
  "total": 1
}

buy_limit.count равный 0 означает «без ограничений». price — стоимость в коинах при покупке через магазин; прямая выдача ниже её игнорирует.

GET /v1/packs/{id}

Один пак по числовому id. 404 not_found, если его нет.

Скоуп: packs:read.

POST /v1/packs/{id}/deliver

Выдать пак напрямую игроку и бесплатно — содержимое выдаётся без списания коинов. Получателя задавайте ровно одним из steam_id или discord_id.

Скоуп: packs:deliver.

ПолеТипСмысл
steam_idstring (17 цифр)Steam64 получателя. Укажите это или discord_id.
discord_idstring (17–20 цифр)Discord-id получателя; резолвится в привязанного игрока. Укажите это или steam_id.
quantityinteger (1–100)Сколько копий. По умолчанию 1.
POST /v1/packs/5/deliver
Content-Type: application/json

{ "steam_id": "76561198000000000", "quantity": 1 }
{
  "pack": { "id": 5, "name": "starter", "display_name": "Starter Pack" },
  "player": { "steam_id": "76561198000000000", "discord_id": "123456789012345678" },
  "quantity": 1,
  "delivered": true,
  "status": "completed",
  "purchase_id": 42,
  "error_message": null
}

delivered — общий итог; status — точный результат (completed, partial, failed, refund_failed, ledger_failed). Выдача попадает в историю ниже с source: "api".

Выдача НЕ идемпотентна — шлите Idempotency-Key

Каждый вызов заново спавнит предметы пака, поэтому повтор при сбое может выдать дважды. Шлите Idempotency-Key, чтобы повтор воспроизвёл первый результат вместо новой выдачи.

Получатель должен быть реальным игроком

discord_id, не привязанный ни к одному игроку, вернёт 404 not_found. Корректный, но ни разу не заходивший steam_id принимается, но предметы могут не дойти (выдача покажет status: "failed" / "partial").

GET /v1/packs/deliveries

История выдач (журнал покупок паков) — каждый пак, дошедший до игрока, независимо от источника: прямые выдачи через API (api), погашения клейм-кодов (claim), ручные админ-выдачи (admin), покупки в магазине и другое.

Скоуп: packs:read.

ПараметрТипСмысл
steam_idstring (цифры)Только выдачи этому игроку. Укажите это или discord_id.
discord_idstring (цифры)Резолвится в привязанного игрока. Непривязанный id → пустая страница.
pack_idintegerТолько выдачи этого пака.
sourcestringТолько этот источник (api, claim, admin, …).
statusstringТолько этот итог (completed, partial, failed, …).
cursorstringНепрозрачный курсор.
limitinteger (1–100)Размер страницы. По умолчанию 50.
{
  "data": [
    {
      "id": 7,
      "pack": { "id": 5, "name": "starter", "display_name": "Starter Pack" },
      "player": { "steam_id": "76561198000000000", "discord_id": "123456789012345678" },
      "quantity": 1,
      "total_price": 0,
      "status": "completed",
      "source": "api",
      "error_message": null,
      "delivered_at": "2026-01-03 18:05:00"
    }
  ],
  "has_more": false,
  "next_cursor": null,
  "total": 1
}

player.discord_idтекущая привязка Discord получателя (Discord едет рядом со Steam — null, когда не привязан), независимо от того, что было записано в момент выдачи.

Ошибки

Стандартный конверт ошибки.

КодСтатусКогда
insufficient_scope403У ключа нет packs:read (чтение) или packs:deliver (выдача).
premium_required403План игрового сервера не включает фичу паков/магазина.
not_found404Неизвестный id пака; или discord_id-получатель/фильтр не привязан ни к одному игроку (только для выдачи — фильтры возвращают пустую страницу).
validation_error400Плохой id, оба/ни одного из steam_id и discord_id, или отказ игрового сервера (его сообщение в error.details.mod_message).
conflict409Выдача отклонена: подключённый игровой сервер слишком старый для бесплатной выдачи — он списал бы коины с получателя. Обновите игровой сервер и повторите.
idempotency_conflict409Присланный Idempotency-Key уже использовался с другим телом запроса. Переиспользуйте ключ только для повтора той же самой выдачи.
server_unavailable503Игровой сервер офлайн или недоступен.
gateway_timeout504Сервер не ответил вовремя.

Содержание