# KRAB.GG API: Telegram Stars, Premium, GRAM и Steam

- **OpenAPI Version:** `3.1.1`
- **API Version:** `1.0.0`

Выдавайте **Telegram Stars**, **Premium** и **GRAM** по `@username`, оплачивайте **розыгрыши** в каналах, пополняйте кабинеты **Telegram Ads** по ссылке и **Steam** по логину. Вы пополняете USDT-баланс и отправляете `POST /orders`, мы выдаём товар.

**Цена.** Stars, Premium, GRAM, розыгрыши и Telegram Ads: оптовая цена Fragment плюс комиссия 1%, у `premium_giveaway` она умножается на число подписок. Steam: без комиссии, спишем ровно столько долларов, сколько вы заказали. Точную сумму до заказа покажет `GET /price`.

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

1. Откройте бота [@apistarsbot](https://t.me/apistarsbot?start=api) и нажмите «Тестовый ключ сейчас»: ключ `sk_test_…` придёт сразу. Боевой `sk_live_…` выдаём по кнопке «Боевой доступ» после проверки заявки.
2. Отправьте заказ:

```bash
curl https://api.krab.gg/v1/orders \
  --request POST \
  --header 'Authorization: Bearer sk_live_…' \
  --header 'Content-Type: application/json' \
  --data '{"type":"stars","qty":100,"username":"@johnsmith","orderId":"order-123"}'
```

3. Посмотрите на `status` в ответе. `completed`: товар выдан. `processing`: выдача идёт, итог придёт вебхуком, или спросите `GET /orders/{id}`. `failed`: выдать не получилось, причина в `reason`.

С тестовым ключом мы ничего не списываем и не выдаём: ответ придёт с ценой, но без `status`.

## Товары

| `type`             | `qty`                                                                  | `username`                                      |
| ------------------ | ---------------------------------------------------------------------- | ----------------------------------------------- |
| `stars`            | звёзды, 50…10 000 000                                                  | `@username` в Telegram                          |
| `premium`          | месяцы: 3, 6 или 12                                                    | `@username` в Telegram                          |
| `gram`             | целые TON                                                              | `@username` в Telegram                          |
| `steam`            | доллары, можно с центами: `10.5`                                       | логин Steam без `@`                             |
| `stars_giveaway`   | всего звёзд на розыгрыш, один из пакетов; победителей в `winners`      | `@handle` канала                                |
| `premium_giveaway` | срок каждой подписки: 3, 6 или 12; подписок столько, сколько `winners` | `@handle` канала                                |
| `ads_recharge`     | целые GRAM                                                             | ссылка «Add Funds on Fragment» или токен из неё |

`@` в имени можно не писать, число можно прислать строкой. Границы у `gram`, `ads_recharge` и `steam` меняются: за пределами придёт `min_quantity` или `max_quantity` с полем `min` или `max`.

`orderId` это ваш номер заказа, до 128 символов из `A-Za-z0-9._:-`. Повторите запрос с тем же `orderId`, и мы вернём тот же заказ, не списав деньги второй раз. Если в повторе другой `type`, `qty` или `username`, придёт `409 order_id_conflict`.

## Деньги

Пока идёт выдача, сумма заказа лежит в резерве на вашем балансе. Что с ней, показывает `settlement`:

- `charged`: списали, товар выдан;
- `pending`: деньги в резерве, выдача идёт;
- `refunded`: вернули на баланс;
- `fail_hold`: выдача не подтверждена, деньги держим до проверки оператором. Если спишем, придёт `order.completed`; если вернём, придёт `order.updated` с `settlement: refunded`.

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

## Ошибки

Ошибка приходит телом `{"ok": false, "error": "код", "message": "текст"}`. Ветвитесь по `error`, а `message` пишите в лог.

- `4xx`: исправьте запрос;
- `429`: подождите столько секунд, сколько в заголовке `Retry-After`. Лимит: 60 в минуту на весь аккаунт, боевой и тестовый ключи тратят общий счётчик;
- `5xx`: повторите позже.

## Контакты

Базовый адрес: `https://api.krab.gg/v1`. В ответах могут появиться новые поля, незнакомые пропускайте. Выпуская боевой ключ, вы принимаете [условия для API-партнёров](https://krab.gg/ru/api-terms). Вопросы и спорные заказы: [@heIIo\_stars](https://t.me/heIIo_stars) или <hello@krab.gg>, укажите `orderId`.

## Идентификатор запроса

В КАЖДОМ ответе приходит заголовок `X-Request-Id` (например `req_mu88via8_53d8cd`). Сохраняйте его в своих логах: по нему мы находим ровно тот запрос, о котором вы спрашиваете, — со всеми деталями отказа. Без него поиск идёт по времени и адресу и занимает несоизмеримо дольше.

```properties
X-Request-Id: req_mu88via8_53d8cd
```

## Servers

- **URL:** `https://api.krab.gg/v1`
  - **Description:** Production

## Operations

### Цена

- **Method:** `GET`
- **Path:** `/price`
- **Tags:** Цены и проверка

Сколько мы спишем за заказ. Ничего не создаёт и не резервирует; при создании заказа цену считаем заново.

#### Parameters

##### `type` required

- **In:** `query`

Товар.

`string`, possible values: `"stars", "premium", "gram", "steam"`

##### `qty` required

- **In:** `query`

То же, что `qty` в `POST /orders`.

`number`

#### Responses

##### Status: 200 Цена

###### Content-Type: application/json

**All of:**

- **`ok`**

  `boolean`

- **`price`**

  `number` — Сумма к списанию в долларах USDT, до шести знаков после запятой.

- **`qty`**

  `number`

- **`type`**

  `string`

**Example:**

```json
{
  "ok": true,
  "type": "stars",
  "qty": 100,
  "price": 1.515
}
```

##### Status: 400 unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "min_quantity",
  "message": "Quantity is below the allowed minimum (see min).",
  "min": 50
}
```

##### Status: 503 Повторите позже: category\_disabled (продажи товара на паузе), plan\_unavailable (нет Premium на этот срок), pricing\_unavailable, rate\_unavailable (нет свежего курса: Steam или TON для GRAM).

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "rate_unavailable",
  "message": "The exchange rate is temporarily unavailable. Please retry.",
  "retryable": true
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Проверка получателя

- **Method:** `GET`
- **Path:** `/check`
- **Tags:** Цены и проверка

Проверяет получателя до заказа, чтобы опечатка не заморозила деньги. Stars, Premium и GRAM проверяет Fragment тем же поиском, что и выдача, Steam проверяет платёжный шлюз. Ответ совпадает с тем, чем кончится заказ на этого получателя.

`accepts: false` приходит с `reason`.

#### Parameters

##### `username` required

- **In:** `query`

`@username` в Telegram или логин Steam.

`string`

##### `type`

- **In:** `query`

Товар: `stars` (по умолчанию), `premium`, `gram` или `steam`.

`string`, possible values: `"stars", "premium", "gram", "steam", "stars_giveaway", "premium_giveaway", "ads_recharge"`, default: `"stars"`

##### `qty`

- **In:** `query`

Только для premium: срок 3, 6 или 12, по умолчанию 3.

`integer`

#### Responses

##### Status: 200 Проверка выполнена

###### Content-Type: application/json

**All of:**

- **`accepts`**

  `boolean` — \`true\`: товар можно отправлять. \`false\`: не отправляйте, причина в \`reason\`.

- **`ok`**

  `boolean`

- **`reason`**

  `string`, possible values: `"already_subscribed", "recipient_rejects"` — Только при \`accepts: false\`. \`already\_subscribed\`: у получателя уже есть Premium. \`recipient\_rejects\`: получатель есть, но заказ на него не пройдёт (для Steam: логин нельзя пополнить). Заказ на такого получателя упадёт с той же причиной в \`reason\`.

- **`type`**

  `string`, possible values: `"stars", "premium", "gram", "steam", "stars_giveaway", "premium_giveaway", "ads_recharge"`

**Example:**

```json
{
  "ok": true,
  "type": "stars",
  "accepts": true
}
```

##### Status: 400 username\_required, invalid\_username, unsupported\_type, invalid\_premium\_duration.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "invalid_username",
  "message": "The recipient username is invalid. Use an @handle of 5-32 characters (letters, digits, _; not starting or ending with _) for stars/premium/gram, or a Steam account login without @ (letters, digits, _ and -) for steam.",
  "type": "stars"
}
```

##### Status: 404 not\_found: такого пользователя нет, или это канал либо бот.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "not_found",
  "message": "Not found.",
  "type": "stars"
}
```

##### Status: 502 fetch\_failed: Fragment или шлюз Steam не ответили либо ответили непонятно. О получателе это ничего не говорит, повторите.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "fetch_failed",
  "message": "Temporary failure checking the recipient. Please retry.",
  "type": "stars"
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Баланс

- **Method:** `GET`
- **Path:** `/balance`
- **Tags:** Баланс и пополнение

Доступный баланс в долларах USDT. История движений есть в кабинете.

#### Responses

##### Status: 200 Баланс

###### Content-Type: application/json

**All of:**

- **`balance`**

  `number` — Доступный баланс в долларах USDT.

- **`ok`**

  `boolean`

**Example:**

```json
{
  "ok": true,
  "balance": 42.5
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Реквизиты пополнения

- **Method:** `GET`
- **Path:** `/deposit`
- **Tags:** Баланс и пополнение

Куда отправить деньги. Мы принимаем только **USDT в сети TON**: переведите от 100 USDT на `address` и **обязательно укажите `memo`** в комментарии. Адрес общий, memo закреплён за вашим аккаунтом. Зачисляем обычно в течение минуты, проверяйте `GET /balance`. Забыли memo: пришлите в поддержку хэш транзакции, зачислим вручную.

#### Responses

##### Status: 200 Реквизиты

###### Content-Type: application/json

- **`address`**

  `string` — Наш кошелёк.

- **`asset`**

  `string`

- **`memo`**

  `string` — Комментарий к переводу. Без него мы не узнаем, чей перевод.

- **`minRecommendedUsdt`**

  `number` — Минимальная сумма пополнения в USDT.

- **`network`**

  `string`

- **`note`**

  `string` — Короткая подсказка, всегда на русском.

- **`ok`**

  `boolean`

**Example:**

```json
{
  "ok": true,
  "asset": "USDT",
  "network": "TON",
  "address": "EQ…",
  "memo": "d1a2b3c4d5e6f7081",
  "minRecommendedUsdt": 100,
  "note": "Отправьте от 100 USDT (TON) на address с указанным memo. Без memo средства зачислить нельзя."
}
```

##### Status: 403 sandbox\_no\_deposit: в песочнице пополнения нет, сначала получите боевой доступ.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "sandbox_no_deposit",
  "message": "Deposits are not available in sandbox. Request live access first."
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Текущий вебхук

- **Method:** `GET`
- **Path:** `/webhook`
- **Tags:** Вебхуки

URL вебхука и `secret` для проверки подписи. Тестовому ключу приходит `secret: null`.

#### Responses

##### Status: 200 Настройки вебхука

###### Content-Type: application/json

- **`ok`**

  `boolean`

- **`secret`**

  `string | null`

- **`url`**

  `string | null`

**Example:**

```json
{
  "ok": true,
  "url": "https://shop.example.com/webhooks/krab",
  "secret": "whsec_4f1c…"
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Задать вебхук

- **Method:** `POST`
- **Path:** `/webhook`
- **Tags:** Вебхуки

Задаёт URL, куда мы отправим POST, когда меняется итог заказа. `url: null` выключает вебхук. В ответе придёт `secret`: он появляется при первой установке URL и не меняется при смене URL. Новый секрет выпускает кнопка «Перевыпустить секрет» в кабинете, старый сразу перестаёт подходить.

**Событие.** JSON с полями `event`, `orderId`, `status`, `type`, `qty`, `username`, `settlement`, `sequence` и `occurredAt` (unix-время в секундах, когда мы зафиксировали это состояние), а если выдача пробовалась и не удалась, ещё `reason` и `retryable`. Событие приходит, когда меняется итог заказа: `order.completed` (выдано), `order.failed` (не выдано или закрыто без выдачи) или `order.updated` (итог прежний, но изменились `settlement`, `reason` или `retryable`, например резерв вернули после `fail_hold`). `sequence` растёт на 1 с каждым событием заказа: пришло событие с номером меньше уже обработанного, пропустите его. Кнопка «Отправить тест» в кабинете шлёт `{"event":"ping","at":<unix-время>}` с `X-Webhook-Id: test`.

**Подпись.** Мы шлём заголовки `X-Webhook-Id`, `X-Webhook-Timestamp` (unix-время в секундах) и `X-Webhook-Signature: v1,<подпись>`, где подпись = base64(HMAC-SHA256(`id.timestamp.body`, secret)), а `body` это сырое тело запроса. Отклоняйте доставки старше нескольких минут.

```js
const expected = Buffer.from(crypto.createHmac('sha256', secret).update(`${id}.${ts}.${rawBody}`).digest('base64'));
const got = Buffer.from(signature.replace(/^v1,/, ''));
const ok = got.length === expected.length && crypto.timingSafeEqual(expected, got);
```

**Доставка.** Ответьте 2xx за 10 секунд, тело ответа не больше 64 КБ, иначе попытка считается неудачной. Редиректы не выполняем: ответ 3xx тоже неудача. Повторяем через 1м→5м→30м→2ч, всего 5 попыток, потом присылаем уведомление в кабинет. Одно событие может прийти дважды: `X-Webhook-Id` при повторах тот же, отбрасывайте дубли по нему. Порядок доставки не гарантирован, сверяйте `sequence`. Событие, не доставленное за 5 попыток или пропущенное при выключенном вебхуке, может не прийти (после включения вебхука могут прийти события по заказам, изменившимся за последние сутки): итоговый статус всегда сверяйте через `GET /orders/{id}`.

#### Request Body

##### Content-Type: application/json

- **`url` (required)**

  `string | null` — Публичный https или http URL. \`null\` выключает вебхук. Если имя хоста указывает во внутреннюю сеть, доставки на него не пройдут.

**Example:**

```json
{
  "url": "https://shop.example.com/webhooks/krab"
}
```

#### Responses

##### Status: 200 Сохранено

###### Content-Type: application/json

- **`ok`**

  `boolean`

- **`secret`**

  `string | null`

- **`url`**

  `string | null`

**Example:**

```json
{
  "ok": true,
  "url": "https://shop.example.com/webhooks/krab",
  "secret": "whsec_4f1c…"
}
```

##### Status: 400 url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "private_address_not_allowed",
  "message": "The webhook URL must be a public address."
}
```

##### Status: 403 test\_key\_readonly: тестовый ключ настройки не меняет, нужен боевой.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "test_key_readonly",
  "message": "A test key (sk_test_) cannot change configuration. Use a live key (sk_live_)."
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Создать заказ

- **Method:** `POST`
- **Path:** `/orders`
- **Tags:** Заказы

Создаёт заказ и сразу отправляет товар. Stars, Premium и GRAM обычно выдаём за несколько секунд, и ответ приходит уже с `status: completed`. Steam обычно отвечает `processing`: итог придёт вебхуком или через `GET /orders/{id}`. Если выдать не получилось сразу, придёт `status: failed` с причиной в `reason`. Если у шлюза Steam кончились деньги и заказ до него не дошёл, заказ ждёт до двух часов, потом завершается `failed` с `reason: temporary`, а деньги возвращаются на баланс. Если отправка могла пройти, решение принимает оператор.

Повтор запроса с тем же `orderId` безопасен: вернём тот же заказ и не спишем деньги второй раз. После `503 order_create_failed` повторите тот же `orderId`: при неудачном создании новый резерв откатывается, деньги не остаются в холде без заказа. Старый резерв без записанных условий возвращает `409 hold_requires_resolution`: обратитесь в поддержку для сверки или освобождения средств. Закрытый резерв по-прежнему возвращает `hold_settled`, резерв другой суммы — `hold_amount_mismatch`.

#### Request Body

##### Content-Type: application/json

- **`orderId` (required)**

  `string` — Ваш номер заказа, до 128 символов из \`A-Za-z0-9.\_:-\`. Повтор того же orderId вернёт существующий заказ и не спишет деньги второй раз; с другим \`type\`, \`qty\` или \`username\` придёт 409 \`order\_id\_conflict\`.

- **`qty` (required)**

  `number` — Сколько: звёзды, месяцы Premium (3, 6, 12), целые TON для gram или доллары для steam. У \`stars\_giveaway\` — ВСЕГО звёзд на розыгрыш (один из пакетов Fragment, см. \`allowed\` в ошибке): площадка сама делит их между победителями. У \`premium\_giveaway\` — срок КАЖДОЙ подписки (3, 6, 12), а подписок столько, сколько победителей. У \`ads\_recharge\` — целые GRAM. См. границы ниже.

- **`type` (required)**

  `string`, possible values: `"stars", "premium", "gram", "steam", "stars_giveaway", "premium_giveaway", "ads_recharge"` — Товар: \`stars\`, \`premium\`, \`gram\`, \`steam\`, \`stars\_giveaway\`, \`premium\_giveaway\` или \`ads\_recharge\`.

- **`username` (required)**

  `string` — Получатель: \`@username\` в Telegram, для steam логин аккаунта Steam. У розыгрышей — \`@handle\` КАНАЛА (в бота или личный аккаунт розыгрыш не проводится). У \`ads\_recharge\` — токен из ссылки Telegram Ads «Add Funds on Fragment» (\`fragment.com/ads/pay?account=…\`); можно прислать ссылку целиком. Это не @имя и не числовой id.

- **`dryRun`**

  `boolean` — \`true\`: песочница. Мы только считаем цену: не списываем, не выдаём и не создаём заказ. Тестовый ключ всегда работает так. В ответе будут цена, \`dryRun: true\` и \`mode\`, но не будет \`status\` и \`settlement\`; \`GET /orders/{id}\` по такому orderId ответит 404, вебхуков не будет. Кроме \`true\`/\`false\` понимаем \`1\`/\`0\` и строки \`"true"\`/\`"false"\`; другое значение → 400 \`invalid\_dry\_run\`.

- **`winners`**

  `integer` — Только для розыгрышей: сколько человек делят приз. У \`stars\_giveaway\` потолок зависит от объёма (Fragment даёт не меньше 100 звёзд на человека, то есть не больше чем \`qty / 100\` победителей), у \`premium\_giveaway\` — до 24000 подписок. У остальных товаров поле не принимается.

**Example:**

```json
{
  "type": "stars",
  "qty": 100,
  "winners": 5,
  "username": "@johnsmith",
  "orderId": "order-123",
  "dryRun": false
}
```

#### Responses

##### Status: 200 Заказ. В песочнице (тестовый ключ или \`dryRun: true\`) заказ не создаётся: поля \`status\` и \`settlement\` отсутствуют, вместо них приходят \`dryRun: true\` и \`mode\`.

###### Content-Type: application/json

**All of:**

- **`dryRun`**

  `boolean` — Только в песочнице: \`true\`.

- **`idempotent`**

  `boolean` — \`true\`: такой orderId уже был, мы вернули существующий заказ и ничего не списали.

- **`mode`**

  `string`, possible values: `"live", "test"` — Только в песочнице: \`test\` для тестового ключа, \`live\` для боевого с dryRun.

- **`ok`**

  `boolean`

- **`orderId`**

  `string`

- **`price`**

  `number` — Цена в долларах USDT. Только в ответе \`POST /orders\`.

- **`qty`**

  `number` — Для steam в долларах, округлено до цента.

- **`reason`**

  `string | null`, possible values: `"already_subscribed", "partial_delivery", "recipient_not_found", "recipient_rejects", "unsupported_type", "under_review", "temporary"` — Почему выдача не удалась. Приходит вместе с \`retryable\`, в том числе когда заказ потом закрыли как \`cancelled\` или \`refunded\`. - \`recipient\_not\_found\`: получателя нет; - \`recipient\_rejects\`: получатель не может принять этот товар; - \`already\_subscribed\`: у получателя уже есть Premium; - \`unsupported\_type\`: товар сейчас не выдаётся; - \`temporary\`: сбой до отправки; повторяйте новым orderId, когда \`retryable: true\`; - \`under\_review\`: отправка могла пройти, мы проверяем, новый заказ не создавайте; - \`partial\_delivery\`: выдали часть, остаток довыдадим вручную, не повторяйте. При \`recipient\_not\_found\`, \`recipient\_rejects\`, \`already\_subscribed\` и \`unsupported\_type\` деньги возвращаются сами, обычно в течение минуты. Что с деньгами сейчас, показывает \`settlement\`.

- **`retryable`**

  `boolean` — \`true\`: деньги по заказу вернулись на баланс, повторите новым orderId. \`false\`: повтор не поможет, или деньги ещё в резерве и выдача может завершиться.

- **`settlement`**

  `string`, possible values: `"charged", "refunded", "fail_hold", "pending"` — Что с деньгами: \`charged\`, \`pending\`, \`refunded\` или \`fail\_hold\` (см. «Деньги» во введении). В песочнице поля нет.

- **`status`**

  `string`, possible values: `"completed", "processing", "failed", "refunded", "cancelled"` — \`completed\`: выдано. \`processing\`: выдача идёт. \`failed\`: выдать не удалось. \`cancelled\`, \`refunded\`: заказ закрыт без выдачи. В ответе песочницы поля нет.

- **`type`**

  `string`

- **`username`**

  `string` — В том виде, в каком вы прислали его в заказе.

**Example:**

```json
{
  "ok": true,
  "orderId": "order-123",
  "status": "completed",
  "type": "stars",
  "qty": 100,
  "username": "@johnsmith",
  "price": 1.515,
  "settlement": "charged"
}
```

##### Status: 400 Исправьте запрос: username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, invalid\_dry\_run. hold\_settled, hold\_amount\_mismatch: этот orderId уже занят, возьмите новый.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "order_id_required",
  "message": "An orderId is required."
}
```

##### Status: 402 insufficient\_funds: не хватает денег. В ответе \`balance\` и \`required\` в долларах.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "insufficient_funds",
  "message": "Insufficient balance for this order (see balance and required).",
  "balance": 0.5,
  "required": 1.515
}
```

##### Status: 409 in\_progress: этот orderId обрабатывается параллельным запросом, повторите через секунду, дубля не будет. order\_id\_conflict: этот orderId уже занят заказом с другим \`type\`, \`qty\` или \`username\`, возьмите новый. hold\_requires\_resolution: у существующего резерва нет подходящих записанных условий; нужна сверка или освобождение средств через поддержку. Новый заказ и выдача не запускаются.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "order_id_conflict",
  "message": "This orderId already belongs to a different order (type, quantity or recipient). Use a new orderId."
}
```

