Перейти к содержанию

Документация

API для партнёров

Каталог, покупки, заказы, баланс и уведомления по одному ключу: игровая валюта, подарочные карты, ключи игр, пополнение Steam, Telegram Stars и Premium.

Версия 1.0.0OpenAPI 3.1.0https://easydonat.com/api/v1

Обзор

API даёт вашей программе то же, что кабинет партнёра: каталог с ценами, покупки, статусы заказов, баланс и уведомления о выполнении. Подходит для своего сайта, Telegram-бота или приложения — заказы выдаются автоматически.

Адрес
https://easydonat.com/api/v1
Формат
JSON в UTF-8. Время — ISO 8601 в UTC: 2026-10-21T10:00:00.000Z.
Деньги
Доллары США, строкой: суммы — с 2 знаками ("12.50"), цена единицы (звезды, единицы валюты Steam) — до 9 знаков ("0.0176"). Считайте их как десятичные числа или в центах, не через дробные числа с плавающей точкой.
Оплата
Покупка сразу списывает деньги с баланса. Если заказ не выполнится, деньги вернутся на баланс — статус refunded.
Ключ
В заголовке X-API-Key — см. «Доступ».

Быстрый старт

Пять шагов от ключа до первого выполненного заказа — на примере пополнения игры.

  1. Получите ключ

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

    Терминал
    export EASYDONAT_API_KEY="ed_live_…"
  2. Проверьте баланс

    curl
    curl "https://easydonat.com/api/v1/balance" \
      -H "X-API-Key: $EASYDONAT_API_KEY"
    Ответ 200
    {
      "ok": true,
      "balance": "20.00",
      "currency": "USD"
    }
  3. Выберите товар

    GET /topups — список игр, GET /topups/offers — номиналы игры с ценами и поля, которые нужно спросить у покупателя (например, ID игрока).

    curl
    curl "https://easydonat.com/api/v1/topups/offers?category_id=pubg_mobile_auto" \
      -H "X-API-Key: $EASYDONAT_API_KEY"
  4. Купите

    Передайте Idempotency-Key — тогда повтор запроса не купит второй раз, и max_price_usd — цену, выше которой покупать не нужно. Ключ в примере — для образца: подставьте номер заказа в вашей системе, для каждой новой покупки — новый ключ.

    curl
    curl -X POST "https://easydonat.com/api/v1/topups/order" \
      -H "X-API-Key: $EASYDONAT_API_KEY" \
      -H "Idempotency-Key: order-topup-1001" \
      -H "Content-Type: application/json" \
      -d '{
        "category_id": "pubg_mobile_auto",
        "offer_id": "60_uc",
        "fields": {
          "player_id": "5123456789"
        },
        "max_price_usd": "1.00"
      }'

    Ответ — HTTP 201 и заказ в статусе pending: деньги списаны, заказ выполняется. Оборвалась связь — повторите тот же запрос с тем же Idempotency-Key: вернётся тот же заказ, второго списания не будет.

  5. Узнайте итог

    Статус заказа — в GET /orders/{order_id} или в уведомлении order.completed на ваш адрес (вебхук).

    curl
    curl "https://easydonat.com/api/v1/orders/ED-000123" \
      -H "X-API-Key: $EASYDONAT_API_KEY"
Песочницы пока нет: проверяйте подключение на недорогих заказах. Невыполненный заказ возвращает деньги на баланс.

Доступ

Ключ выглядит как ed_live_ и 32 символа (цифры и буквы a–f). Передавайте его в одном из заголовков:

Заголовки
X-API-Key: ed_live_…
Authorization: Bearer ed_live_…
  • Только в заголовке — никогда в адресе запроса: адреса попадают в журналы серверов. Если переданы оба заголовка, в них должен быть один и тот же ключ.
  • Храните ключ на своём сервере. Не кладите его в код сайта, мобильного приложения или бота, который видят пользователи.
  • Ключи создаются и отзываются в кабинете («Интеграция»), активных — до 10. Полный ключ виден только при создании: мы храним лишь его отпечаток, начало и последние 4 символа, поэтому потерянный ключ не восстановить — создайте новый, а старый отзовите. Отозванный ключ получает 401 unauthorized.
  • Смена пароля и выход из кабинета ключи не отзывают — иначе остановились бы ваши интеграции. Ключ, который мог утечь или больше не нужен, отзовите в «Интеграции».
  • В кабинете видно, когда ключ последний раз использовался (обновляется не чаще раза в минуту).
  • Если аккаунт партнёра отключён, не работает ни один ключ — 403 account_disabled.

Доступ по IP

Необязательная защита на случай утечки ключа: в кабинете можно перечислить до 20 адресов IPv4 и IPv6. Пока список не пуст, запросы с других адресов получают 403 ip_not_allowed.

Ответы и ошибки

Успешный ответ — { "ok": true, … }. Новый заказ — HTTP 201, повтор покупки с тем же Idempotency-Key — HTTP 200 и тот же заказ.

Ошибка — { "ok": false, "error": "…", "code": "…" }, у некоторых кодов — с дополнительными полями. Ветвитесь по code: текст error — пояснение по-русски для людей.

Ответ 402
{
  "ok": false,
  "error": "Недостаточно средств на балансе",
  "code": "insufficient_funds",
  "need_usd": "3.20",
  "balance_usd": "5.60"
}
Коды ошибок
HTTPcodeКогда
400invalid_requestтело не JSON или не той формы, неизвестное поле, неверный параметр
401unauthorizedнет ключа, ключ неверный или отозван
402insufficient_fundsне хватает баланса; доп. поля need_usd (сколько не хватает), balance_usd
403ip_not_allowedзапрос не с разрешённого IP-адреса
403account_disabledаккаунт отключён
404not_foundнет такого товара (по id из каталога), номинала, заказа, записи журнала
409price_changedитог выше max_price_usd; доп. поле total_usd — текущий итог. Деньги не списаны
409idempotency_conflictэтот Idempotency-Key уже использован для другого заказа или итог того заказа выше max_price_usd повтора
422invalid_fieldsполе покупателя не заполнено или неверно; доп. поле field
422product_unavailableтовар или номинал сейчас не продаётся (у Steam, звёзд и Premium — и когда товара сейчас нет в каталоге)
422out_of_stockстолько нет в наличии
422quantity_out_of_rangeколичество или сумма вне пределов; доп. поля min, max
422order_limitсумма заказа больше потолка одного заказа
422recipient_not_foundаккаунт Telegram не найден
422already_premiumу получателя уже есть Telegram Premium
422not_a_userusername принадлежит не пользователю (канал, бот)
429rate_limitedлимит запросов; заголовок Retry-After
503service_unavailableпокупки временно выключены, каталог загружается, выдача на паузе, получателя Telegram сейчас не проверить; Retry-After
500internalсбой у нас; покупку можно повторить с тем же Idempotency-Key
При ответах 4xx и 503 заказ не создаётся и деньги не списываются. При 500 повторите покупку с тем же Idempotency-Key: если заказ успел создаться, вернётся он — второго списания не будет.

Повторы и цена

Защита от двойной покупки

Связь иногда обрывается так, что запрос дошёл, а ответ — нет. Чтобы повтор не купил второй раз, передавайте в каждой покупке заголовок Idempotency-Key — например, номер заказа в вашей системе. Работает на всех покупках, включая Telegram.

Заголовок
Idempotency-Key: my-order-42
  • 8–128 символов: латинские буквы, цифры, - и _. Один ключ — один заказ: для каждой новой покупки — новый ключ, для повтора той же покупки — прежний.
  • Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ в текущем состоянии, без второго списания.
  • Тот же ключ с другим товаром, номиналом, количеством, суммой или значениями полей — 409 idempotency_conflict. Другой max_price_usd — тоже 409, если итог прежнего заказа выше нового потолка; иначе вернётся прежний заказ.
  • Без ключа каждый запрос — новый заказ.
  • Ключи общие для API и кабинета партнёра: ключ, уже использованный в кабинете, в API тоже считается занятым.

Потолок цены

Цены могут меняться. Передайте в теле покупки max_price_usd — например, цену, которую видел покупатель. Если итог заказа выше, заказ не создаётся и деньги не списываются: ответ 409 price_changed, в total_usd — текущий итог. Значение — строка или число, сравнивается с точностью до цента.

Ответ 409
{
  "ok": false,
  "error": "Цена изменилась: было $0.95, стало $0.97",
  "code": "price_changed",
  "total_usd": "0.97"
}

Лимиты

Лимиты запросов
ЧтоЛимит
Все запросы с одним ключом120 в минуту
Покупки30 в минуту на партнёра
Проверка ID игрока — POST /topups/validate-id10 в минуту на партнёра
Проверка получателя Telegram — POST /telegram/recipient20 в минуту на партнёра
Поиск нового получателя Telegram — в проверках и покупках Stars и Premium, API и кабинет вместе10 в минуту на партнёра
Сохранение и проверка вебхука — PUT /account/webhook и POST /account/webhook/test вместе10 в минуту на партнёра

Превышение — 429 rate_limited и заголовок Retry-After: через сколько секунд повторить. С тем же заголовком приходит 503 service_unavailable — например, пока загружается каталог или выдача товара на паузе.

Лимиты в таблице, кроме поиска получателя Telegram, считаются для API отдельно от кабинета: покупки в кабинете их не расходуют. Кроме них есть общие лимиты сервиса на проверки ID игрока и получателя Telegram — одни на всех партнёров. Их превышение — тоже 429 с Retry-After, даже если ваши лимиты не исчерпаны.

Поиск получателя Telegram — ваша доля в общем лимите сервиса, один счётчик на API и кабинет: в него идут проверки получателя и покупки Stars и Premium. Получатель, которого недавно уже искали, берётся из памяти и лимит не тратит, поэтому проверка перед покупкой и сама покупка — один поиск. Пока доля исчерпана, проверка и покупка с новым получателем отклоняются с Retry-After, деньги не списываются.

Каталог не нужно запрашивать перед каждой покупкой: обновляйте его у себя по расписанию, а от изменения цены защитит потолок цены.

Заказ и статусы

Покупка создаёт заказ и сразу списывает деньги. Дальше заказ выполняется в фоне: следите за ним по GET /orders/{order_id} или по вебхукам. Номер заказа — вида ED-000123. В GET /orders есть и заказы, сделанные в кабинете.

Статусы

Статусы заказа
statusЧто значит
pendingПринят, деньги списаны, выполнение ещё не началось.
processingВыполняется.
completedВыполнен. Коды карт и ключи игр — в delivery.codes, выдача текстом — в delivery.text.
failedНе выполнен. Сейчас деньги возвращаются сразу, поэтому такой заказ вы увидите уже в статусе refunded.
refundedНе выполнен, деньги вернулись на баланс. Причина — в failure_reason.

Окончательные статусы — completed и refunded: после них заказ больше не меняется.

Этапы Telegram

У заказов Telegram Stars и Premium есть поле telegram: этап выдачи stage и признак тестового заказа test (звёзды и Premium на самом деле не отправляются, деньги возвращаются на баланс). Итог по-прежнему — статус заказа.

