К документации
Разработчикам/API Reference
API v1КОНТРАКТ 0.2.0

Ваш проект.
Ваши интеграции.

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

ПРОТОКОЛREST / JSON
ДОСТУПБез API-ключа
МЕТОДЫ6 × GET
СПЕЦИФИКАЦИЯOpenAPI 3.1

Здесь описано публичное чтение. API возвращает конфигурацию, каталог, публичную ленту и статус процесса. Корзины, заказы и выдачу на игровые серверы ведёт отдельный API плагинов по ключу магазина — ключи создаются в кабинете, в разделе «Плагин и API». Платежи через HTTP пока не принимаются.

01 / QUICK START

Первый запрос за пару строк

Получите каталог магазина. Тело запроса и заголовок Authorization не требуются.

БАЗОВЫЙ АДРЕСhttps://adonate.app
НАСТРОЕННЫЙ API
Получить каталог
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/products?store=rust-one' \
  -H "Accept: application/json"

Все примеры используют таймаут клиента 10 секунд. Это рекомендация для примера, а не гарантированное время ответа API. Python-пример использует стандартную библиотеку. C#-пример предназначен для консольного приложения .NET 6+ и не требует сторонних пакетов.

  1. 01

    Уточните игру и валютуВызовите GET /v1/store перед отображением цен.

  2. 02

    Загрузите товарыИспользуйте GET /v1/products и обработайте пустой массив.

  3. 03

    Покажите результатВыберите нужный вариант товара и кэшируйте ответ на своей стороне.

02 / ACCESS

Доступ и окружение

Публичное чтение

API-ключ, Bearer-токен и пользовательская сессия не нужны. Методы не возвращают приватные профили, email или реквизиты платежей. Ключ магазина нужен только API плагинов игровых серверов; методы этого справочника его не принимают, поэтому ограничение запросов здесь считается по IP клиента.

Отдельный backend