##### Status: 503 Повторите позже: category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "order_create_failed",
  "message": "Could not create the order. Please retry."
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

### Статус заказа

- **Method:** `GET`
- **Path:** `/orders/{id}`
- **Tags:** Заказы

Заказ по вашему `orderId`: `status`, `settlement`, а после неудачной выдачи ещё `reason` и `retryable`. Цены здесь нет, она приходит в ответе `POST /orders`.

#### Parameters

##### `id` required

- **In:** `path`

Ваш orderId.

`string`

#### Responses

##### Status: 200 Заказ

###### Content-Type: application/json

**All of:**

- **`dryRun`**

  `boolean` — Только в песочнице: \`true\`.

- **`idempotent`**

  `boolean` — \`true\`: такой orderId уже был, мы вернули существующий заказ и ничего не списали.

- **`mode`**

  `string`, possible values: `"live", "test"` — Только в песочнице: \`test\` для тестового ключа, \`live\` для боевого с dryRun.

- **`ok`**

  `boolean`

- **`orderId`**

  `string`

- **`price`**

  `number` — Цена в долларах USDT. Только в ответе \`POST /orders\`.

- **`qty`**

  `number` — Для steam в долларах, округлено до цента.

- **`reason`**

  `string | null`, possible values: `"already_subscribed", "partial_delivery", "recipient_not_found", "recipient_rejects", "unsupported_type", "under_review", "temporary"` — Почему выдача не удалась. Приходит вместе с \`retryable\`, в том числе когда заказ потом закрыли как \`cancelled\` или \`refunded\`. - \`recipient\_not\_found\`: получателя нет; - \`recipient\_rejects\`: получатель не может принять этот товар; - \`already\_subscribed\`: у получателя уже есть Premium; - \`unsupported\_type\`: товар сейчас не выдаётся; - \`temporary\`: сбой до отправки; повторяйте новым orderId, когда \`retryable: true\`; - \`under\_review\`: отправка могла пройти, мы проверяем, новый заказ не создавайте; - \`partial\_delivery\`: выдали часть, остаток довыдадим вручную, не повторяйте. При \`recipient\_not\_found\`, \`recipient\_rejects\`, \`already\_subscribed\` и \`unsupported\_type\` деньги возвращаются сами, обычно в течение минуты. Что с деньгами сейчас, показывает \`settlement\`.

- **`retryable`**

  `boolean` — \`true\`: деньги по заказу вернулись на баланс, повторите новым orderId. \`false\`: повтор не поможет, или деньги ещё в резерве и выдача может завершиться.

- **`settlement`**

  `string`, possible values: `"charged", "refunded", "fail_hold", "pending"` — Что с деньгами: \`charged\`, \`pending\`, \`refunded\` или \`fail\_hold\` (см. «Деньги» во введении). В песочнице поля нет.

- **`status`**

  `string`, possible values: `"completed", "processing", "failed", "refunded", "cancelled"` — \`completed\`: выдано. \`processing\`: выдача идёт. \`failed\`: выдать не удалось. \`cancelled\`, \`refunded\`: заказ закрыт без выдачи. В ответе песочницы поля нет.

- **`type`**

  `string`

- **`username`**

  `string` — В том виде, в каком вы прислали его в заказе.

**Example:**

```json
{
  "ok": true,
  "orderId": "order-123",
  "status": "completed",
  "type": "stars",
  "qty": 100,
  "username": "@johnsmith",
  "settlement": "charged"
}
```

##### Status: 400 invalid\_order\_id: неверный формат orderId.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "invalid_order_id",
  "message": "The orderId format is invalid. Use up to 128 characters from A-Z, a-z, 0-9, dot, underscore, colon or hyphen."
}
```