Этапы выдачи Telegram
stageЧто значит
queuedВ очереди.
preparingГотовим отправку.
payingОтправляем.
deliveredВыдано.
checkingЗаказ проверяется вручную.

Объект заказа

Один и тот же объект — в ответах покупок, в GET /orders и в уведомлениях вебхука.

order
{
  "order_id": "ED-000123",
  "status": "completed",
  "kind": "topup",
  "product_id": "topup:pubg_mobile_auto",
  "item_id": "60_uc",
  "product_name": "PUBG Mobile (Auto)",
  "item_name": "60 UC",
  "quantity": 1,
  "amount": null,
  "currency": null,
  "fields": [
    {
      "key": "player_id",
      "label": "Player ID",
      "value": "5123456789"
    }
  ],
  "price_usd": "0.97",
  "total_usd": "0.97",
  "delivery": {
    "codes": [],
    "text": null
  },
  "failure_reason": null,
  "telegram": null,
  "idempotency_key": "my-order-42",
  "channel": "api",
  "created_at": "2026-10-21T10:00:00.000Z",
  "updated_at": "2026-10-21T10:00:05.000Z",
  "completed_at": "2026-10-21T10:00:05.000Z"
}
Поля объекта заказа
ПолеТипОписание
order_idstringНомер заказа EasyDonat.
statusstringpending — принят, деньги списаны, выполнение ещё не началось; processing — выполняется; completed — выполнен; failed — не выполнен, деньги вот-вот вернутся (обычно неудача сразу становится возвратом, и этот статус вы не увидите); refunded — не выполнен или отменён, деньги вернулись на баланс. Окончательные статусы — completed и refunded; о неудаче сообщает order.refunded.
kindstringtopup — пополнение игр; giftcard — подарочная карта; gamekey — ключ игры; steam_topup — пополнение Steam; telegram — Telegram Stars и Premium; manual — услуга, купленная в кабинете (через API v1 не продаётся).
product_idstringid товара: <kind>:<category_id или game_id>; у Steam — steam_topup:wallet, у Telegram — telegram:stars и telegram:premium.
item_idstringНоминал: offer_id, card_id или key_id; у Steam — валюта (RUB…); у звёзд — stars; у Premium — срок в месяцах (3, 6, 12).
product_namestring
item_namestring
quantityintegerКоличество; у пополнений игр, Steam и Telegram — 1.Не меньше 1.
amountnumber | nullУ Steam — сумма в валюте currency; у звёзд Telegram — число звёзд; иначе null.
currencystring | nullУ Steam — валюта кошелька; иначе null.Одно из: RUB, USD, UAH, KZT.
fieldsobject[]Что указал покупатель.
fields[].keystring
fields[].labelstring
fields[].valuestringЧто указал покупатель; у секретных полей — ••••.
price_usdstringЦена за единицу. Доллары США строкой с 2 знаками после точки.
total_usdstringИтог — столько списано с баланса. Доллары США строкой с 2 знаками после точки.
deliveryobject | nullВыдача — только у completed, иначе null. У пополнений игр и Steam товар зачисляется прямо на аккаунт, кодов нет.
delivery.codesobject[]Коды карт и ключи игр; у остальных товаров — пустой список.
delivery.codes[].codestringКод или ключ.
delivery.codes[].pinstring | nullPIN, если есть.
delivery.codes[].serialstring | nullСерийный номер, если есть.
delivery.codes[].notestring | nullПояснение к коду, если есть.
delivery.textstring | nullВыдача текстом (например, у Telegram) или null.
failure_reasonstring | nullПочему заказ не выполнен — по-русски; иначе null.
telegramobject | nullХод выдачи Telegram Stars и Premium; у остальных — null.
telegram.stagestringqueued — в очереди; preparing — готовим отправку; paying — отправляем; delivered — выдано; checking — заказ проверяется вручную.
telegram.testbooleanТестовый заказ: звёзды и Premium на самом деле не отправляются, деньги возвращаются на баланс.
idempotency_keystring | nullIdempotency-Key, с которым создан заказ; без ключа и у заказов из кабинета — null.
channelstringГде создан заказ: через API или в кабинете.Одно из: api, cabinet.
created_atstringВремя в ISO 8601 UTC.
updated_atstringВремя в ISO 8601 UTC.
completed_atstring | nullКогда выполнен; иначе null.

Справочник

Все пути — от адреса https://easydonat.com/api/v1, ключ — в заголовке X-API-Key. В примерах ключ берётся из переменной окружения EASYDONAT_API_KEY, а Idempotency-Key у покупок — для образца: подставляйте свой, новый для каждой покупки. Ошибки 401, 403, 429, 500 и 503 возможны у любого вызова и описаны один раз — в «Ответы и ошибки».

Аккаунт

Данные аккаунта, баланс и движение денег.

Аккаунт

GET/me

Данные аккаунта и итоги: total_orders — число выполненных заказов, total_spent_usd — их сумма.

Пример запроса
curl
curl "https://easydonat.com/api/v1/me" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "id": "3f1c2b9e-6a4d-4c8e-9b7a-2d5e8f0a1c3b",
  "email": "[email protected]",
  "name": "Game Shop",
  "created_at": "2026-09-01T08:00:00.000Z",
  "summary": {
    "total_spent_usd": "152.40",
    "total_orders": 87
  }
}
Поля ответа
Поля ответа «Аккаунт»
ПолеТипОписание
idstringid партнёра.
emailstring
namestring
created_atstringВремя в ISO 8601 UTC.
summaryobject
summary.total_spent_usdstringСумма выполненных заказов. Доллары США строкой с 2 знаками после точки.
summary.total_ordersintegerЧисло выполненных заказов.
Коды ответа
Коды ответа «Аккаунт»
HTTPЧто значит
200Аккаунт.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Баланс

GET/balance

Текущий баланс партнёра в долларах США.

Пример запроса
curl
curl "https://easydonat.com/api/v1/balance" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "balance": "20.00",
  "currency": "USD"
}
Поля ответа
Поля ответа «Баланс»
ПолеТипОписание
balancestringБаланс в долларах США строкой с 2 знаками после точки.
currencystringВсегда USD.
Коды ответа
Коды ответа «Баланс»
HTTPЧто значит
200Баланс.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Движение денег

GET/transactions

Пополнения баланса, оплата заказов, возвраты и корректировки, новые сверху.

Параметры
Параметры вызова «Движение денег»
ПараметрТипОбязательныйОписание
pageв адресеintegerнетНомер страницы, с 1.Не меньше 1.По умолчанию 1.
limitв адресеintegerнетЗаписей на странице.От 1 до 100.По умолчанию 50.
Пример запроса
curl
curl "https://easydonat.com/api/v1/transactions" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "items": [
    {
      "id": 3012,
      "type": "debit",
      "kind": "charge",
      "amount": "0.97",
      "balance_before": "20.97",
      "balance_after": "20.00",
      "order_id": "ED-000123",
      "note": "PUBG Mobile (Auto) — 60 UC",
      "created_at": "2026-10-21T10:00:00.000Z"
    },
    {
      "id": 3011,
      "type": "credit",
      "kind": "topup",
      "amount": "20.00",
      "balance_before": "0.97",
      "balance_after": "20.97",
      "order_id": null,
      "note": "Пополнение баланса",
      "created_at": "2026-10-20T15:30:00.000Z"
    }
  ],
  "total": 2,
  "page": 1,
  "limit": 50
}
Поля ответа
Поля ответа «Движение денег»
ПолеТипОписание
itemsobject[]
items[].idintegerНе меньше 1.
items[].typestringcredit — зачисление, debit — списание.
items[].kindstringtopup — пополнение баланса; charge — оплата заказа; refund — возврат за заказ; adjust — корректировка (например, возврат за тестовый заказ Telegram).
items[].amountstringСумма, всегда положительная; направление — в type. Доллары США строкой с 2 знаками после точки.
items[].balance_beforestringБаланс до записи. Баланс в долларах США строкой с 2 знаками после точки.
items[].balance_afterstringБаланс после записи. Баланс в долларах США строкой с 2 знаками после точки.
items[].order_idstring | nullЗаказ, к которому относится запись, или null.
items[].notestring | nullПояснение по-русски.
items[].created_atstringВремя в ISO 8601 UTC.
totalintegerВсего записей.
pageintegerНе меньше 1.
limitintegerОт 1 до 100.
Коды ответа
Коды ответа «Движение денег»
HTTPЧто значит
200Страница журнала.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
400 · example
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Запись журнала

GET/transactions/{id}

Одна запись движения денег.

Параметры
Параметры вызова «Запись журнала»
ПараметрТипОбязательныйОписание
idв путиintegerдаid записи журнала.Не меньше 1.Пример: 3012.
Пример запроса
curl
curl "https://easydonat.com/api/v1/transactions/3012" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "transaction": {
    "id": 3012,
    "type": "debit",
    "kind": "charge",
    "amount": "0.97",
    "balance_before": "20.97",
    "balance_after": "20.00",
    "order_id": "ED-000123",
    "note": "PUBG Mobile (Auto) — 60 UC",
    "created_at": "2026-10-21T10:00:00.000Z"
  }
}
Поля ответа
Поля ответа «Запись журнала»
ПолеТипОписание
transactionobjectЗапись движения денег.
transaction.idintegerНе меньше 1.
transaction.typestringcredit — зачисление, debit — списание.
transaction.kindstringtopup — пополнение баланса; charge — оплата заказа; refund — возврат за заказ; adjust — корректировка (например, возврат за тестовый заказ Telegram).
transaction.amountstringСумма, всегда положительная; направление — в type. Доллары США строкой с 2 знаками после точки.
transaction.balance_beforestringБаланс до записи. Баланс в долларах США строкой с 2 знаками после точки.
transaction.balance_afterstringБаланс после записи. Баланс в долларах США строкой с 2 знаками после точки.
transaction.order_idstring | nullЗаказ, к которому относится запись, или null.
transaction.notestring | nullПояснение по-русски.
transaction.created_atstringВремя в ISO 8601 UTC.
Коды ответа
Коды ответа «Запись журнала»
HTTPЧто значит
200Запись журнала.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Заказы

Все заказы партнёра — из API и из кабинета, новые сверху.

Список заказов

GET/orders

Заказы партнёра — из API и из кабинета, новые сверху. Можно отобрать по статусу.

