Интеграция Reseller API: от ключа до первого заказа
Путь от выпуска ключа до доставленного заказа: какие запросы отправить, что придёт в ответ и где интеграции обычно ошибаются.
Содержание 9 разделов
От ключа до доставленного заказа шесть шагов: ключ, каталог, проверка получателя, создание заказа, оплата и опрос статуса. У каждого шага запрос, ответ и место, где легко ошибиться.
#Ключ и базовый адрес
Ключ выпускается в кабинете после входа через Telegram и показывается один раз. Положите его в переменную окружения: в коде и логах ему не место. Каждый запрос несёт заголовок Authorization: Bearer <ключ>.
Базовый адрес https://hexpay.live. Префиксы /api/reseller и /api/reseller/v1 равнозначны. Для новой интеграции берите версионированный: с выходом v2 он продолжит работать по-старому.
curl https://hexpay.live/api/reseller/v1/balance \
-H "Authorization: Bearer $HEX_API_KEY"Лимит около 60 запросов в минуту на ключ. На превышение API отвечает 429 с заголовком Retry-After: ждите указанное там время и только потом повторяйте запрос.
#Каталог
Витрину стройте по ответу GET /products: оптовая цена зависит от курса и ваших персональных условий, и своя таблица цен быстро устареет. Поле pricing_mode у позиции говорит, что передавать в заказе, а required_field называет обязательное поле.
| Товар | product | quantity | Получатель |
|---|---|---|---|
| Telegram Stars | stars | число звёзд, 50…1 000 000 | Telegram-юзернейм |
| Telegram Premium | premium_3m, premium_6m, premium_12m | не передаётся | Telegram-юзернейм |
| Подарки Telegram | gift и gift_id из /gifts | не передаётся | Telegram-юзернейм |
| Подписки на нейросети с ключом | neural и code из /neural | не передаётся | не нужен, ключ выдаётся вам |
Подписки на нейросети с delivery: redeem | neural и code из /neural | только 1 | organization_id аккаунта покупателя в fields |
| Игровые коды | game и product_ref из /games | пакетов кодов, 1…10 | не нужен, коды выдаются вам |
У позиций с delivery: redeem ключа нет: подписку платформа подключает сама на аккаунт покупателя по его organization_id. Какие поля нужны и какие условия аккаунта показать покупателю до оплаты, отдаёт /neural.
Подарочные карты и музыкальные подписки тоже заказываются через свои подкаталоги, по product_ref. Его формат для каждого подкаталога описан в справочнике у метода создания заказа.
#Проверка получателя
GET /check-recipient бесплатен и не трогает депозит. Неверный получатель срывает доставку с кодом recipient_invalid, и проверка до оплаты отсекает такой заказ дешевле всего.
curl -G https://hexpay.live/api/reseller/v1/check-recipient \
-H "Authorization: Bearer $HEX_API_KEY" \
--data-urlencode "product=premium_3m" \
--data-urlencode "username=buyer_username"status бывает ok, not_found и premium_already. Для neural и game получателя нет, на них метод ответит 400 с error_code: no_recipient.#Заказ в две фазы
Первый запрос фиксирует цену, второй списывает депозит. Между ними у вас точная сумма, которую можно показать покупателю.
curl https://hexpay.live/api/reseller/v1/order/create \
-H "Authorization: Bearer $HEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"custom_id": "a4cee2fe-ce8c-448b-bf2c-000000000001",
"product": "stars",
"recipient_username": "buyer_username",
"quantity": 100
}'custom_id придумываете вы, удобнее всего UUID. Цена держится до expires_at, потом неоплаченный заказ отменяется, и его создают заново с новым custom_id.curl https://hexpay.live/api/reseller/v1/order/pay \
-H "Authorization: Bearer $HEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"custom_id": "a4cee2fe-ce8c-448b-bf2c-000000000001"}'price_charged_rub, только со статусом. Успехом считайте оба кода. Наличие проверяется дважды: на create и на pay. Если позиция кончилась, пока заказ ждал оплаты, pay ответит 409 с error_code: out_of_stock, депозит не тронут.#Опрос статуса
Опрашивайте GET /order/{custom_id} до конечного статуса, даже если подключили вебхук. Вебхук может не дойти, и источником истины остаётся опрос.
status | Что значит | Конечный |
|---|---|---|
created | цена зафиксирована, депозит не списан | нет |
pending | оплачен, ждёт доставки | нет |
processing | доставляется | нет |
delivered | доставлен | да |
failed | доставка не удалась, депозит возвращён | да |
cancelled | истёк неоплаченным или отменён вручную | да, обрабатывайте как failed |
rejected | на оплате не хватило депозита, списания не было | да |
import os
import time
import requests
API = "https://hexpay.live/api/reseller/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['HEX_API_KEY']}"}
FINAL = {"delivered", "failed", "cancelled", "rejected"}
def wait_order(custom_id: str, pause: int = 5) -> dict:
while True:
r = requests.get(f"{API}/order/{custom_id}", headers=HEADERS, timeout=15)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", pause)))
continue
r.raise_for_status()
order = r.json()
if order["status"] in FINAL:
return order
time.sleep(pause)Верхней границы по времени в цикле нет намеренно. У асинхронных товаров доставка идёт минутами и часами, а иногда ждёт действия покупателя. Для них приходят поля delivery_state, action_required и eta_seconds, а свой таймаут превратил бы живой заказ в возврат денег за товар, который ещё придёт.
Пауза 5 секунд на один заказ это 12 запросов в минуту из 60. Если в доставке одновременно десяток заказов, опрашивайте их одним проходом и с паузой длиннее.
#Где лежит товар
Результат приходит в delivered_payload. У звёзд, Premium и подарков там подтверждение: товар ушёл получателю сам. У нейросетей с ключом в поле key лежит сам товар, рядом приходит activation_guide с инструкцией. У позиций с delivery: redeem там только activated: true: подписка уже на аккаунте покупателя. У игровых кодов это массив codes. Ключ и коды вы передаёте покупателю сами.
{
"success": true,
"custom_id": "a4cee2fe-ce8c-448b-bf2c-000000000001",
"status": "delivered",
"product": "stars",
"recipient": "buyer_username",
"quantity": 100,
"price_quoted_nano": 132070,
"price_charged_nano": 132070,
"delivered_payload": {
"tx_hash": "37ada9160f7870a33fc8"
},
"refunded": false,
"created_at": "2026-08-21T12:00:00Z",
"completed_at": "2026-08-21T12:00:41Z"
}Если поставщик выдал меньше кодов, чем заказано, статус остаётся delivered, а разница возвращается на депозит. Количество для покупателя берите из delivered_payload.delivered_quantity: в quantity лежит то, что вы заказали.
#Суммы в nano
У каждой суммы два поля: *_rub для показа и *_nano для арифметики, где 1 ₽ = 1000 nano. Складывайте total_to_pay_nano, price_charged_nano и refund_amount_nano в целых и округляйте один раз на выводе. С float копейки разойдутся с балансом уже на второй сотне заказов.
#Коды ответов
| HTTP | Где | Что значит |
|---|---|---|
| 400 | create | ошибка валидации, например invalid_quantity или invalid_order_data |
| 401 | все методы | API не принял ключ |
| 402 | pay | не хватило депозита, заказ в статусе rejected, списания не было |
| 404 | pay, /order/{custom_id} | заказ не найден |
| 409 | create | позиции нет в наличии, заказ не создан |
| 409 | pay | заказ отменён или отклонён, либо позиция кончилась (out_of_stock), депозит не тронут |
| 429 | все методы | лимит запросов, ждите Retry-After |
| 503 | create | товар временно недоступен |
У заказа в failed есть машиночитаемый error_code. Ветвитесь по нему, а не по тексту error_message. Полная таблица кодов с пометкой, вернулись ли деньги и стоит ли повторять, есть в статье про идемпотентность и вебхуки.
Один код стоит запомнить сразу. delivery_in_review значит, что доставку смотрит человек: заказ живой, деньги не возвращались, статус не конечный. Возвращать по нему оплату покупателю нельзя, дождитесь delivered или failed.
Если код за вас пишет нейросеть, отдайте ей бриф из справочника, раздел «Для ИИ-агента». Что ещё вписать в задание, чтобы она не списала депозит дважды, написано в статье про интеграцию руками агента.
#Чек-лист
Первый заказ на минимальную сумму
Выпустите ключ, пополните депозит и пройдите шаги из статьи. В справочнике у метода пример ответа и разбор каждого отказа.
Читать дальше
Что делать с таймаутом, повтором и вебхуком, чтобы не списать депозит дважды.
Если код пишет агент: что дать ему на входе и что проверить.
Нужен ли вам API или хватит магазина в боте.