##### Status: 404 not\_found: такого заказа нет. Заказы из песочницы не сохраняются.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "not_found",
  "message": "Not found."
}
```

##### Status: default Ошибка, тело по схеме \`Error\`. Кроме кодов, описанных у метода, на любой запрос могут прийти: - \`401\` missing\_api\_key, invalid\_api\_key: ключа нет, он неверный или отозван, либо доступ к аккаунту приостановлен или закрыт; - \`403\` ip\_not\_allowed: запрос пришёл с адреса вне IP-списка аккаунта; в теле ответа поле \`seen\_ip\` — адрес, который увидели мы (именно его и вносите в список: за NAT или балансировщиком он отличается от того, что вы видите у себя); - \`429\` rate\_limited: превышен лимит аккаунта (по умолчанию 60 в минуту) или с одного IP пришло больше 120 запросов в минуту, тогда адрес блокируем на 5 минут. Ждите \`Retry-After\` секунд, остаток лимита видно в заголовках \`X-RateLimit-Limit\` и \`X-RateLimit-Remaining\`; - \`400\` bad\_request, \`413\` payload\_too\_large: тело не JSON или больше 32 КБ; - \`404\` not\_found: такого метода нет (неверный путь или HTTP-метод); - \`404\` partner\_not\_found: аккаунт закрыли, пока шёл запрос; следующие запросы получат 401; - \`500\`, \`503\`: сбой у нас или API остановлен (service\_unavailable), повторите позже.

###### Content-Type: application/json

**All of:**

- **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

- **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

- **`ok` (required)**

  `boolean`

- **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

- **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

- **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

- **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

- **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

- **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

- **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

- **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

- **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

- **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "missing_api_key",
  "message": "Missing API key. Send header 'Authorization: Bearer sk_...'."
}
```