Параметры
Параметры вызова «Список заказов»
ПараметрТипОбязательныйОписание
pageв адресеintegerнетНомер страницы, с 1.Не меньше 1.По умолчанию 1.
limitв адресеintegerнетЗаписей на странице.От 1 до 100.По умолчанию 50.
statusв адресеstringнетТолько заказы в этом статусе; не указан — все.Одно из: pending, processing, completed, failed, refunded.
Пример запроса
curl
curl "https://easydonat.com/api/v1/orders" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "items": [
    {
      "order_id": "ED-000123",
      "status": "completed",
      "kind": "topup",
      "product_id": "topup:pubg_mobile_auto",
      "item_id": "60_uc",
      "product_name": "PUBG Mobile (Auto)",
      "item_name": "60 UC",
      "quantity": 1,
      "amount": null,
      "currency": null,
      "fields": [
        {
          "key": "player_id",
          "label": "Player ID",
          "value": "5123456789"
        }
      ],
      "price_usd": "0.97",
      "total_usd": "0.97",
      "delivery": {
        "codes": [],
        "text": null
      },
      "failure_reason": null,
      "telegram": null,
      "idempotency_key": "my-order-42",
      "channel": "api",
      "created_at": "2026-10-21T10:00:00.000Z",
      "updated_at": "2026-10-21T10:00:05.000Z",
      "completed_at": "2026-10-21T10:00:05.000Z"
    },
    {
      "order_id": "ED-000122",
      "status": "completed",
      "kind": "giftcard",
      "product_id": "giftcard:acash_my",
      "item_id": "10_myr",
      "product_name": "A-Cash",
      "item_name": "10 MYR",
      "quantity": 2,
      "amount": null,
      "currency": null,
      "fields": [],
      "price_usd": "2.86",
      "total_usd": "5.72",
      "delivery": {
        "codes": [
          {
            "code": "AC10-7K2M-9QXP-4LDT",
            "pin": null,
            "serial": null,
            "note": null
          },
          {
            "code": "AC10-3H8W-6RZN-1VBE",
            "pin": null,
            "serial": null,
            "note": null
          }
        ],
        "text": null
      },
      "failure_reason": null,
      "telegram": null,
      "idempotency_key": null,
      "channel": "cabinet",
      "created_at": "2026-10-20T18:12:00.000Z",
      "updated_at": "2026-10-20T18:12:09.000Z",
      "completed_at": "2026-10-20T18:12:09.000Z"
    }
  ],
  "total": 2,
  "page": 1,
  "limit": 50
}
Поля ответа
Поля ответа «Список заказов»
ПолеТипОписание
itemsOrder[]
totalintegerВсего заказов (с учётом status).
pageintegerНе меньше 1.
limitintegerОт 1 до 100.
Коды ответа
Коды ответа «Список заказов»
HTTPЧто значит
200Страница заказов.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
400 · example
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Заказ

GET/orders/{order_id}

Один заказ партнёра — источник правды о статусе: после вебхука или обрыва связи проверяйте заказ здесь. Чужой или несуществующий заказ — 404.

Параметры
Параметры вызова «Заказ»
ПараметрТипОбязательныйОписание
order_idв путиstringдаНомер заказа, например ED-000123 (регистр не важен).Пример: ED-000123.
Пример запроса
curl
curl "https://easydonat.com/api/v1/orders/ED-000123" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
{
  "ok": true,
  "order": {
    "order_id": "ED-000123",
    "status": "completed",
    "kind": "topup",
    "product_id": "topup:pubg_mobile_auto",
    "item_id": "60_uc",
    "product_name": "PUBG Mobile (Auto)",
    "item_name": "60 UC",
    "quantity": 1,
    "amount": null,
    "currency": null,
    "fields": [
      {
        "key": "player_id",
        "label": "Player ID",
        "value": "5123456789"
      }
    ],
    "price_usd": "0.97",
    "total_usd": "0.97",
    "delivery": {
      "codes": [],
      "text": null
    },
    "failure_reason": null,
    "telegram": null,
    "idempotency_key": "my-order-42",
    "channel": "api",
    "created_at": "2026-10-21T10:00:00.000Z",
    "updated_at": "2026-10-21T10:00:05.000Z",
    "completed_at": "2026-10-21T10:00:05.000Z"
  }
}
Поля ответа
Поля ответа «Заказ»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Заказ»
HTTPЧто значит
200Заказ.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Пополнение игр

Игровая валюта по ID игрока: номиналы, поля покупателя, проверка ID и покупка.

Игры

GET/topups

Игры с пополнением по ID игрока. Список постраничный: пока meta.has_more — запрашивайте дальше с cursor = meta.next_cursor. Номиналы и поля покупателя — GET /topups/offers.

Параметры
Параметры вызова «Игры»
ПараметрТипОбязательныйОписание
limitв адресеintegerнетЗаписей на странице.От 1 до 500.По умолчанию 200.
cursorв адресеstringнетПродолжение списка — meta.next_cursor из прошлого ответа.
Пример запроса
curl
curl "https://easydonat.com/api/v1/topups" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "kind": "topup",
  "items": [
    {
      "category_id": "pubg_mobile_auto",
      "name": "PUBG Mobile (Auto)",
      "region": "GLOBAL",
      "note": "Region: Global\nAutomatic PUBG Mobile top-up.",
      "imageurl": "https://easydonat.com/media/4e1f0c9a7b2d6e3f8a51.webp",
      "can_validate": true
    }
  ],
  "meta": {
    "next_cursor": "eyJpIjoyMDB9",
    "has_more": true
  }
}
Поля ответа
Поля ответа «Игры»
ПолеТипОписание
kindstringВсегда topup.
itemsobject[]
items[].category_idstring
items[].namestring
items[].regionstring | nullРегион товара, если известен: GLOBAL, BR, CIS, MY…
items[].notestring | nullОписание товара (часто на английском) или null.
items[].imageurlstring | nullКартинка товара (WebP 128×128) на easydonat.com или null.
items[].can_validatebooleanРаботает проверка ID игрока (POST /topups/validate-id).
metaobject
meta.next_cursorstring | nullПередайте в cursor за следующей страницей; null — это всё.
meta.has_morebooleanЕсть ли ещё страницы.
Коды ответа
Коды ответа «Игры»
HTTPЧто значит
200Страница списка игр.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
400 · example
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Номиналы и поля игры

GET/topups/offers

Номиналы игры с ценами и поля, которые нужно спросить у покупателя (ID игрока, зона, сервер…). Ключи полей — ключи объекта fields в покупке.

Параметры
Параметры вызова «Номиналы и поля игры»
ПараметрТипОбязательныйОписание
category_idв адресеstringдаcategory_id игры из GET /topups.Пример: pubg_mobile_auto.
Пример запроса
curl
curl "https://easydonat.com/api/v1/topups/offers?category_id=pubg_mobile_auto" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "category_id": "pubg_mobile_auto",
  "name": "PUBG Mobile (Auto)",
  "note": "Region: Global\nAutomatic PUBG Mobile top-up.",
  "offers": [
    {
      "offer_id": "60_uc",
      "name": "60 UC",
      "price_usd": "0.97",
      "available": true
    },
    {
      "offer_id": "325_uc",
      "name": "325 UC",
      "price_usd": "4.83",
      "available": true
    },
    {
      "offer_id": "660_uc",
      "name": "660 UC",
      "price_usd": "9.66",
      "available": true
    }
  ],
  "fields": [
    {
      "key": "player_id",
      "label": "Player ID",
      "type": "text"
    }
  ]
}
Поля ответа
Поля ответа «Номиналы и поля игры»
ПолеТипОписание
category_idstring
namestring
notestring | nullОписание товара (часто на английском) или null.
offersobject[]
offers[].offer_idstring
offers[].namestring
offers[].price_usdstringДоллары США строкой с 2 знаками после точки.
offers[].availablebooleanМожно ли купить сейчас.
fieldsobject[]Что спросить у покупателя; пустой список — ничего.
fields[].keystringКлюч в объекте fields тела покупки.
fields[].labelstringПодпись поля.
fields[].typestringtext — ввод строки; select — выбор из options.
fields[].optionsobject[]Только у select: передавайте value одного из вариантов. Может не быть.
fields[].options[].valuestringЧто передать в fields.
fields[].options[].labelstringЧто показать покупателю.
Коды ответа
Коды ответа «Номиналы и поля игры»
HTTPЧто значит
200Номиналы и поля.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Где работает проверка ID

GET/topups/validate-id

Игры, для которых работает проверка ID игрока, и ключи полей, которые она проверяет.

Пример запроса
curl
curl "https://easydonat.com/api/v1/topups/validate-id" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "items": [
    {
      "category_id": "pubg_mobile_auto",
      "fields": [
        "player_id"
      ]
    },
    {
      "category_id": "pubg_mobile_fast",
      "fields": [
        "player_id"
      ]
    }
  ]
}
Поля ответа
Поля ответа «Где работает проверка ID»
ПолеТипОписание
itemsobject[]
items[].category_idstring
items[].fieldsstring[]Ключи полей, которые проверяются.
Коды ответа
Коды ответа «Где работает проверка ID»
HTTPЧто значит
200Список игр.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Проверить ID игрока

POST/topups/validate-id

Проверка ID игрока до покупки — без списания денег. valid: null — проверить сейчас не удалось; это не значит, что ID неверный. Лимит — 10 проверок в минуту.

Тело запроса
Тело запроса «Проверить ID игрока»
ПолеТипОбязательноеОписание
category_idstringдаcategory_id игры с can_validate: true.
fieldsobjectдаПоля покупателя: ключ — fields[].key из GET /topups/offers, значение — строка до 128 символов; у select — value одного из вариантов. Каждое поле обязательно, лишние ключи не учитываются.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/topups/validate-id" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "category_id": "pubg_mobile_auto",
    "fields": {
      "player_id": "5123456789"
    }
  }'
Ответ 200
{
  "ok": true,
  "category_id": "pubg_mobile_auto",
  "valid": true,
  "player_name": "ProGamer777"
}
Поля ответа
Поля ответа «Проверить ID игрока»
ПолеТипОписание
category_idstring
validboolean | nulltrue — игрок найден; false — такого игрока нет; null — проверить не удалось (это не «неверно»).
player_namestring | nullИмя игрока, если проверка его вернула.
Коды ответа
Коды ответа «Проверить ID игрока»
HTTPЧто значит
200Итог проверки.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.
422invalid_fields — поле не заполнено или неверно; product_unavailable — для этой игры проверки нет или игра не продаётся.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Купить пополнение

POST/topups/order

Покупка номинала игры. Деньги списываются сразу, заказ выполняется в фоне: следите за статусом через GET /orders/{order_id} или вебхук.

Параметры
Параметры вызова «Купить пополнение»
ПараметрТипОбязательныйОписание
Idempotency-KeyзаголовокstringнетЗащита от двойной покупки (очень рекомендуем): 8–128 символов — латинские буквы, цифры, - и _; один ключ — один заказ. Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ без второго списания; тот же ключ с другим телом — 409 idempotency_conflict. Тело сравнивается по смыслу: товар, номинал, количество, сумма и значения полей покупателя после той же обработки, что у покупки (пробелы по краям, @ и t.me/ у username); поля, которых у товара нет, не учитываются (их отбрасывает и первая покупка). max_price_usd повтора ниже итога прежнего заказа — тоже 409 idempotency_conflict; выше или равен (или его нет) — прежний заказ. Без ключа каждый запрос — новый заказ. Ключи общие для API и кабинета партнёра.Пример: my-order-42.
Тело запроса
Тело запроса «Купить пополнение»
ПолеТипОбязательноеОписание
category_idstringдаcategory_id из GET /topups.
offer_idstringдаoffer_id из GET /topups/offers этой игры.
fieldsobjectдаПоля покупателя: ключ — fields[].key из GET /topups/offers, значение — строка до 128 символов; у select — value одного из вариантов. Каждое поле обязательно, лишние ключи не учитываются.
max_price_usdstring | numberнетПотолок итога заказа в долларах — строка или число. Итог выше — 409 price_changed, деньги не списаны. Сравнивается с точностью до цента.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/topups/order" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Idempotency-Key: order-topup-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "category_id": "pubg_mobile_auto",
    "offer_id": "60_uc",
    "fields": {
      "player_id": "5123456789"
    },
    "max_price_usd": "1.00"
  }'