Страница /api/ — документация. Локальный API запускается отдельно командой npm run api:dev на порту 3001. Порт сайта 3000 не обслуживает /v1/*.

Запросы из браузера и CORS

Сайт — adonate.app, панель — my.adonate.app, магазины — <slug>.adonate.app. CORS разрешает HTTPS-источники платформы и зарегистрированных магазинов из STORE_REGISTRY, а также точные источники из WEB_ORIGIN. Произвольный поддомен не получает доступ автоматически.

Для браузера разрешены GET, HEAD и OPTIONS; credentialed CORS не включён. Запрос без заголовка Origin — cURL, серверный клиент, мониторинг — механизмом CORS не ограничивается, но лимит запросов действует на него так же.

Для публичной интеграции используйте HTTPS-адрес развёрнутого backend. NEXT_PUBLIC_API_URL задаёт адрес для витрины и примеров на этой странице. API_INTERNAL_URL используется только серверным рендерингом витрины и не должен становиться публичным адресом.

ДемоDATABASE_URL не задан

Каталог из встроенных примеров. Лента возвращает 4 демонстрационные покупки.

База данныхDATABASE_URL задан

Каталог из PostgreSQL. Лента возвращает пустой массив до подключения реальных покупок.

Машиночитаемый контракт

Swagger UI: /docs · OpenAPI JSON: /openapi.json на запущенном сервере API. Схемы Product, Store и PurchaseFeed строятся из общих Zod-контрактов. Межполевые правила для вариантов и шансов описаны ниже: JSON Schema не отражает все проверки.

Оба маршрута монтируются только вне production-режима: при ADONATE_ENV=production процесс их не публикует, поскольку дамп схемы перечисляет все поля и проверки. В Caddy наружу проксируется только /v1/*, так что и в демо-режиме документация доступна лишь на самом процессе API.

03 / ENDPOINTS

Методы API

На домене магазина он определяется по Host; на основном домене передайте ?store=slug. Каталог поддерживает фильтры и пагинацию. В примерах замените demo на slug подключённого магазина. Успешный ответ — 200 application/json.

GET/v1/products/:idProduct#

Отдельный товар

Получите товар по ID в пределах выбранного магазина.

  • Замените :id на ID из каталога, например rust-vip. Параметр store действует так же, как для каталога.
  • Товар другого магазина не подставляется. Если ID отсутствует — 404.
Запрос
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/products/rust-vip?store=rust-one' \
  -H "Accept: application/json"
200Пример ответа

Демонстрационные данные для Rust. Полный ответ метода в демо-режиме.

Ответ /v1/products/:id
{
  "id": "rust-vip",
  "game": "rust",
  "category": "ranks",
  "name": "VIP",
  "subtitle": "Больше, чем просто игрок",
  "price": 290,
  "oldPrice": 390,
  "accent": "silver",
  "image": "crown",
  "features": [
    "Приоритет в очереди",
    "Набор ресурсов раз в сутки",
    "VIP-префикс в чате"
  ],
  "period": "30 дней",
  "popular": 70,
  "defaultVariantId": "days-30",
  "variants": [
    {
      "id": "days-7",
      "label": "7 дней",
      "durationDays": 7,
      "price": 102
    },
    {
      "id": "days-30",
      "label": "30 дней",
      "durationDays": 30,
      "price": 290,
      "oldPrice": 390
    },
    {
      "id": "days-90",
      "label": "90 дней",
      "durationDays": 90,
      "price": 725,
      "oldPrice": 870
    }
  ]
}
GET/v1/readyReadiness#

Готовность хранилища

Проверяет доступность PostgreSQL и наличие столбца store_id после миграции.

  • 200 — хранилище каталога доступно; без DATABASE_URL возвращается mode: bundled.
  • 503 — база или необходимая схема недоступны. Платежи и игровые серверы не проверяются.
Запрос
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/ready' \
  -H "Accept: application/json"
200Пример ответа

Демонстрационные данные для Rust. Полный ответ метода в демо-режиме.

Ответ /v1/ready
{
  "status": "ok",
  "mode": "database"
}
GET/v1/storeStore#

Конфигурация магазина

Получите идентификатор, игру, валюту, навигацию и виджеты магазина. Начните с этого метода, чтобы правильно интерпретировать каталог.

  • Каждый магазин имеет свою игру, ID, slug и адрес https://<slug>.adonate.app. STORE_REGISTRY связывает домен с магазином; два магазина одной игры имеют отдельные каталоги.
  • На домене магазина он определяется автоматически. На adonate.app и my.adonate.app передайте ?store=<slug>. Неизвестный магазин — 404, несовпадение домена и store — 400. Флаг development относится к интерфейсу; источник каталога проверяйте через /v1/health.
  • Изменения из демо-админки хранятся в браузере: этот метод не читает их. Массив серверов отдельным полем Store пока не возвращается.
Запрос
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/store?store=rust-one' \
  -H "Accept: application/json"
200Пример ответа

Демонстрационные данные для Rust. Полный ответ метода в демо-режиме.

Ответ /v1/store
{
  "id": "adonate-rust",
  "name": "aDonate",
  "game": "rust",
  "currency": "KZT",
  "development": false,
  "monitoringEnabled": true,
  "widgets": [
    {
      "id": "community-discord",
      "type": "discord",
      "title": "Discord Community",
      "serverId": "adonate-guild",
      "inviteUrl": "https://discord.gg/adonate",
      "memberCount": 1420,
      "onlineCount": 380
    },
    {
      "id": "community-telegram",
      "type": "telegram",
      "title": "Telegram Channel",
      "url": "https://t.me/adonate",
      "handle": "@adonate",
      "memberCount": 2850
    }
  ],
  "navigation": [
    {
      "id": "contacts",
      "label": {
        "ru": "Контакты",
        "kk": "Байланыс",
        "en": "Contacts",
        "pl": "Kontakt",
        "uk": "Контакти"
      },
      "href": "/seller/",
      "visible": true
    }
  ]
}
GET/v1/productsProduct[]#

Каталог товаров

Получите товары выбранной игры: привилегии, наборы, валюту и рулетки. Ответ — JSON-массив без обёртки data, счётчика total или курсора.

  • Без DATABASE_URL возвращаются 10 демо-товаров выбранной игры. С базой данных — только строки с ID и игрой выбранного магазина. Пустой каталог возвращается как [] со статусом 200.
  • Параметры: category=ranks|kits|currency|roulette; q — поиск по названию и подзаголовку (до 100 символов); sort=popular|price-asc|price-desc|name; limit=1…100; offset=0…100000. Без limit возвращается весь результат. По умолчанию sort=popular и offset=0. Неизвестные, повторные и неверные параметры — 400.
  • Цены — положительные целые числа в единицах валюты магазина: 290 означает 290 ₸ при KZT. Это не тиыны. Конвертации валют и локализации через этот API нет.
  • При выборе варианта используйте его price и oldPrice. defaultVariantId указывает на вариант по умолчанию; если его нет, витрина выбирает первый вариант. При недоступности БД или нарушении схемы ответа возвращается 503.
Запрос
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/products?store=rust-one' \
  -H "Accept: application/json"
200Пример ответаОдин товар из массива

Демонстрационные данные для Rust. Сокращён только массив; объект товара показан целиком.

Ответ /v1/products
[
  {
    "id": "rust-vip",
    "game": "rust",
    "category": "ranks",
    "name": "VIP",
    "subtitle": "Больше, чем просто игрок",
    "price": 290,
    "oldPrice": 390,
    "accent": "silver",
    "image": "crown",
    "features": [
      "Приоритет в очереди",
      "Набор ресурсов раз в сутки",
      "VIP-префикс в чате"
    ],
    "period": "30 дней",
    "popular": 70,
    "defaultVariantId": "days-30",
    "variants": [
      {
        "id": "days-7",
        "label": "7 дней",
        "durationDays": 7,
        "price": 102
      },
      {
        "id": "days-30",
        "label": "30 дней",
        "durationDays": 30,
        "price": 290,
        "oldPrice": 390
      },
      {
        "id": "days-90",
        "label": "90 дней",
        "durationDays": 90,
        "price": 725,
        "oldPrice": 870
      }
    ]
  }
]
GET/v1/purchasesPurchaseFeed#

Лента покупок

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

  • Лента отдаёт только подтверждённые публичные покупки. Пока такие записи не подключены, items пустой в обоих режимах.
  • При заданном DATABASE_URL ответ — { mode: "live", items: [] }. Чтение реальных заказов и публикация покупок пока не подключены; даже mode: live не подтверждает наличие оплаченных заказов.
  • Записи содержат публичный alias, а не SteamID, email или платёжные данные. minutesAgo — относительное число минут, не временная метка. Статусов платежей, сумм и истории заказов в ответе нет.
Запрос
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/purchases?store=rust-one' \
  -H "Accept: application/json"
200Пример ответа

Демонстрационные данные для Rust. Полный ответ метода в демо-режиме.

Ответ /v1/purchases
{
  "mode": "live",
  "items": []
}
GET/v1/healthHealth#

Статус процесса API

Проверьте, что процесс API отвечает, и узнайте выбранный источник каталога. Метод подходит для простой проверки доступности процесса.

  • status: ok означает, что обработчик доступен. Подключения к PostgreSQL и игровым серверам здесь не проверяются. Это liveness-проверка, а не гарантия готовности всех зависимостей.
  • mode: bundled — переменная DATABASE_URL отсутствует; mode: database — задана. При недоступной БД health может вернуть 200, а products — 503.
  • paymentsEnabled всегда false в текущей версии. Доступность метода не означает, что сервис принимает реальные платежи.
Запрос
curl --fail-with-body --max-time 10 \
  'https://adonate.app/v1/health' \
  -H "Accept: application/json"
200Пример ответа

Демонстрационные данные для Rust. Полный ответ метода в демо-режиме.

Ответ /v1/health
{
  "status": "ok",
  "mode": "database",
  "paymentsEnabled": false
}
04 / DATA MODELS

Точные формы данных

Обязательность относится к полям ответа. Публичных методов создания или изменения этих объектов в API нет.

Необязательные поля могут отсутствовать. При чтении БД известные опциональные поля со значением null убираются перед отправкой. Учитывайте дополнительные поля в будущих версиях; не привязывайте клиент к порядку ключей.

ProductТовар каталога
Поля Product
Поле / типОписание
idstringОбязательноеИдентификатор товара. В демо — rust-vip и аналогичные значения; не разбирайте ID как обязательный формат.
gameGameIdОбязательноеИгра магазина. Шесть допустимых значений приведены ниже.
categoryenumОбязательноеranks · kits · currency · roulette. Значение all — фильтр интерфейса и не категория товара.
namestringОбязательноеНазвание товара.
subtitlestringОбязательноеКраткий подзаголовок.
customCopybooleanОпциональноеПризнак собственного текста товара для витрины.
descriptionstringОпциональноеРазвёрнутое описание, до 10 000 символов.
priceinteger > 0ОбязательноеБазовая цена в валюте магазина. Для варианта используется variants[].price.
oldPriceinteger > 0ОпциональноеПредыдущая цена. Проверка oldPrice > price схемой не задаётся.
accentenumОбязательноеsilver · lime · purple · gold — визуальный акцент карточки.
imageenumОбязательноеcrown · chest · roulette — ключ иллюстрации, не URL и не загруженный файл.
badgestringОпциональноеТекст метки на карточке.
featuresstring[]ОбязательноеОсобенности товара. Массив может быть пустым.
periodstringОбязательноеТекст срока или количества: например, «30 дней». Для варианта отображается label.
popularnumberОбязательноеЧисловой показатель для сортировки. Это не количество оплаченных заказов.
layoutenumОпциональноеvertical · horizontal · square. При отсутствии вид выбирается витриной по категории.
variantsProductVariant[]ОпциональноеЕсли передан — минимум один вариант; id внутри массива уникальны.
defaultVariantIdstringОпциональноеНепустой ID существующего элемента variants.
rewardsRouletteReward[]ОпциональноеОбязателен для category: roulette. Минимум одна награда, сумма шансов — 100%.
ProductVariantВариант товара
Поля ProductVariant
Поле / типОписание
idstringОбязательноеНепустой ID, уникальный внутри товара.
labelstringОбязательноеНепустая подпись, например «30 дней» или «5 открытий».
priceinteger > 0ОбязательноеЦена выбранного варианта в валюте магазина.
oldPriceinteger > 0ОпциональноеПредыдущая цена варианта; отсутствие не заменяется базовой oldPrice.
durationDaysinteger > 0ОпциональноеПродолжительность в днях. API не отсчитывает и не активирует срок.
openingsinteger > 0ОпциональноеКоличество открытий. API не запускает розыгрыш награды.
RouletteRewardНаграда рулетки
Поля RouletteReward
Поле / типОписание
idstringОбязательноеНепустой идентификатор награды. Схема не требует совпадения с Product.id.
labelstringОбязательноеНепустое название награды.
chancenumberОбязательноеБольше 0, не больше 100. Сумма chance всех наград — 100 с допуском 0.000001.
StoreКонфигурация магазина
Поля Store
Поле / типОписание
slugstringОпциональноеУникальный поддомен магазина. Служебные имена, включая my, api и www, зарезервированы.
urlstring (HTTPS URL)ОпциональноеКанонический адрес магазина на adonate.app.
idstringОбязательноеНепустой ID магазина; текущий формат конфигурации — adonate-{game}.
namestringОбязательноеНепустое название. По умолчанию aDonate.
gameGameIdОбязательноеОдна игра на магазин. Выбирается на сервере, не параметром запроса.
currencyCurrencyCodeОбязательноеВалюта отображения. Конфигурация этого API возвращает KZT.
developmentbooleanОбязательноеВитрина рисует черновик владельца из браузера, а не конфигурацию сервера. В продакшене всегда false.
monitoringEnabledbooleanОбязательноеФлаг виджета мониторинга. HTTP-метода мониторинга серверов пока нет.
serversobject[]ОпциональноеСозданные владельцем серверы: id — неизменяемый ключ; name — название (1–60 символов); host — IP или домен без протокола и порта (пустая строка скрывает подключение); port — целое 1–65535; visible — видимость на витрине. Пустой список не подменяется готовыми серверами. Черновики кабинета сохраняются в браузере и автоматически в API не публикуются.
widgetsWidget[]ОбязательноеВиджеты сообщества типов discord, telegram, vk или custom.
navigationNavigationItem[]ОбязательноеУпорядоченные ссылки навигации магазина.
PurchaseFeedПубличная лента покупок
Поля PurchaseFeed
Поле / типОписание
modebundled | liveОбязательноеРежим всей ленты; items пока всегда пустой.
itemsRecentPurchase[]ОбязательноеМассив публичных записей, может быть пустым.
items[].idstringОбязательноеИдентификатор записи ленты, не платёжный ID.
items[].productIdstringОбязательноеСсылка на товар каталога.
items[].serverstringОбязательноеНазвание игрового сервера.
items[].aliasstringОбязательноеПубличный псевдоним, до 24 символов.
items[].minutesAgointeger ≥ 0ОбязательноеОтносительное время в минутах; в демо — фиксированные значения.
HealthСтатус процесса
Поля Health
Поле / типОписание
status"ok"ОбязательноеОтвет работающего обработчика. Не проверяет зависимости.
modebundled | databaseОбязательноеВыбранный источник каталога по наличию DATABASE_URL.
paymentsEnabledfalseОбязательноеПриём платежей в этой версии отключён.
WidgetВиджет сообщества
Поля Widget
Поле / типОписание
idstringОбязательноеИдентификатор виджета.
typeenumОбязательноеdiscord · telegram · vk · custom. Определяет набор остальных полей; вложенного поля discord или telegram нет.
titlestringОбязательноеЗаголовок. По умолчанию Discord, Telegram или VKontakte для соответствующего типа; для custom задаётся явно.
serverIdstringОпциональноеТолько discord, присутствует в его ответе. По умолчанию adonate-guild.
inviteUrlstringОпциональноеТолько discord, присутствует в его ответе. Ссылка-приглашение.
memberCountintegerОпциональноеПрисутствует у discord, telegram и vk. Отображаемое количество участников, не результат отдельного метода мониторинга.
onlineCountintegerОпциональноеПрисутствует только у discord. Отображаемое количество онлайн.
urlstringОпциональноеПрисутствует у telegram и vk; необязателен у custom. Ссылка виджета.
handlestringОпциональноеПрисутствует у telegram и vk. Имя сообщества.
descriptionstringОпциональноеНеобязательное описание только для custom.
iconstringОпциональноеНеобязательное обозначение иконки только для custom.
badgestringОпциональноеНеобязательная метка только для custom.
NavigationItemСсылка навигации
Поля NavigationItem
Поле / типОписание
idstringОбязательноеНепустой ID ссылки.
labelstring | objectОбязательноеНепустая строка или объект с обязательным ru и необязательными kk, en, pl, uk.
hrefstringОбязательноеЛокальный путь /…, якорь #… или HTTP(S) URL; без пробелов, обратных слешей и protocol-relative // адресов.
visiblebooleanОбязательноеВидимость ссылки, по умолчанию true.

Игры · GameId

Minecraftminecraft
Rustrust
Unturnedunturned
alt:Valtv
Project Zomboidzomboid
DayZdayz

Валюты · CurrencyCode

Общая схема принимает KZT · RUB · USD · PLN · UAH · USDT · USDC · TON · GRAM · TRX · LTC · BTC · ETH · SOL. Текущая конфигурация API всегда возвращает KZT. Этот список описывает допустимые коды, а не подключённые платёжные способы или сервис обмена валют.

Форматы аккаунта игрока

Эти проверки применяются общей библиотекой витрины. Перечисленные GET-методы не принимают аккаунт игрока, не проверяют его существование и не выполняют вход.

ИграФорматПример
Minecraft3–16 латинских букв, цифр или _Steve_123
alt:V1–10 цифр; первая от 1 до 912345
Rust, Unturned, Zomboid, DayZSteamID64: 17 цифр, начало 765611976561198000000000
05 / LIMITS

Лимиты без мелкого шрифта

Ограничение запросов включено: 120 запросов в минуту по умолчанию, на IP клиента. Тарифных планов и гарантированного SLA по-прежнему нет.

Запросы в минуту

120 по умолчанию

Считается по IP клиента, в скользящем окне 60 секунд, отдельно для каждого процесса API. Для /v1/products лимит строже, для /v1/health — выше; таблица ниже. При превышении возвращается 429 с заголовком Retry-After.

Заголовки лимита

x-ratelimit-*

Каждый ответ несёт остаток и время до сброса окна, поэтому опрашивать лимит отдельным запросом не нужно. Ориентируйтесь на них, а не на подсчёт запросов у себя.

Ключ лимита

IP клиента

Публичные методы работают без ключа, поэтому окно общее для всех клиентов за одним адресом: NAT, корпоративный прокси или CI делят одну квоту. За обратным прокси реальный IP учитывается только при настроенном TRUST_PROXY. Ключ магазина есть только у API плагинов /v1/plugin/*, и там действует ещё и лимит на ключ.

Размер каталога

limit и offset

limit — 1…100, offset — 0…100000. Без limit сохраняется совместимость: возвращается весь каталог магазина, подходящий под фильтры.

Запись данных

Только API плагинов

Методы этого справочника — только GET: они не создают платёж, заказ или выдачу. Корзины, заказы и выдачу игровые серверы ведут через API плагинов по ключу магазина; он описан отдельно и в справочник не входит.

Таймаут API

SLA не установлен

Подключение и выполнение SQL ограничены 5 секундами каждое. Клиенту всё равно следует задавать собственный HTTP-таймаут.

Соединения с БД

До 5 на процесс

Пул PostgreSQL ограничен 5 соединениями на процесс API. Именно его защищает пониженный лимит на /v1/products.

Кэш и повторы

На стороне клиента

API возвращает Cache-Control: no-store и X-Request-Id для поиска запроса в логах; Retry-After приходит с 429. Встроенная витрина считает данные свежими 60 секунд и выполняет одну повторную попытку.

Подписки и события

Недоступны

Нет webhooks, WebSocket и SSE. Лента покупок — обычный GET без потока обновлений; плагины забирают выдачу опросом.

Квоты по методам

ПутьЗапросов / 60 сПочему так
/v1/products60Каждый запрос обращается к PostgreSQL: самый дорогой метод, лимит строже общего.
/v1/health600Liveness-проверка не читает базу; лимит рассчитан на опрос системами мониторинга.
/v1/store, /v1/purchases120Общий лимит. Обе конфигурации кэшируются на стороне клиента и меняются редко.

Заголовки ответа

ЗаголовокКогдаЗначение
x-ratelimit-limitКаждый ответМаксимум запросов в текущем окне для этого пути.
x-ratelimit-remainingКаждый ответСколько запросов осталось до конца окна. 0 — следующий будет 429.
x-ratelimit-resetКаждый ответСекунд до обнуления счётчика.
retry-afterТолько 429Секунд до следующей разрешённой попытки. Используйте это значение, а не фиксированную паузу.

Окно считается независимо каждым процессом API: за балансировщиком фактический предел умножается на число процессов, поэтому не стройте на нём точный учёт. Ключ — IP клиента, так что за NAT или корпоративным прокси квота общая. Реальный адрес учитывается только при заданной переменной TRUST_PROXY: без неё запросы из-за обратного прокси считаются по адресу прокси.

Ограничения значений

  • price, oldPrice, durationDays, openings: положительные целые числа; отдельного бизнес-лимита сверху нет. description — до 10 000 символов; alias — до 24.
  • Если variants или rewards переданы, массив не может быть пустым. Верхний предел длины не задан. ID вариантов уникальны в пределах товара.
  • defaultVariantId должен существовать в variants. У рулеток обязателен массив rewards, а сумма положительных шансов должна быть 100% с допуском 0.000001.
  • minutesAgo — целое число от 0. Значения категорий, игр, оформления и изображений ограничены перечислениями в моделях.
РЕКОМЕНДАЦИЯ ДЛЯ ИНТЕГРАЦИИ

Кэшируйте. Обновляйте осознанно.

Кэш каталога на 60 секунд, одна одновременная загрузка на витрину и таймаут клиента 10 секунд держат обычную витрину на порядок ниже квоты. При 503 или сетевой ошибке — ограниченное число повторов с растущей задержкой; при 429 — пауза ровно на Retry-After. Следите за x-ratelimit-remaining: если он регулярно подходит к нулю, добавьте кэш, а не параллельные запросы.

06 / ERRORS

Ошибки и восстановление

Сначала проверяйте HTTP-статус, затем разбирайте JSON. Прокси может вернуть HTML или оборвать соединение — JSON-тело есть не у каждой ошибки.

200

OKУспешный ответ. Пустые массивы каталога и ленты допустимы.

400

Bad RequestНеверный параметр, не указан store на основном домене или выбранный магазин не соответствует домену запроса.

404

Not FoundНеизвестный магазин, товар или путь. Проверьте домен, slug, ID товара и метод GET.

429

Too Many RequestsПревышен лимит запросов. Дождитесь числа секунд из заголовка Retry-After и повторите — не отправляйте запрос сразу и не наращивайте параллелизм. Тело: statusCode, error, message.

503

Service UnavailableКаталог недоступен: ошибка чтения БД или проверки схемы результата. Повторите позже с задержкой; сохранённый каталог можно показать как устаревший.

NETWORK

Нет доступного HTTP-ответаПроверьте адрес backend, TLS, таймаут и CORS. Не выдавайте такую ошибку за пустой каталог.

Пример 503 от /v1/products
{
  "message": "Catalog is temporarily unavailable",
  "error": "Service Unavailable",
  "statusCode": 503
}
Пример 429 при превышении лимита
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Rate limit exceeded, retry in 42 seconds"
}

Ответы 401, 403 и 422 методами этого справочника не формируются: аутентификации и тел запросов у них нет. Если они приходят, их отдаёт внешний прокси — обрабатывайте отдельно, его правила задаёт оператор. Не выводите игрокам необработанный текст внутренних ошибок.

07 / WHAT’S NEXT

Что пока не входит в API

Эти возможности требуют отдельной реализации. Наличие похожего экрана в демо-панели не означает наличие серверного метода.

Создание магазинов и управление ключами через APIНЕДОСТУПНО
Изменение товаров, промокодов и страницНЕДОСТУПНО
Платежи и возвратыНЕДОСТУПНО
Лента реальных покупокНЕДОСТУПНО
Вебхуки и проверка их подписиНЕДОСТУПНО
Steam OAuth, мониторинг и загрузка файловНЕДОСТУПНО

Префикс /v1 — версия маршрутов, 0.2.0 — текущая версия контракта приложения. Политика сроков поддержки и вывода версий из эксплуатации пока не опубликована. Перед обновлением сверяйте контракт и межполевые правила.

ГОТОВЫ ПОДКЛЮЧИТЬ КАТАЛОГ?

Начните с первого запроса.

К примеру кода