Ҳуҷҷатҳои 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
Дар ҳисоби GamesDrop бахши **API**-ро кушоед ва калид созед. Қимати пурра танҳо як бор нишон дода мешавад. Онро дар муҳити сервери худ нигоҳ доред. Агар фош шавад, онро бекор кунед ва нав созед.
## 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` дақиқ нишон медиҳад, ки ҳангоми санҷиши ID ё сохтани фармоиш дар `fields` кадом калидҳоро фиристодан лозим аст (масалан `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 гирифта мешавад. Агар баланс кам бошад, `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, ва host бояд ба IPv4-и оммавӣ ҳал шавад (суроғаҳои дохилӣ, хусусӣ ва танҳо IPv6 бо `400 invalid_request` рад мешаванд). Редиректҳо пайравӣ намешаванд.
- `PUT /webhook` — сабти URL: `{"url":"https://example.com/hook"}`. Дар ҷавоб secret-и пурра (`whsec_...`) нишон дода мешавад.
- `GET /webhook` — дидани танзимот (secret қисман пинҳон аст), вақт ва натиҷаи интиқоли охирин ва `failsInARow`.
- `POST /webhook` — амалҳои идоракунӣ. Иваз кардани secret: `{"action":"rotate_secret"}`; дар ҷавоб 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-и шумо бояд дар 8 сония бо HTTP 2xx ҷавоб диҳад. Вагарна 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` | Калиди API нодуруст ё бекор |
| 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-ро дар ҳар рӯйдод пеш аз боварӣ санҷед.