Ответ 201
PUBG Mobile 60 UC — заказ принят
{
  "ok": true,
  "order": {
    "order_id": "ED-000123",
    "status": "pending",
    "kind": "topup",
    "product_id": "topup:pubg_mobile_auto",
    "item_id": "60_uc",
    "product_name": "PUBG Mobile (Auto)",
    "item_name": "60 UC",
    "quantity": 1,
    "amount": null,
    "currency": null,
    "fields": [
      {
        "key": "player_id",
        "label": "Player ID",
        "value": "5123456789"
      }
    ],
    "price_usd": "0.97",
    "total_usd": "0.97",
    "delivery": null,
    "failure_reason": null,
    "telegram": null,
    "idempotency_key": "my-order-42",
    "channel": "api",
    "created_at": "2026-10-21T10:00:00.000Z",
    "updated_at": "2026-10-21T10:00:00.000Z",
    "completed_at": null
  }
}
Поля ответа
Поля ответа «Купить пополнение»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Купить пополнение»
HTTPЧто значит
200Повтор с тем же Idempotency-Key и тем же телом — прежний заказ в текущем состоянии, без второго списания.
201Заказ создан, деньги списаны.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
402insufficient_funds — не хватает баланса: need_usd — сколько не хватает, balance_usd — текущий баланс. Деньги не списаны.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.
409price_changed — итог выше max_price_usd, в total_usd — текущий итог; idempotency_conflict — этот Idempotency-Key уже использован для другого заказа (другие товар, номинал, количество, сумма или поля) или итог того заказа выше max_price_usd повтора. Деньги не списаны.
422invalid_fields — поле покупателя не заполнено или неверно; product_unavailable — игра или номинал сейчас не продаётся. Деньги не списаны.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Подарочные карты

Карты и ваучеры. Коды приходят в order.delivery.codes, когда заказ выполнен.

Подарочные карты

GET/giftcards

Виды подарочных карт. Список постраничный: пока meta.has_more — запрашивайте дальше с cursor = meta.next_cursor. Номиналы — GET /giftcards/cards.

Параметры
Параметры вызова «Подарочные карты»
ПараметрТипОбязательныйОписание
limitв адресеintegerнетЗаписей на странице.От 1 до 500.По умолчанию 200.
cursorв адресеstringнетПродолжение списка — meta.next_cursor из прошлого ответа.
Пример запроса
curl
curl "https://easydonat.com/api/v1/giftcards" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "kind": "giftcard",
  "items": [
    {
      "category_id": "acash_my",
      "name": "A-Cash",
      "region": "MY",
      "note": "Region: MY\nA-Cash Malaysia gift cards.\nCodes can be safely stored and redeemed later.",
      "imageurl": null
    }
  ],
  "meta": {
    "next_cursor": null,
    "has_more": false
  }
}
Поля ответа
Поля ответа «Подарочные карты»
ПолеТипОписание
kindstringВсегда giftcard.
itemsobject[]
items[].category_idstring
items[].namestring
items[].regionstring | nullРегион товара, если известен: GLOBAL, BR, CIS, MY…
items[].notestring | nullОписание товара (часто на английском) или null.
items[].imageurlstring | nullКартинка товара (WebP 128×128) на easydonat.com или null.
metaobject
meta.next_cursorstring | nullПередайте в cursor за следующей страницей; null — это всё.
meta.has_morebooleanЕсть ли ещё страницы.
Коды ответа
Коды ответа «Подарочные карты»
HTTPЧто значит
200Страница списка карт.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
400 · example
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Номиналы карты

GET/giftcards/cards

Номиналы карты с ценами, остатком и пределами количества в одном заказе.

Параметры
Параметры вызова «Номиналы карты»
ПараметрТипОбязательныйОписание
category_idв адресеstringдаcategory_id карты из GET /giftcards.Пример: acash_my.
Пример запроса
curl
curl "https://easydonat.com/api/v1/giftcards/cards?category_id=acash_my" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "category_id": "acash_my",
  "name": "A-Cash",
  "note": "Region: MY\nA-Cash Malaysia gift cards.\nCodes can be safely stored and redeemed later.",
  "offers": [
    {
      "card_id": "10_myr",
      "name": "10 MYR",
      "price_usd": "2.86",
      "stock": 100,
      "min_order_quantity": 1,
      "max_order_quantity": 100,
      "available": true
    },
    {
      "card_id": "20_myr",
      "name": "20 MYR",
      "price_usd": "5.71",
      "stock": 100,
      "min_order_quantity": 1,
      "max_order_quantity": 100,
      "available": true
    }
  ]
}
Поля ответа
Поля ответа «Номиналы карты»
ПолеТипОписание
category_idstring
namestring
notestring | nullОписание товара (часто на английском) или null.
offersobject[]
offers[].card_idstring
offers[].namestring
offers[].price_usdstringДоллары США строкой с 2 знаками после точки.
offers[].stockinteger | nullОстаток; null — не сообщается.
offers[].min_order_quantityintegerМинимум штук в одном заказе.Не меньше 1.
offers[].max_order_quantityintegerМаксимум штук в одном заказе (не больше 100 и не больше остатка).Не меньше 1.
offers[].availablebooleanМожно ли купить сейчас.
Коды ответа
Коды ответа «Номиналы карты»
HTTPЧто значит
200Номиналы.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Купить карты

POST/giftcards/order

Покупка одной или нескольких карт одного номинала. Деньги списываются сразу; коды — в order.delivery.codes, когда заказ completed.

Параметры
Параметры вызова «Купить карты»
ПараметрТипОбязательныйОписание
Idempotency-KeyзаголовокstringнетЗащита от двойной покупки (очень рекомендуем): 8–128 символов — латинские буквы, цифры, - и _; один ключ — один заказ. Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ без второго списания; тот же ключ с другим телом — 409 idempotency_conflict. Тело сравнивается по смыслу: товар, номинал, количество, сумма и значения полей покупателя после той же обработки, что у покупки (пробелы по краям, @ и t.me/ у username); поля, которых у товара нет, не учитываются (их отбрасывает и первая покупка). max_price_usd повтора ниже итога прежнего заказа — тоже 409 idempotency_conflict; выше или равен (или его нет) — прежний заказ. Без ключа каждый запрос — новый заказ. Ключи общие для API и кабинета партнёра.Пример: my-order-42.
Тело запроса
Тело запроса «Купить карты»
ПолеТипОбязательноеОписание
category_idstringдаcategory_id из GET /giftcards.
card_idstringдаcard_id из GET /giftcards/cards этой карты.
quantityintegerдаСколько карт; в пределах min_order_quantity…max_order_quantity и остатка.От 1 до 100.
max_price_usdstring | numberнетПотолок итога заказа в долларах — строка или число. Итог выше — 409 price_changed, деньги не списаны. Сравнивается с точностью до цента.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/giftcards/order" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Idempotency-Key: order-giftcard-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "category_id": "acash_my",
    "card_id": "10_myr",
    "quantity": 2,
    "max_price_usd": "6.00"
  }'
Ответ 201
A-Cash 10 MYR × 2 — заказ принят
{
  "ok": true,
  "order": {
    "order_id": "ED-000128",
    "status": "pending",
    "kind": "giftcard",
    "product_id": "giftcard:acash_my",
    "item_id": "10_myr",
    "product_name": "A-Cash",
    "item_name": "10 MYR",
    "quantity": 2,
    "amount": null,
    "currency": null,
    "fields": [],
    "price_usd": "2.86",
    "total_usd": "5.72",
    "delivery": null,
    "failure_reason": null,
    "telegram": null,
    "idempotency_key": "cards-acash-7",
    "channel": "api",
    "created_at": "2026-10-21T11:00:00.000Z",
    "updated_at": "2026-10-21T11:00:00.000Z",
    "completed_at": null
  }
}
Поля ответа
Поля ответа «Купить карты»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Купить карты»
HTTPЧто значит
200Повтор с тем же Idempotency-Key и тем же телом — прежний заказ в текущем состоянии, без второго списания.
201Заказ создан, деньги списаны.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
402insufficient_funds — не хватает баланса: need_usd — сколько не хватает, balance_usd — текущий баланс. Деньги не списаны.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.
409price_changed — итог выше max_price_usd, в total_usd — текущий итог; idempotency_conflict — этот Idempotency-Key уже использован для другого заказа (другие товар, номинал, количество, сумма или поля) или итог того заказа выше max_price_usd повтора. Деньги не списаны.
422product_unavailable — карта или номинал сейчас не продаётся; out_of_stock — столько нет в наличии; quantity_out_of_range — количество вне пределов номинала (min, max). Деньги не списаны.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Ключи игр

Ключи активации игр. Ключи приходят в order.delivery.codes, когда заказ выполнен.

Игры с ключами

GET/gamekeys

Игры с ключами — в том числе те, чьи издания сейчас не продаются: можно ли купить издание, видно по available в GET /gamekeys/keys. Список постраничный: пока meta.has_more — запрашивайте дальше с cursor = meta.next_cursor. Издания и цены — GET /gamekeys/keys.

Параметры
Параметры вызова «Игры с ключами»
ПараметрТипОбязательныйОписание
limitв адресеintegerнетЗаписей на странице.От 1 до 500.По умолчанию 200.
cursorв адресеstringнетПродолжение списка — meta.next_cursor из прошлого ответа.
Пример запроса
curl
curl "https://easydonat.com/api/v1/gamekeys" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "kind": "gamekey",
  "items": [
    {
      "game_id": "7_days_to_die_global",
      "name": "7 Days to Die",
      "region": "GLOBAL",
      "platform": "Steam",
      "imageurl": "https://easydonat.com/media/9b0d2e7c4a1f6e3d5c88.webp"
    }
  ],
  "meta": {
    "next_cursor": null,
    "has_more": false
  }
}
Поля ответа
Поля ответа «Игры с ключами»
ПолеТипОписание
kindstringВсегда gamekey.
itemsobject[]
items[].game_idstring
items[].namestring
items[].regionstring | nullРегион товара, если известен: GLOBAL, BR, CIS, MY…
items[].platformstring | nullГде активируется ключ: Steam, Xbox, Rockstar…
items[].imageurlstring | nullКартинка товара (WebP 128×128) на easydonat.com или null.
metaobject
meta.next_cursorstring | nullПередайте в cursor за следующей страницей; null — это всё.
meta.has_morebooleanЕсть ли ещё страницы.
Коды ответа
Коды ответа «Игры с ключами»
HTTPЧто значит
200Страница списка игр.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
400 · example
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Ключи игры