## Schemas

### Error

- **Type:**`object`

* **`error` (required)**

  `string` — Код ошибки. 400, исправьте запрос: unsupported\_type, invalid\_quantity, min\_quantity, max\_quantity, invalid\_premium\_duration, username\_required, invalid\_username, order\_id\_required, invalid\_order\_id, invalid\_dry\_run, hold\_settled, hold\_amount\_mismatch, url\_required, invalid\_url, unsupported\_protocol, private\_address\_not\_allowed, invalid\_stars\_package, winners\_required, invalid\_winners, winners\_not\_supported, recipient\_not\_channel, recipient\_not\_found, invalid\_ads\_account, ads\_account\_not\_found, fragment\_rejected, bad\_request. 401: missing\_api\_key, invalid\_api\_key. 402: insufficient\_funds. 403: ip\_not\_allowed, test\_key\_readonly, sandbox\_no\_deposit. 404: not\_found, partner\_not\_found. 409: in\_progress, order\_id\_conflict, hold\_requires\_resolution. 413: payload\_too\_large. 429: rate\_limited. 502: fetch\_failed. 503, повторите позже: service\_unavailable, category\_disabled, plan\_unavailable, pricing\_unavailable, rate\_unavailable, order\_create\_failed, hold\_failed. 500, повторите: internal\_error, auth\_error, tenant\_lookup\_failed.

