Документация GamesDrop API
# GamesDrop API — официальная документация (Русский)
## 1. Общая информация
API связывает ботов, приложения и партнёрские магазины с GamesDrop. Все ответы — в формате JSON.
- Base URL: `https://gamesdrop.org/api/v1`
- Аутентификация: `Authorization: Bearer GD_API_KEY` (ключ выглядит как `gd_live_xxxxxxxxxxxx.secret`)
- Content-Type: `application/json`
- Отправляйте запросы с сервера. Никогда не размещайте ключ в браузере или клиентском приложении.
- Для создания заказа обязателен заголовок `Idempotency-Key`: 8–128 печатаемых ASCII-символов (рекомендуется UUID). Для каждого нового заказа используйте новый ключ. Тот же ключ сохраняйте только для безопасного повтора точно такого же запроса.
- В каждом ответе есть заголовок `X-Request-Id`. Передайте его в поддержку при обращении.
- Текст `error` предназначен для людей и может быть на таджикском. Строите логику всегда на поле `code` и HTTP-статусе, а не на тексте.
## 2. Получение API-ключа
Откройте раздел **API** в личном кабинете GamesDrop и создайте ключ. Полное значение показывается только один раз. Храните его в окружении сервера. Если ключ раскрыт, отзовите его и создайте новый.
## 3. Каталог и цены
ID категорий (`rg-...`) и ID предложений (`rgp-...`) — непрозрачные строки. Всегда берите их из каталога; не составляйте и не угадывайте их. Значения `categoryId` и `offerId` в примерах ниже — только заполнители.
### `GET /catalog`
Возвращает активные категории. Необязательные параметры: `q`, `limit` (1–100, по умолчанию 50) и `offset`.
```bash
curl 'https://gamesdrop.org/api/v1/catalog?limit=50' \
-H 'Authorization: Bearer GD_API_KEY'
```
Пример ответа:
```json
{"ok":true,"total":1,"categories":[{"id":"rg-XXXX","kind":"topup","title":"Free Fire — SG"}]}
```
### `GET /catalog/{id}`
Возвращает детали категории, обязательные поля ввода, предложения и цены. `priceTjs` — ваша партнёрская цена. `retailPriceTjs` — рекомендуемая розничная цена, может быть `null`. Цены могут меняться, обновляйте их перед заказом.
Список `fields` точно показывает, какие ключи нужно передать в `fields` при проверке ID или создании заказа (например `gameUserId`). Отсутствующий ключ даёт `400 missing_field`.
```json
{"ok":true,"category":{"id":"rg-XXXX","kind":"topup","title":"Free Fire — SG","fields":[{"key":"gameUserId","label":"Player ID","type":"text","options":null}],"idCheckField":"gameUserId","offers":[{"offerId":"rgp-XXXX","title":"110 Diamonds","priceTjs":"8.75","retailPriceTjs":null}],"steamTopup":null}}
```
Для обычных категорий `steamTopup` равен `null`. Для категории, поддерживающей пополнение Steam на сумму, это объект:
- `minUsd`, `maxUsd` — допустимый диапазон суммы в USD
- `tjsPerUsd` — ваш курс: TJS за 1 USD (ваш уровень цен уже учтён)
- `noFeeFromUsd`, `tjsPerUsdNoFee` — необязательно; лучший курс для сумм от `noFeeFromUsd`
## 4. Проверка ID игрока
### `POST /check-id`
Запрос (ключ берите из `idCheckField`):
```json
{"categoryId":"rg-XXXX","fields":{"gameUserId":"123456789"}}
```
Пример ответа:
```json
{"ok":true,"valid":true,"playerName":"PlayerOne","region":"SG"}
```
`valid:true` — ID подтверждён. `valid:false` — ID не подтверждён: он неверный, относится к другому региону или игру нельзя проверить. `503 check_unavailable_now` означает, что проверка временно недоступна; это не значит, что ID неверный.
## 5. Создание заказа
### `POST /orders`
Заголовки:
```http
Authorization: Bearer GD_API_KEY
Content-Type: application/json
Idempotency-Key: НОВЫЙ-UUID
```
Обычный товар:
```json
{"categoryId":"rg-XXXX","offerId":"rgp-XXXX","fields":{"gameUserId":"123456789"}}
```
Пополнение Steam (только для категорий, где `steamTopup` не `null`; иначе `400 invalid_request`):
```json
{"categoryId":"STEAM_CATEGORY_ID","amountUsd":20,"fields":{"login":"steamlogin"}}
```
`amountUsd` — число (не строка), больше 0, не более 2 знаков после точки, в пределах `minUsd`–`maxUsd`. Не передавайте `offerId` вместе с `amountUsd`. В ответе на заказ Steam `offerId` равен `null`, а `amountUsd` возвращается. Точная цена — в `order.priceTjs`; из-за округления она может отличаться от `amountUsd × tjsPerUsd` не более чем на 0.01 TJS.
Пример ответа:
```json
{"ok":true,"order":{"id":"UUID","number":128,"categoryId":"rg-XXXX","offerId":"rgp-XXXX","priceTjs":"8.75","status":"processing","delivery":null,"error":null,"createdAt":"2026-10-11T10:00:00Z","completedAt":null}}
```
Стоимость заказа списывается с внутреннего баланса GamesDrop. При недостатке средств API вернёт `402 insufficient_balance`, и заказ не будет создан.
Идемпотентность: повтор запроса с тем же `Idempotency-Key` и тем же телом возвращает исходный заказ (или исходную ошибку) и не создаёт второй заказ. Если первый запрос ещё выполняется, вернётся `409 in_progress`; подождите несколько секунд и повторите. Тот же ключ с другим телом даёт `422 idempotency_key_reuse`.
Если поставщик не выполнил заказ, API вернёт `502 fulfillment_failed`, а заказ будет в поле `order`. Средства возвращаются, статус заказа — `refunded`.
## 6. Получение заказов
- `GET /orders/{id}` — получить заказ по UUID или короткому номеру.
- `GET /orders?status=processing&limit=50&offset=0` — список заказов (сначала новые) с фильтром и пагинацией. `limit` от 1 до 100 (по умолчанию 50). Ответ содержит `total` и `orders`.
Статусы: `processing` (в работе), `fulfilled` (выполнен), `refunded` (поставщик не выполнил, средства возвращены) и `failed` (заказ не выполнен; см. поле `error`). Не рассчитывайте, что `processing` завершится быстро: используйте webhook или опрашивайте `GET /orders/{id}`.
## 7. Баланс
### `GET /balance`
```json
{"ok":true,"balanceTjs":"125.40"}
```
Это баланс вашего аккаунта GamesDrop. Все суммы указаны в сомони (TJS) с двумя знаками после точки.
## 8. Webhook
Webhook настраивается в личном кабинете → **API** или через API. URL должен соответствовать правилам: только `https://`, только порт 443, без логина и пароля в URL, а хост должен разрешаться в публичный IPv4-адрес (внутренние, приватные и только IPv6 адреса отклоняются с `400 invalid_request`). Редиректы не выполняются.
- `PUT /webhook` — сохранить URL: `{"url":"https://example.com/hook"}`. В ответе показывается полный секрет (`whsec_...`).
- `GET /webhook` — получить настройки (секрет частично скрыт), время и результат последней доставки и `failsInARow`.
- `POST /webhook` — управляющие действия. Смена секрета: `{"action":"rotate_secret"}`; в ответе показывается новый секрет.
- Отключение: `PUT /webhook` с `{"url":null}`.
События: `order.fulfilled`, `order.refunded`, `order.failed`.
Тело запроса:
```json
{"event":"order.fulfilled","sentAt":"2026-10-11T10:00:05Z","order":{"id":"UUID","number":128,"status":"fulfilled","...":"те же поля, что в GET /orders/{id}"}}
```
Заголовок подписи: `X-GamesDrop-Signature: t=UNIX,v1=HEX`. Подпись — HMAC-SHA256 от строки `t + "." + RAW_BODY` (сырое тело запроса, байт в байт) с использованием webhook secret. Сравнивайте за постоянное время. Отклоняйте события, у которых `t` старше 5 минут.
Доставка: ваш endpoint должен ответить HTTP 2xx в течение 8 секунд. Иначе GamesDrop повторяет отправку: всего до 4 попыток с паузами 1, 5 и 15 минут. Ответ HTTP 4xx считается окончательным и не повторяется. Каждая попытка подписывается с новым `t`. Отвечайте быстро и обрабатывайте повторные события по `order.id` и `event`. Если что-то пропущено, прочитайте заказ через `GET /orders/{id}`.
## 9. Ошибки и лимиты
Пример ошибки:
```json
{"ok":false,"code":"insufficient_balance","error":"Дар ҳисоби панел маблағ нокифоя аст."}
```
Текст `error` предназначен для людей и может меняться. Используйте `code`. У некоторых ошибок есть дополнительные поля, например `field` в `missing_field` и `retryAfterSeconds` в `rate_limited`.
| HTTP | Code | Значение |
|---|---|---|
| 400 | `invalid_request`, `missing_field` | Некорректный запрос или поле (`field` указывает имя) |
| 401 | `unauthorized`, `key_revoked` | Неверный или отозванный ключ |
| 402 | `insufficient_balance` | Недостаточно средств |
| 403 | `account_blocked` | Аккаунт заблокирован |
| 404 | `not_found` | Категория, предложение или заказ не найдены |
| 405 | `method_not_allowed` | Метод не разрешён для этого пути |
| 409 | `offer_unavailable`, `in_progress` | Предложение недоступно или запрос ещё выполняется |
| 422 | `idempotency_key_reuse` | Повторный ключ использован с другим содержимым |
| 429 | `rate_limited` | Превышен лимит запросов; повторите позже |
| 500 | `internal_error` | Внутренняя ошибка; передайте `requestId` в поддержку |
| 502 | `fulfillment_failed` | Поставщик не выполнил заказ; средства возвращаются; ответ содержит `order` |
| 503 | `service_unavailable`, `check_unavailable_now` | Сервис временно недоступен |
Лимит по умолчанию — 30 запросов в минуту на ключ (администратор может изменить его). При `429` дождитесь `retryAfterSeconds` (он также приходит в заголовке `Retry-After`). `429` может также означать, что сервис сейчас перегружен для всех партнёров; правило то же.
## 10. Безопасность
1. Не передавайте API Key и Webhook Secret другим людям и не публикуйте их в GitHub.
2. Используйте только HTTPS.
3. Отправляйте запросы с сервера, а не из браузера.
4. Для каждого нового заказа используйте новый `Idempotency-Key`.
5. Перед заказом проверяйте цену и ID игрока.
6. Проверяйте подпись webhook в каждом событии, прежде чем ему доверять.