GET/gamekeys/keys

Издания игры с ценами, остатком и пределами количества в одном заказе.

Параметры
Параметры вызова «Ключи игры»
ПараметрТипОбязательныйОписание
game_idв адресеstringдаgame_id игры из GET /gamekeys.Пример: 7_days_to_die_global.
Пример запроса
curl
curl "https://easydonat.com/api/v1/gamekeys/keys?game_id=7_days_to_die_global" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "game_id": "7_days_to_die_global",
  "name": "7 Days to Die",
  "region": "GLOBAL",
  "platform": "Steam",
  "keys": [
    {
      "key_id": "7_days_to_die",
      "name": "7 Days to Die",
      "price_usd": "18.07",
      "stock": 121,
      "min_order_quantity": 1,
      "max_order_quantity": 100,
      "available": true
    }
  ]
}
Поля ответа
Поля ответа «Ключи игры»
ПолеТипОписание
game_idstring
namestring
regionstring | nullРегион товара, если известен: GLOBAL, BR, CIS, MY…
platformstring | null
keysobject[]
keys[].key_idstring
keys[].namestring
keys[].price_usdstringДоллары США строкой с 2 знаками после точки.
keys[].stockinteger | nullОстаток; null — не сообщается.
keys[].min_order_quantityintegerМинимум штук в одном заказе.Не меньше 1.
keys[].max_order_quantityintegerМаксимум штук в одном заказе (не больше 100 и не больше остатка).Не меньше 1.
keys[].availablebooleanМожно ли купить сейчас.
Коды ответа
Коды ответа «Ключи игры»
HTTPЧто значит
200Ключи игры.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Купить ключи

POST/gamekeys/order

Покупка одного или нескольких ключей одного издания. Деньги списываются сразу; ключи — в order.delivery.codes, когда заказ completed.

Параметры
Параметры вызова «Купить ключи»
ПараметрТипОбязательныйОписание
Idempotency-KeyзаголовокstringнетЗащита от двойной покупки (очень рекомендуем): 8–128 символов — латинские буквы, цифры, - и _; один ключ — один заказ. Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ без второго списания; тот же ключ с другим телом — 409 idempotency_conflict. Тело сравнивается по смыслу: товар, номинал, количество, сумма и значения полей покупателя после той же обработки, что у покупки (пробелы по краям, @ и t.me/ у username); поля, которых у товара нет, не учитываются (их отбрасывает и первая покупка). max_price_usd повтора ниже итога прежнего заказа — тоже 409 idempotency_conflict; выше или равен (или его нет) — прежний заказ. Без ключа каждый запрос — новый заказ. Ключи общие для API и кабинета партнёра.Пример: my-order-42.
Тело запроса
Тело запроса «Купить ключи»
ПолеТипОбязательноеОписание
game_idstringдаgame_id из GET /gamekeys.
key_idstringдаkey_id из GET /gamekeys/keys этой игры.
quantityintegerдаСколько ключей; в пределах min_order_quantity…max_order_quantity и остатка.От 1 до 100.
max_price_usdstring | numberнетПотолок итога заказа в долларах — строка или число. Итог выше — 409 price_changed, деньги не списаны. Сравнивается с точностью до цента.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/gamekeys/order" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Idempotency-Key: order-gamekey-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "game_id": "7_days_to_die_global",
    "key_id": "7_days_to_die",
    "quantity": 1,
    "max_price_usd": "18.50"
  }'
Ответ 201
Ключ 7 Days to Die — заказ принят
{
  "ok": true,
  "order": {
    "order_id": "ED-000129",
    "status": "pending",
    "kind": "gamekey",
    "product_id": "gamekey:7_days_to_die_global",
    "item_id": "7_days_to_die",
    "product_name": "7 Days to Die",
    "item_name": "7 Days to Die",
    "quantity": 1,
    "amount": null,
    "currency": null,
    "fields": [],
    "price_usd": "18.07",
    "total_usd": "18.07",
    "delivery": null,
    "failure_reason": null,
    "telegram": null,
    "idempotency_key": "key-7dtd-1",
    "channel": "api",
    "created_at": "2026-10-21T11:10:00.000Z",
    "updated_at": "2026-10-21T11:10:00.000Z",
    "completed_at": null
  }
}
Поля ответа
Поля ответа «Купить ключи»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Купить ключи»
HTTPЧто значит
200Повтор с тем же Idempotency-Key и тем же телом — прежний заказ в текущем состоянии, без второго списания.
201Заказ создан, деньги списаны.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
402insufficient_funds — не хватает баланса: need_usd — сколько не хватает, balance_usd — текущий баланс. Деньги не списаны.
404not_found — нет такого товара (по id из каталога), номинала, заказа или записи журнала.
409price_changed — итог выше max_price_usd, в total_usd — текущий итог; idempotency_conflict — этот Idempotency-Key уже использован для другого заказа (другие товар, номинал, количество, сумма или поля) или итог того заказа выше max_price_usd повтора. Деньги не списаны.
422product_unavailable — игра или издание сейчас не продаётся; out_of_stock — столько нет в наличии; quantity_out_of_range — количество вне пределов (min, max). Деньги не списаны.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Пополнение Steam

Пополнение кошелька Steam по логину на любую сумму в RUB, USD, UAH или KZT.

Цены пополнения Steam

GET/steam-topup/rates

Валюты кошелька Steam, цена 1 единицы валюты в долларах и пределы суммы. Итог заказа считает сервер: примерно amount × usd_per_unit, вверх до цента (не выше этой оценки).

Пример запроса
curl
curl "https://easydonat.com/api/v1/steam-topup/rates" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "base": "USD",
  "currencies": [
    {
      "currency": "RUB",
      "usd_per_unit": "0.013159444",
      "min_amount": 100,
      "max_amount": 100000
    },
    {
      "currency": "USD",
      "usd_per_unit": "1.1",
      "min_amount": 1,
      "max_amount": 1000
    },
    {
      "currency": "UAH",
      "usd_per_unit": "0.024471189",
      "min_amount": 50,
      "max_amount": 50000
    },
    {
      "currency": "KZT",
      "usd_per_unit": "0.002425579",
      "min_amount": 500,
      "max_amount": 500000
    }
  ]
}
Поля ответа
Поля ответа «Цены пополнения Steam»
ПолеТипОписание
basestringВ чём списываются деньги.Всегда USD.
currenciesobject[]
currencies[].currencystringВалюта кошелька Steam.Одно из: RUB, USD, UAH, KZT.
currencies[].usd_per_unitstringСколько долларов спишется за 1 единицу валюты. Цена единицы в долларах США строкой, до 9 знаков после точки.
currencies[].min_amountnumberНаименьшая сумма пополнения в этой валюте.
currencies[].max_amountnumberНаибольшая сумма пополнения в этой валюте.
Коды ответа
Коды ответа «Цены пополнения Steam»
HTTPЧто значит
200Валюты и цены.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Пополнить Steam

POST/steam-topup/order

Пополнение кошелька Steam по логину на сумму в выбранной валюте. Деньги списываются сразу, итог — в order.total_usd. Если Steam не примет логин, заказ не выполнится и деньги вернутся на баланс.

Параметры
Параметры вызова «Пополнить Steam»
ПараметрТипОбязательныйОписание
Idempotency-KeyзаголовокstringнетЗащита от двойной покупки (очень рекомендуем): 8–128 символов — латинские буквы, цифры, - и _; один ключ — один заказ. Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ без второго списания; тот же ключ с другим телом — 409 idempotency_conflict. Тело сравнивается по смыслу: товар, номинал, количество, сумма и значения полей покупателя после той же обработки, что у покупки (пробелы по краям, @ и t.me/ у username); поля, которых у товара нет, не учитываются (их отбрасывает и первая покупка). max_price_usd повтора ниже итога прежнего заказа — тоже 409 idempotency_conflict; выше или равен (или его нет) — прежний заказ. Без ключа каждый запрос — новый заказ. Ключи общие для API и кабинета партнёра.Пример: my-order-42.
Тело запроса
Тело запроса «Пополнить Steam»
ПолеТипОбязательноеОписание
steamLoginstringдаЛогин аккаунта Steam (не имя профиля), до 128 символов.
currencystringдаВалюта кошелька Steam.Одно из: RUB, USD, UAH, KZT.
amountnumberдаСумма пополнения в валюте currency, не больше 2 знаков после точки; в пределах min_amount…max_amount из GET /steam-topup/rates.Больше 0.
max_price_usdstring | numberнетПотолок итога заказа в долларах — строка или число. Итог выше — 409 price_changed, деньги не списаны. Сравнивается с точностью до цента.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/steam-topup/order" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Idempotency-Key: order-steam-topup-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "steamLogin": "example_login",
    "currency": "RUB",
    "amount": 500,
    "max_price_usd": "7.00"
  }'
Ответ 201
Steam 500 RUB — заказ принят
{
  "ok": true,
  "order": {
    "order_id": "ED-000124",
    "status": "pending",
    "kind": "steam_topup",
    "product_id": "steam_topup:wallet",
    "item_id": "RUB",
    "product_name": "Steam",
    "item_name": "500 RUB",
    "quantity": 1,
    "amount": 500,
    "currency": "RUB",
    "fields": [
      {
        "key": "steamLogin",
        "label": "Логин Steam",
        "value": "example_login"
      }
    ],
    "price_usd": "6.58",
    "total_usd": "6.58",
    "delivery": null,
    "failure_reason": null,
    "telegram": null,
    "idempotency_key": "steam-500-rub-1",
    "channel": "api",
    "created_at": "2026-10-21T10:05:00.000Z",
    "updated_at": "2026-10-21T10:05:00.000Z",
    "completed_at": null
  }
}
Поля ответа
Поля ответа «Пополнить Steam»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Пополнить Steam»
HTTPЧто значит
200Повтор с тем же Idempotency-Key и тем же телом — прежний заказ в текущем состоянии, без второго списания.
201Заказ создан, деньги списаны.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
402insufficient_funds — не хватает баланса: need_usd — сколько не хватает, balance_usd — текущий баланс. Деньги не списаны.
409price_changed — итог выше max_price_usd, в total_usd — текущий итог; idempotency_conflict — этот Idempotency-Key уже использован для другого заказа (другие товар, номинал, количество, сумма или поля) или итог того заказа выше max_price_usd повтора. Деньги не списаны.
422invalid_fields — логин не указан или неверен (field: steamLogin); quantity_out_of_range — сумма вне пределов валюты (min, max); product_unavailable — пополнение в этой валюте или пополнение Steam вообще сейчас недоступно (тогда и GET /steam-topup/rates отдаёт пустой currencies). Деньги не списаны.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Telegram