* **`message` (required)**

  `string` — Фраза на английском для логов. Логику стройте по \`error\`.

* **`ok` (required)**

  `boolean`

* **`allowed`**

  `array` — Допустимые сроки Premium. Приходит с \`invalid\_premium\_duration\`.

  **Items:**

  `integer`

* **`balance`**

  `number` — Ваш баланс в долларах. Приходит с \`insufficient\_funds\`.

* **`max`**

  `number` — Верхняя граница \`qty\`. Приходит с \`max\_quantity\`.

* **`min`**

  `number` — Нижняя граница \`qty\`. Приходит с \`min\_quantity\`.

* **`required`**

  `number` — Сколько нужно для заказа, в долларах. Приходит с \`insufficient\_funds\`.

* **`retryable`**

  `boolean` — Приходит с \`in\_progress\` и \`rate\_unavailable\`: запрос можно повторить.

* **`retryAfter`**

  `integer` — Через сколько секунд повторить. Приходит с \`rate\_limited\`.

* **`step`**

  `number` — Приходит с \`invalid\_quantity\`, когда у steam больше двух знаков после запятой: сумма с точностью до цента.

* **`type`**

  `string` — Товар, для которого шла проверка. Приходит с ошибками \`GET /check\` о получателе: invalid\_username, invalid\_premium\_duration, not\_found, fetch\_failed.

* **`whole`**

  `boolean` — Приходит с \`invalid\_quantity\`, когда у stars, premium или gram прислали дробное \`qty\`: нужно целое.

**Example:**

```json
{
  "ok": false,
  "error": "min_quantity",
  "message": "Quantity is below the allowed minimum (see min).",
  "min": 50
}
```

### Price

- **Type:**`object`

* **`ok`**

  `boolean`

* **`price`**

  `number` — Сумма к списанию в долларах USDT, до шести знаков после запятой.

* **`qty`**

  `number`

* **`type`**

  `string`

**Example:**

```json
{
  "ok": true,
  "type": "stars",
  "qty": 100,
  "price": 1.515
}
```

### Recipient

- **Type:**`object`

* **`accepts`**

  `boolean` — \`true\`: товар можно отправлять. \`false\`: не отправляйте, причина в \`reason\`.

* **`ok`**

  `boolean`

* **`reason`**

  `string`, possible values: `"already_subscribed", "recipient_rejects"` — Только при \`accepts: false\`. \`already\_subscribed\`: у получателя уже есть Premium. \`recipient\_rejects\`: получатель есть, но заказ на него не пройдёт (для Steam: логин нельзя пополнить). Заказ на такого получателя упадёт с той же причиной в \`reason\`.

* **`type`**

  `string`, possible values: `"stars", "premium", "gram", "steam", "stars_giveaway", "premium_giveaway", "ads_recharge"`

**Example:**

```json
{
  "ok": true,
  "type": "stars",
  "accepts": true
}
```

### Balance

- **Type:**`object`

* **`balance`**

  `number` — Доступный баланс в долларах USDT.

* **`ok`**

  `boolean`

**Example:**

```json
{
  "ok": true,
  "balance": 42.5
}
```

### OrderRequest

- **Type:**`object`

* **`orderId` (required)**

  `string` — Ваш номер заказа, до 128 символов из \`A-Za-z0-9.\_:-\`. Повтор того же orderId вернёт существующий заказ и не спишет деньги второй раз; с другим \`type\`, \`qty\` или \`username\` придёт 409 \`order\_id\_conflict\`.

* **`qty` (required)**

  `number` — Сколько: звёзды, месяцы Premium (3, 6, 12), целые TON для gram или доллары для steam. У \`stars\_giveaway\` — ВСЕГО звёзд на розыгрыш (один из пакетов Fragment, см. \`allowed\` в ошибке): площадка сама делит их между победителями. У \`premium\_giveaway\` — срок КАЖДОЙ подписки (3, 6, 12), а подписок столько, сколько победителей. У \`ads\_recharge\` — целые GRAM. См. границы ниже.

* **`type` (required)**

  `string`, possible values: `"stars", "premium", "gram", "steam", "stars_giveaway", "premium_giveaway", "ads_recharge"` — Товар: \`stars\`, \`premium\`, \`gram\`, \`steam\`, \`stars\_giveaway\`, \`premium\_giveaway\` или \`ads\_recharge\`.

* **`username` (required)**

  `string` — Получатель: \`@username\` в Telegram, для steam логин аккаунта Steam. У розыгрышей — \`@handle\` КАНАЛА (в бота или личный аккаунт розыгрыш не проводится). У \`ads\_recharge\` — токен из ссылки Telegram Ads «Add Funds on Fragment» (\`fragment.com/ads/pay?account=…\`); можно прислать ссылку целиком. Это не @имя и не числовой id.

* **`dryRun`**

  `boolean` — \`true\`: песочница. Мы только считаем цену: не списываем, не выдаём и не создаём заказ. Тестовый ключ всегда работает так. В ответе будут цена, \`dryRun: true\` и \`mode\`, но не будет \`status\` и \`settlement\`; \`GET /orders/{id}\` по такому orderId ответит 404, вебхуков не будет. Кроме \`true\`/\`false\` понимаем \`1\`/\`0\` и строки \`"true"\`/\`"false"\`; другое значение → 400 \`invalid\_dry\_run\`.

* **`winners`**

  `integer` — Только для розыгрышей: сколько человек делят приз. У \`stars\_giveaway\` потолок зависит от объёма (Fragment даёт не меньше 100 звёзд на человека, то есть не больше чем \`qty / 100\` победителей), у \`premium\_giveaway\` — до 24000 подписок. У остальных товаров поле не принимается.

**Example:**

```json
{
  "type": "stars",
  "qty": 100,
  "winners": 5,
  "username": "@johnsmith",
  "orderId": "order-123",
  "dryRun": false
}
```

### Order

- **Type:**`object`

* **`dryRun`**

  `boolean` — Только в песочнице: \`true\`.

* **`idempotent`**

  `boolean` — \`true\`: такой orderId уже был, мы вернули существующий заказ и ничего не списали.

* **`mode`**

  `string`, possible values: `"live", "test"` — Только в песочнице: \`test\` для тестового ключа, \`live\` для боевого с dryRun.

* **`ok`**

  `boolean`

* **`orderId`**

  `string`

* **`price`**

  `number` — Цена в долларах USDT. Только в ответе \`POST /orders\`.

* **`qty`**

  `number` — Для steam в долларах, округлено до цента.

* **`reason`**

  `string | null`, possible values: `"already_subscribed", "partial_delivery", "recipient_not_found", "recipient_rejects", "unsupported_type", "under_review", "temporary"` — Почему выдача не удалась. Приходит вместе с \`retryable\`, в том числе когда заказ потом закрыли как \`cancelled\` или \`refunded\`. - \`recipient\_not\_found\`: получателя нет; - \`recipient\_rejects\`: получатель не может принять этот товар; - \`already\_subscribed\`: у получателя уже есть Premium; - \`unsupported\_type\`: товар сейчас не выдаётся; - \`temporary\`: сбой до отправки; повторяйте новым orderId, когда \`retryable: true\`; - \`under\_review\`: отправка могла пройти, мы проверяем, новый заказ не создавайте; - \`partial\_delivery\`: выдали часть, остаток довыдадим вручную, не повторяйте. При \`recipient\_not\_found\`, \`recipient\_rejects\`, \`already\_subscribed\` и \`unsupported\_type\` деньги возвращаются сами, обычно в течение минуты. Что с деньгами сейчас, показывает \`settlement\`.

* **`retryable`**

  `boolean` — \`true\`: деньги по заказу вернулись на баланс, повторите новым orderId. \`false\`: повтор не поможет, или деньги ещё в резерве и выдача может завершиться.

* **`settlement`**

  `string`, possible values: `"charged", "refunded", "fail_hold", "pending"` — Что с деньгами: \`charged\`, \`pending\`, \`refunded\` или \`fail\_hold\` (см. «Деньги» во введении). В песочнице поля нет.

* **`status`**

  `string`, possible values: `"completed", "processing", "failed", "refunded", "cancelled"` — \`completed\`: выдано. \`processing\`: выдача идёт. \`failed\`: выдать не удалось. \`cancelled\`, \`refunded\`: заказ закрыт без выдачи. В ответе песочницы поля нет.

* **`type`**

  `string`

* **`username`**

  `string` — В том виде, в каком вы прислали его в заказе.

**Example:**

```json
{
  "ok": true,
  "orderId": "order-123",
  "status": "completed",
  "type": "stars",
  "qty": 100,
  "username": "@johnsmith",
  "price": 1.515,
  "settlement": "charged"
}
```