Telegram Stars и Telegram Premium по username. Получатель проверяется до списания денег: не найден — 422, деньги не списаны; заказ создаётся в статусе pending. Поисков получателя у Telegram (мимо кеша) — не больше 10 в минуту на партнёра, вместе с кабинетом и покупками; сверх — проверка отвечает 429, покупка — 503 service_unavailable с Retry-After, деньги не списаны.

Цена звёзд

GET/telegram/stars

Цена одной звезды и сколько звёзд можно купить одним заказом. Итог заказа — quantity × price_per_star, вверх до цента.

Пример запроса
curl
curl "https://easydonat.com/api/v1/telegram/stars" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "kind": "telegram_stars",
  "price_per_star": "0.0176",
  "min_amount": 50,
  "max_amount": 11363
}
Поля ответа
Поля ответа «Цена звёзд»
ПолеТипОписание
kindstringВсегда telegram_stars.
price_per_starstringЦена одной звезды. Цена единицы в долларах США строкой, до 9 знаков после точки.
min_amountintegerНаименьшее число звёзд в заказе.Не меньше 1.
max_amountintegerНаибольшее число звёзд в заказе (с учётом потолка суммы одного заказа).Не меньше 1.
Коды ответа
Коды ответа «Цена звёзд»
HTTPЧто значит
200Цена и пределы.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Цены Premium

GET/telegram/premium

Сроки Telegram Premium и их цены.

Пример запроса
curl
curl "https://easydonat.com/api/v1/telegram/premium" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "kind": "telegram_premium",
  "plans": [
    {
      "months": 3,
      "price_usd": "12.66",
      "available": true
    },
    {
      "months": 6,
      "price_usd": "17.31",
      "available": true
    },
    {
      "months": 12,
      "price_usd": "31.25",
      "available": true
    }
  ]
}
Поля ответа
Поля ответа «Цены Premium»
ПолеТипОписание
kindstringВсегда telegram_premium.
plansobject[]
plans[].monthsintegerСрок Telegram Premium в месяцах.Одно из: 3, 6, 12.
plans[].price_usdstringДоллары США строкой с 2 знаками после точки.
plans[].availablebooleanМожно ли купить сейчас.
Коды ответа
Коды ответа «Цены Premium»
HTTPЧто значит
200Сроки и цены.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Проверить получателя

POST/telegram/recipient

Проверка получателя до покупки — без списания денег: есть ли такой аккаунт и может ли он получить звёзды или Premium. found: null — проверить сейчас нельзя (в том числе пока Telegram выдаётся вручную). Лимит — 20 проверок в минуту; из них поисков у Telegram мимо кеша — не больше 10 в минуту на партнёра, вместе с кабинетом и покупками (сверх — 429).

Тело запроса
Тело запроса «Проверить получателя»
ПолеТипОбязательноеОписание
telegram_usernamestringдаUsername получателя: с @ или без, можно ссылкой t.me/…; 5–32 символа — латинские буквы, цифры и _.
productstringдаЧто собираетесь купить.Одно из: stars, premium.
monthsintegerнетТолько для premium: срок. Срок Telegram Premium в месяцах.Одно из: 3, 6, 12.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/telegram/recipient" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "telegram_username": "@example_user",
    "product": "premium",
    "months": 3
  }'
Ответ 200
{
  "ok": true,
  "found": true,
  "name": "Example User",
  "message": null
}
Поля ответа
Поля ответа «Проверить получателя»
ПолеТипОписание
foundboolean | nulltrue — можно покупать; false — нельзя (аккаунт не найден, уже есть Premium, это канал или бот — см. message); null — проверить сейчас нельзя.
namestring | nullИмя получателя в Telegram, если найден.
messagestring | nullПояснение по-русски, если купить нельзя или проверка не удалась.
Коды ответа
Коды ответа «Проверить получателя»
HTTPЧто значит
200Итог проверки.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
422invalid_fields — username неверного вида (field: telegram_username); product_unavailable — товар сейчас не продаётся (звёзды сняты с продажи, срок Premium недоступен).

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Купить звёзды

POST/telegram/stars/buy

Покупка Telegram Stars для username. Получатель проверяется до списания денег. Выдача идёт в фоне: этап — в order.telegram.stage, итог — статус заказа.

Параметры
Параметры вызова «Купить звёзды»
ПараметрТипОбязательныйОписание
Idempotency-KeyзаголовокstringнетЗащита от двойной покупки (очень рекомендуем): 8–128 символов — латинские буквы, цифры, - и _; один ключ — один заказ. Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ без второго списания; тот же ключ с другим телом — 409 idempotency_conflict. Тело сравнивается по смыслу: товар, номинал, количество, сумма и значения полей покупателя после той же обработки, что у покупки (пробелы по краям, @ и t.me/ у username); поля, которых у товара нет, не учитываются (их отбрасывает и первая покупка). max_price_usd повтора ниже итога прежнего заказа — тоже 409 idempotency_conflict; выше или равен (или его нет) — прежний заказ. Без ключа каждый запрос — новый заказ. Ключи общие для API и кабинета партнёра.Пример: my-order-42.
Тело запроса
Тело запроса «Купить звёзды»
ПолеТипОбязательноеОписание
telegram_usernamestringдаUsername получателя: с @ или без, можно ссылкой t.me/…; 5–32 символа — латинские буквы, цифры и _.
quantityintegerдаЧисло звёзд; в пределах min_amount…max_amount из GET /telegram/stars.Не меньше 50.
max_price_usdstring | numberнетПотолок итога заказа в долларах — строка или число. Итог выше — 409 price_changed, деньги не списаны. Сравнивается с точностью до цента.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/telegram/stars/buy" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Idempotency-Key: order-telegram-stars-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "telegram_username": "@example_user",
    "quantity": 500,
    "max_price_usd": "9.00"
  }'
Ответ 201
500 звёзд — заказ принят
{
  "ok": true,
  "order": {
    "order_id": "ED-000125",
    "status": "pending",
    "kind": "telegram",
    "product_id": "telegram:stars",
    "item_id": "stars",
    "product_name": "Telegram Stars",
    "item_name": "500 звёзд",
    "quantity": 1,
    "amount": 500,
    "currency": null,
    "fields": [
      {
        "key": "username",
        "label": "Username в Telegram",
        "value": "example_user"
      }
    ],
    "price_usd": "8.80",
    "total_usd": "8.80",
    "delivery": null,
    "failure_reason": null,
    "telegram": {
      "stage": "queued",
      "test": false
    },
    "idempotency_key": "stars-500-1",
    "channel": "api",
    "created_at": "2026-10-21T10:10:00.000Z",
    "updated_at": "2026-10-21T10:10:00.000Z",
    "completed_at": null
  }
}
Поля ответа
Поля ответа «Купить звёзды»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Купить звёзды»
HTTPЧто значит
200Повтор с тем же Idempotency-Key и тем же телом — прежний заказ в текущем состоянии, без второго списания.
201Заказ создан, деньги списаны.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
402insufficient_funds — не хватает баланса: need_usd — сколько не хватает, balance_usd — текущий баланс. Деньги не списаны.
409price_changed — итог выше max_price_usd, в total_usd — текущий итог; idempotency_conflict — этот Idempotency-Key уже использован для другого заказа (другие товар, номинал, количество, сумма или поля) или итог того заказа выше max_price_usd повтора. Деньги не списаны.
422invalid_fields — username неверного вида (field: telegram_username); quantity_out_of_range — число звёзд вне пределов (min, max — те же, что min_amount и max_amount в GET /telegram/stars: максимум уже с потолком суммы одного заказа); order_limit — даже минимум звёзд дороже потолка одного заказа; recipient_not_found — аккаунт не найден; not_a_user — username принадлежит каналу или боту; product_unavailable — звёзды сейчас не продаются. Деньги не списаны.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Подарить Premium

POST/telegram/premium/buy

Подарок Telegram Premium на 3, 6 или 12 месяцев для username. Получатель проверяется до списания денег. Выдача идёт в фоне: этап — в order.telegram.stage, итог — статус заказа.

Параметры
Параметры вызова «Подарить Premium»
ПараметрТипОбязательныйОписание
Idempotency-KeyзаголовокstringнетЗащита от двойной покупки (очень рекомендуем): 8–128 символов — латинские буквы, цифры, - и _; один ключ — один заказ. Повтор с тем же ключом и тем же телом — HTTP 200 и прежний заказ без второго списания; тот же ключ с другим телом — 409 idempotency_conflict. Тело сравнивается по смыслу: товар, номинал, количество, сумма и значения полей покупателя после той же обработки, что у покупки (пробелы по краям, @ и t.me/ у username); поля, которых у товара нет, не учитываются (их отбрасывает и первая покупка). max_price_usd повтора ниже итога прежнего заказа — тоже 409 idempotency_conflict; выше или равен (или его нет) — прежний заказ. Без ключа каждый запрос — новый заказ. Ключи общие для API и кабинета партнёра.Пример: my-order-42.
Тело запроса
Тело запроса «Подарить Premium»
ПолеТипОбязательноеОписание
telegram_usernamestringдаUsername получателя: с @ или без, можно ссылкой t.me/…; 5–32 символа — латинские буквы, цифры и _.
monthsintegerдаСрок Telegram Premium в месяцах.Одно из: 3, 6, 12.
max_price_usdstring | numberнетПотолок итога заказа в долларах — строка или число. Итог выше — 409 price_changed, деньги не списаны. Сравнивается с точностью до цента.
Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/telegram/premium/buy" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Idempotency-Key: order-telegram-premium-1001" \
  -H "Content-Type: application/json" \
  -d '{
    "telegram_username": "example_user",
    "months": 3,
    "max_price_usd": "12.66"
  }'
Ответ 201
Premium на 3 месяца — заказ принят
{
  "ok": true,
  "order": {
    "order_id": "ED-000126",
    "status": "pending",
    "kind": "telegram",
    "product_id": "telegram:premium",
    "item_id": "3",
    "product_name": "Telegram Premium",
    "item_name": "3 месяца",
    "quantity": 1,
    "amount": null,
    "currency": null,
    "fields": [
      {
        "key": "username",
        "label": "Username в Telegram",
        "value": "example_user"
      }
    ],
    "price_usd": "12.66",
    "total_usd": "12.66",
    "delivery": null,
    "failure_reason": null,
    "telegram": {
      "stage": "queued",
      "test": false
    },
    "idempotency_key": "premium-3m-1",
    "channel": "api",
    "created_at": "2026-10-21T10:20:00.000Z",
    "updated_at": "2026-10-21T10:20:00.000Z",
    "completed_at": null
  }
}
Поля ответа
Поля ответа «Подарить Premium»
ПолеТипОписание
orderOrderЗаказ партнёра.
Коды ответа
Коды ответа «Подарить Premium»
HTTPЧто значит
200Повтор с тем же Idempotency-Key и тем же телом — прежний заказ в текущем состоянии, без второго списания.
201Заказ создан, деньги списаны.
400invalid_request — тело не JSON или не той формы, неизвестное поле, неверный параметр или заголовок Idempotency-Key.
402insufficient_funds — не хватает баланса: need_usd — сколько не хватает, balance_usd — текущий баланс. Деньги не списаны.
409price_changed — итог выше max_price_usd, в total_usd — текущий итог; idempotency_conflict — этот Idempotency-Key уже использован для другого заказа (другие товар, номинал, количество, сумма или поля) или итог того заказа выше max_price_usd повтора. Деньги не списаны.
422invalid_fields — username неверного вида (field: telegram_username); recipient_not_found — аккаунт не найден; already_premium — у получателя уже есть Premium; not_a_user — username принадлежит каналу или боту; order_limit — сумма больше потолка одного заказа; product_unavailable — этот срок сейчас не продаётся. Деньги не списаны.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Некорректные данные заказа",
  "code": "invalid_request"
}

Вебхук

Уведомления о смене статуса заказов на ваш адрес (PUT /account/webhook): order.processing, order.completed и order.refunded (так приходит и неудача: заказ не выполнен, деньги вернулись), а также webhook.test. Подпись, повторы и пример проверки — в разделе «Вебхуки».

Настройки вебхука

GET/account/webhook

Адрес, секрет подписи и состояние доставок. Не настроен — webhook: null.

Пример запроса
curl
curl "https://easydonat.com/api/v1/account/webhook" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "webhook": {
    "url": "https://shop.example.com/hooks/easydonat",
    "enabled": true,
    "secret": "whsec_0123456789abcdef0123456789abcdef",
    "consecutive_failures": 0,
    "last_success_at": "2026-10-21T10:00:05.400Z",
    "last_failure_at": null,
    "last_failure_reason": null,
    "created_at": "2026-10-20T09:00:00.000Z",
    "updated_at": "2026-10-20T09:00:00.000Z"
  }
}
Поля ответа
Поля ответа «Настройки вебхука»
ПолеТипОписание
webhookobject | null
webhook.urlstring
webhook.enabledbooleanОтправляются ли уведомления.
webhook.secretstringСекрет подписи уведомлений. Храните его так же бережно, как ключ API.
webhook.consecutive_failuresintegerНеудачных попыток подряд: считается каждая попытка, в том числе повторы одного события и проверки webhook.test; удачная попытка обнуляет счётчик, смена адреса — тоже.
webhook.last_success_atstring | null
webhook.last_failure_atstring | null
webhook.last_failure_reasonstring | nullПочему не удалась последняя неудачная попытка.
webhook.created_atstringВремя в ISO 8601 UTC.
webhook.updated_atstringВремя в ISO 8601 UTC.
Коды ответа
Коды ответа «Настройки вебхука»
HTTPЧто значит
200Вебхук или null.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Сохранить вебхук

PUT/account/webhook

Создать вебхук или сменить адрес и включение. При первом сохранении создаётся секрет подписи whsec_…. Уведомления приходят о каждой следующей смене статуса — в том числе у заказов, созданных раньше и ещё не завершённых; о прошлых сменах уведомлений не будет. Без enabled: у нового вебхука — включён, у существующего — прежнее значение. Адрес проверяется (в том числе по DNS) при каждом сохранении.

Тело запроса
Тело запроса «Сохранить вебхук»
ПолеТипОбязательноеОписание
urlstringдаТолько https://, порт 443 (по умолчанию) или 8443, без логина и пароля в адресе, не длиннее 2048 символов (после кодирования: не-ASCII в пути считается как %XX), не на частные, локальные и служебные адреса.
enabledbooleanнетВключить или выключить отправку уведомлений.
Пример запроса
curl
curl -X PUT "https://easydonat.com/api/v1/account/webhook" \
  -H "X-API-Key: $EASYDONAT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://shop.example.com/hooks/easydonat",
    "enabled": true
  }'
Ответ 200
JSON
{
  "ok": true,
  "webhook": {
    "url": "https://shop.example.com/hooks/easydonat",
    "enabled": true,
    "secret": "whsec_0123456789abcdef0123456789abcdef",
    "consecutive_failures": 0,
    "last_success_at": null,
    "last_failure_at": null,
    "last_failure_reason": null,
    "created_at": "2026-10-20T09:00:00.000Z",
    "updated_at": "2026-10-20T09:00:00.000Z"
  }
}
Поля ответа
Поля ответа «Сохранить вебхук»
ПолеТипОписание
webhookobject | null
webhook.urlstring
webhook.enabledbooleanОтправляются ли уведомления.
webhook.secretstringСекрет подписи уведомлений. Храните его так же бережно, как ключ API.
webhook.consecutive_failuresintegerНеудачных попыток подряд: считается каждая попытка, в том числе повторы одного события и проверки webhook.test; удачная попытка обнуляет счётчик, смена адреса — тоже.
webhook.last_success_atstring | null
webhook.last_failure_atstring | null
webhook.last_failure_reasonstring | nullПочему не удалась последняя неудачная попытка.
webhook.created_atstringВремя в ISO 8601 UTC.
webhook.updated_atstringВремя в ISO 8601 UTC.
Коды ответа
Коды ответа «Сохранить вебхук»
HTTPЧто значит
200Вебхук сохранён.
400invalid_request — тело не той формы или адрес не подходит (не https://, порт не 443 и не 8443, логин и пароль в адресе, длиннее 2048 символов — считая уже закодированные символы не латиницей, частный или локальный адрес).

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
400 · example
{
  "ok": false,
  "error": "Адрес вебхука должен начинаться с https://",
  "code": "invalid_request"
}

Удалить вебхук

DELETE/account/webhook

Удаляет вебхук и останавливает отправку уведомлений.

Пример запроса
curl
curl -X DELETE "https://easydonat.com/api/v1/account/webhook" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true
}
Коды ответа
Коды ответа «Удалить вебхук»
HTTPЧто значит
200Вебхук удалён.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Новый секрет

POST/account/webhook/secret/regenerate

Создаёт новый секрет подписи. Старый перестаёт действовать сразу — обновите его у себя: уведомления, которые ещё не ушли, будут подписаны новым. Тело запроса не нужно: пустое тело принимается при любом Content-Type, {} — тоже; другое тело — 400.

Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/account/webhook/secret/regenerate" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "secret": "whsec_fedcba9876543210fedcba9876543210"
}
Поля ответа
Поля ответа «Новый секрет»
ПолеТипОписание
secretstring
Коды ответа
Коды ответа «Новый секрет»
HTTPЧто значит
200Новый секрет.
400invalid_request — тело не пустое и не {}: у этого вызова параметров нет. Не JSON — «Ожидается JSON (Content-Type: application/json)», JSON с полями (или не объект) — «Тело запроса не нужно: пустое или {}».
404not_found — вебхук не настроен.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Тело запроса не нужно: пустое или {}",
  "code": "invalid_request"
}

Проверить вебхук

POST/account/webhook/test

Одна отправка события webhook.test на ваш адрес, без повторов. Итог отправки — всегда HTTP 200: ok — ответил ли ваш адрес кодом 2xx. Тело запроса не нужно: пустое тело принимается при любом Content-Type, {} — тоже; другое тело — 400.

Пример запроса
curl
curl -X POST "https://easydonat.com/api/v1/account/webhook/test" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
{
  "ok": true,
  "status": 200,
  "error": null
}
Поля ответа
Поля ответа «Проверить вебхук»
ПолеТипОписание
okbooleanОтветил ли ваш адрес кодом 2xx.
statusinteger | nullHTTP-статус ответа; null — ответа не было.
errorstring | nullЧто пошло не так.
Коды ответа
Коды ответа «Проверить вебхук»
HTTPЧто значит
200Итог отправки.
400invalid_request — тело не пустое и не {}: у этого вызова параметров нет. Не JSON — «Ожидается JSON (Content-Type: application/json)», JSON с полями (или не объект) — «Тело запроса не нужно: пустое или {}».
404not_found — вебхук не настроен.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Примеры ответов с ошибкой
{
  "ok": false,
  "error": "Тело запроса не нужно: пустое или {}",
  "code": "invalid_request"
}

Журнал доставок

GET/account/webhook/deliveries

Последние 50 доставок уведомлений, новые сверху.

Пример запроса
curl
curl "https://easydonat.com/api/v1/account/webhook/deliveries" \
  -H "X-API-Key: $EASYDONAT_API_KEY"
Ответ 200
JSON
{
  "ok": true,
  "items": [
    {
      "id": 1043,
      "event": "order.completed",
      "event_id": "evt_3b1f6c2a9d8e4f70",
      "order_id": "ED-000123",
      "attempt": 1,
      "status": "delivered",
      "response_status": 200,
      "duration_ms": 184,
      "error": null,
      "created_at": "2026-10-21T10:00:05.000Z",
      "next_retry_at": null
    },
    {
      "id": 1042,
      "event": "order.processing",
      "event_id": "evt_8a4c1e7f2b9d6035",
      "order_id": "ED-000124",
      "attempt": 2,
      "status": "pending",
      "response_status": 500,
      "duration_ms": 92,
      "error": "Ответ HTTP 500",
      "created_at": "2026-10-21T10:05:03.000Z",
      "next_retry_at": "2026-10-21T10:11:03.000Z"
    }
  ]
}
Поля ответа
Поля ответа «Журнал доставок»
ПолеТипОписание
itemsobject[]Последние 50 доставок, новые сверху.До 50 элементов.
items[].idintegerid доставки — как в заголовке X-EasyDonat-Delivery.Не меньше 1.
items[].eventstringorder.processing, order.completed, order.refunded — заказ перешёл в этот статус (order.refunded — заказ не выполнен и деньги вернулись: отдельного события о неудаче нет); webhook.test — проверка вебхука.
items[].event_idstringid события — как id в теле уведомления.
items[].order_idstring | nullЗаказ события; у webhook.test — null.
items[].attemptintegerНомер попытки, 1–9. Если ваш адрес не ответил вовсе (DNS, соединение, таймаут), попытка засчитывается и остальным доставкам, которые ждали отправки, — без отправки (в error так и написано): срок 9 попыток идёт от события.От 1 до 9.
items[].statusstringpending — ждёт отправки или повтора; delivered — ваш адрес ответил 2xx; failed — все попытки неудачны, либо доставка отменена (по заказу поставлено событие о новом статусе, вебхук удалён) или проверка прервалась — причина в error.
items[].response_statusinteger | nullHTTP-статус ответа; null — ответа не было.
items[].duration_msinteger | nullСколько длилась отправка, мс.
items[].errorstring | nullЧто пошло не так.
items[].created_atstringВремя в ISO 8601 UTC.
items[].next_retry_atstring | nullКогда следующий повтор; null — повторов больше не будет.
Коды ответа
Коды ответа «Журнал доставок»
HTTPЧто значит
200Доставки.

Ещё возможны общие ошибки 401, 403, 429, 500, 503 — они одинаковы у всех вызовов, см. «Ответы и ошибки».

Вебхуки

Вебхук — уведомление на ваш адрес, когда меняется статус заказа: созданного через API или в кабинете. С ним не нужно постоянно опрашивать GET /orders.

Как подключить

  1. Сохраните адрес в кабинете («Интеграция») или вызовом PUT /account/webhook. При первом сохранении создаётся секрет подписи whsec_… — он виден в кабинете и в GET /account/webhook.
  2. Проверьте адрес: POST /account/webhook/test отправит событие webhook.test один раз, без повторов.
  3. Что и когда отправлялось — в журнале последних 50 доставок: GET /account/webhook/deliveries.

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

Адрес — только https:// на порту 443 (по умолчанию) или 8443, без логина и пароля, не длиннее 2048 символов (символы не латиницей в пути считаются в закодированном виде %XX), не на частные, локальные и служебные адреса: это проверяется при сохранении и при каждой отправке. Редиректы не выполняются.

События

События вебхука
typeКогда приходит
order.processingЗаказ начал выполняться. Приходит при смене статуса любого заказа партнёра — из API и из кабинета. Подпись, повторы и сроки ответа — в описании раздела «Вебхук».
order.completedЗаказ выполнен; коды карт и ключи — в data.order.delivery.
order.refundedДеньги за заказ вернулись на баланс партнёра: заказ не выполнен или отменён, причина — в data.order.failure_reason. Это и есть уведомление о неудаче: отдельного события о статусе failed нет — неудача сразу становится возвратом.
webhook.testОтправляется по POST /account/webhook/test один раз, без повторов. Подписана так же, как остальные события.

Отдельного события о сбое нет: если заказ не выполнился, деньги сразу возвращаются на баланс и приходит order.refunded, причина — в data.order.failure_reason.

Запрос

POST на ваш адрес с телом в JSON (Content-Type: application/json) и заголовками:

Заголовки уведомления
ЗаголовокЧто в нём
X-EasyDonat-EventТип события — то же, что type в теле.
X-EasyDonat-Deliveryid доставки — как id в журнале доставок (GET /account/webhook/deliveries). У всех попыток одного события он один и тот же, номер попытки — attempt в журнале.
X-EasyDonat-Signaturet=<unix-время>,v1=<hex> — подпись: HMAC-SHA256 с секретом вебхука от строки <t>.<сырое тело запроса>. Как проверять — ниже.
Поля тела уведомления
ПолеТипОписание
idstringid события. Одно событие может прийти больше одного раза — отсеивайте повторы по нему, а сами смены статуса обрабатывайте идемпотентно по паре (order_id, status).
typestringorder.processing, order.completed, order.refunded — заказ перешёл в этот статус (order.refunded — заказ не выполнен и деньги вернулись: отдельного события о неудаче нет); webhook.test — проверка вебхука.
created_atstringВремя в ISO 8601 UTC.
dataobjectУ событий order.* — заказ на момент отправки: в повторе type остаётся исходным, а data.order.status — текущий (заказ мог успеть выполниться). Статус берите из data.order.status и обрабатывайте идемпотентно по паре (order_id, status): два события с разными id могут нести один и тот же статус — второе пропускайте. Как только по заказу поставлено событие о новом статусе, прежнее недоставленное отменяется. У webhook.test поля order может не быть.
data.orderOrderЗаказ партнёра. Может не быть.
{
  "id": "evt_8a4c1e7f2b9d6035",
  "type": "order.processing",
  "created_at": "2026-10-21T10:05:03.000Z",
  "data": {
    "order": {
      "order_id": "ED-000124",
      "status": "processing",
      "kind": "steam_topup",
      "product_id": "steam_topup:wallet",
      "item_id": "RUB",
      "product_name": "Steam",
      "item_name": "500 RUB",
      "quantity": 1,
      "amount": 500,
      "currency": "RUB",
      "fields": [
        {
          "key": "steamLogin",
          "label": "Логин Steam",
          "value": "example_login"
        }
      ],
      "price_usd": "6.58",
      "total_usd": "6.58",
      "delivery": null,
      "failure_reason": null,
      "telegram": null,
      "idempotency_key": "steam-500-rub-1",
      "channel": "api",
      "created_at": "2026-10-21T10:05:00.000Z",
      "updated_at": "2026-10-21T10:05:03.000Z",
      "completed_at": null
    }
  }
}

Проверка подписи

Подпись доказывает, что уведомление отправили мы и его не изменили по дороге. Проверяйте её у каждого запроса:

  1. Возьмите сырое тело запроса — байты как пришли, до разбора JSON.
  2. Из заголовка X-EasyDonat-Signature: t=…,v1=… достаньте t (время отправки, секунды Unix) и v1.
  3. Посчитайте HMAC-SHA256 от строки <t>.<сырое тело>. Ключ — секрет вебхука целиком, вместе с whsec_; результат — 64 шестнадцатеричных символа.
  4. Сравните результат с v1 сравнением за постоянное время (timingSafeEqual, hash_equals, hmac.compare_digest), а не обычным ==.
  5. Отклоните запрос, если t отличается от текущего времени больше чем на 5 минут: так перехваченный запрос не повторить позже.
// Node.js 18+ и Express. Сохраните как .mjs или добавьте "type": "module" в package.json — код на import.
import crypto from "node:crypto";
import express from "express";

const TOLERANCE_SEC = 5 * 60; // запросы старше 5 минут отклоняем
const SECRET_RE = /^whsec_[0-9a-f]{32}$/; // секрет вебхука: «whsec_» и 32 символа 0–9, a–f

/** rawBody — тело запроса как есть (Buffer), до JSON.parse. */
function verifySignature(rawBody, header, secret) {
  // Пустой или искажённый секрет — ошибка настройки, а не чужая подпись: HMAC с пустым ключом посчитает кто угодно.
  if (typeof secret !== "string" || !SECRET_RE.test(secret)) {
    throw new Error("Секрет вебхука не задан или не похож на whsec_…");
  }
  const parts = {};
  for (const item of String(header ?? "").split(",")) {
    const i = item.indexOf("=");
    if (i > 0) parts[item.slice(0, i).trim()] = item.slice(i + 1).trim();
  }
  const t = Number(parts.t);
  if (!Number.isInteger(t) || !/^[0-9a-f]{64}$/.test(parts.v1 ?? "")) return false;
  if (Math.abs(Date.now() / 1000 - t) > TOLERANCE_SEC) return false;

  // Ключ HMAC — секрет целиком, вместе с «whsec_».
  const expected = crypto.createHmac("sha256", secret).update(`${t}.`).update(rawBody).digest();
  return crypto.timingSafeEqual(expected, Buffer.from(parts.v1, "hex"));
}

const SECRET = process.env.EASYDONAT_WEBHOOK_SECRET; // whsec_…
const app = express();

async function handleEvent(event) {
  // Ваша обработка: event.type — что случилось, event.data.order — заказ на момент отправки.
}

// express.raw — тело байт в байт: после разбора и обратной сборки JSON подпись не сойдётся.
app.post("/hooks/easydonat", express.raw({ type: "application/json" }), (req, res) => {
  // Секрет не задан — verifySignature бросит исключение, и Express ответит 500.
  if (!verifySignature(req.body, req.get("X-EasyDonat-Signature"), SECRET)) {
    return res.status(400).send("bad signature");
  }
  const event = JSON.parse(req.body.toString("utf8"));
  res.sendStatus(200); // ответить нужно за 10 секунд — заказ обрабатываем уже после ответа

  // Одно событие может прийти дважды: пропускайте уже обработанные event.id.
  // Источник правды — GET /orders/{order_id}.
  handleEvent(event).catch(console.error);
});

app.listen(3000);
После POST /account/webhook/secret/regenerate старый секрет перестаёт действовать сразу — в том числе для повторов. Обновите секрет у себя сразу после смены.

Ответ и повторы

Ответьте любым кодом 2xx в течение 10 секунд — доставка засчитана. Тяжёлую обработку делайте после ответа. Иначе уведомление придёт снова — через столько после предыдущей попытки:

  1. 1сразу
  2. 2+1 мин
  3. 3+5 мин
  4. 4+15 мин
  5. 5+1 ч
  6. 6+3 ч
  7. 7+6 ч
  8. 8+12 ч
  9. 9+24 ч
  • Всего 9 попыток, после последней неудачной доставка — failed (видно в журнале доставок).
  • Каждая попытка подписана заново — со свежим t, поэтому окно в 5 минут повторам не мешает.
  • Одно событие может прийти больше одного раза — отсеивайте повторы по id события: он одинаков у всех попыток. X-EasyDonat-Delivery у всех попыток одного события тоже один и тот же — это номер доставки в журнале, а номер попытки там — attempt. Повтор уже обработанного события — не ошибка: ответьте на него 2xx.
  • Если статус заказа сменился дважды между отправками, может прийти только последнее событие.
  • Источник правды — GET /orders/{order_id}: при сомнениях сверяйтесь с ним.

Переход с другого API

Если ваша интеграция уже работает с API автодоната с теми же разделами (/topups, /giftcards, /gamekeys, /steam-topup, /telegram), переход займёт немного времени: пути, имена полей и формат ответов совпадают — обычно достаточно сменить адрес и ключ.

Что совпадает

  • Поля покупок: category_id, offer_id, fields, game_id, key_id, card_id, quantity, steamLogin, currency, amount, telegram_username, months.
  • Ответ { "ok": true, … }, ошибка { "ok": false, "error": … }, ключ — в X-API-Key или Authorization: Bearer.
  • Каталог — постранично через limit и cursor, пока meta.has_more.
  • Вебхук — те же вызовы /account/webhook: сохранить, новый секрет, проверка, журнал доставок.

Что добавили

На что обратить внимание

  • Все покупки отвечают HTTP 201, повтор с тем же Idempotency-Key — HTTP 200.
  • Номер заказа — вида ED-000123.
  • Деньги — в долларах США, строками: суммы с 2 знаками, цена единицы — до 9 знаков.
  • Steam: GET /steam-topup/rates отдаёт currencies[] с usd_per_unit — нашей ценой за единицу валюты, а не курсом обмена. Итог заказа считает сервер.
  • Картинка товара imageurl приходит сразу, полным адресом.
  • У GET /me и GET /transactions — свои поля, см. «Аккаунт».

Чего пока нет

  • Тестовых ключей (песочницы).
  • Ручных услуг, подарков в Steam и проверки логина Steam.
  • Пополнения баланса через API — баланс пополняется в кабинете.

OpenAPI

Машинное описание API — OpenAPI 3.1.0, версия 1.0.0. Его можно открыть в Postman или Insomnia и по нему собрать клиент для своего языка.

Терминал
curl -O https://easydonat.com/docs/openapi.json

История изменений

  1. 1.0.0
    • Первая версия API для партнёров: каталог, покупки игровой валюты, подарочных карт, ключей игр, пополнение Steam, Telegram Stars и Premium.
    • Заказы и статусы, баланс и движение денег.
    • Защита от двойной покупки Idempotency-Key, потолок цены max_price_usd, перечисленные коды ошибок.
    • Подписанные вебхуки с повторами, доступ по IP, проверка получателя Telegram до покупки.

Ещё нет ключа?

Ключ API выдаётся в кабинете партнёра. Оставьте заявку — расскажем об условиях и откроем доступ.