Перейти к содержимому
SupplyMe

SUPPLYME / DEVELOPERS

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

Каталог, баланс и покупки в вашей интеграции.

Версия контракта 1.5.0 · 12 октября 2026

Подключение

API предназначен для серверной интеграции: каталог, баланс партнёра, закупка товаров и получение выданных данных. Доступ выдаётся на функции магазина. Административных прав клиентский токен не даёт.

Базовый адрес: https://supply-me.ru/api/v1. Все методы ниже указываются относительно него. Документация доступна без ключа: страница API, OpenAPI 3.0 JSON, скачать Markdown.

Войдите в SupplyMe через Telegram и откройте «Профиль → API». Создайте ключ для своей интеграции. Обычный ключ разрешает чтение каталога, своего баланса и заказов этого API-клиента (shop_read). Для автоматических закупок отдельно разрешите покупки с баланса (shop_purchase): каждый новый успешный POST /orders списывает реальные средства вашего аккаунта.

Можно иметь до пяти активных ключей. Полный ключ показывается один раз при создании. Скопируйте его и храните на backend в переменной окружения или хранилище секретов; не помещайте ключ в браузерный код, публичный репозиторий или URL. В профиле можно посмотреть ограничения, использование и отозвать ключ. Создание и отзыв выполняются в авторизованном профиле: Bearer-ключ не даёт доступа к управлению ключами, профилем или административным методам.

При отзыве ключ перестаёт проходить новые проверки авторизации; уже завершённые покупки сохраняются в истории аккаунта. Новый ключ, созданный в профиле, относится к новому API-клиенту: его история и Idempotency-Key независимы от прежнего. До отзыва ключа восстановите результат всех покупок с неопределённым исходом. Не повторяйте такую покупку с новым API-клиентом — это может создать второй заказ и повторное списание. При утрате ключа проверьте историю покупок в профиле и обратитесь в поддержку.

Для ключей, настроенных администратором, могут действовать срок окончания и список разрешённых IP. В списке используются публичные исходящие IP вашего backend, а не IP покупателя. Административный перевыпуск токена существующего API-клиента сохраняет его заказы и область идемпотентности, но немедленно отключает старый токен.

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Accept-Language: ru
X-Request-ID: your-order-123-check-1

Authorization обязателен для методов магазина. Content-Type обязателен для POST; поддерживается также тип с окончанием +json. Тело — UTF-8 JSON-объект. Предпочтительный язык: ru или en, по умолчанию ru. Приоритет: ?lang=, затем ?language=, X-Language, Accept-Language. Не передавайте секреты в URL.

X-Request-ID необязателен: 8–64 символа, латинские буквы, цифры, ., _, :, -. Сервер возвращает принятый ID в JSON и заголовке; неверный или отсутствующий ID заменяется новым. Это идентификатор диагностики. Для покупки POST /orders отдельно обязателен Idempotency-Key, защищающий от повторного списания.

Перепродажа: подключение партнёра

Партнёр принимает оплату в своём магазине. После подтверждённой оплаты его backend покупает товар в SupplyMe с заранее пополненного баланса и получает данные для выдачи своему покупателю. SupplyMe не обращается к платёжной системе партнёра и не проверяет оплату его покупателя: эту проверку выполняет интеграция партнёра.

Создайте ключ в «Профиль → API» и включите покупки с баланса. Ключ автоматически привязан к вашему аккаунту; выбирать чужой аккаунт нельзя. Примите правила магазина и заранее пополните баланс через профиль или бота. Привязанный аккаунт впоследствии не заменяется: другому владельцу нужен отдельный API-клиент. Если для интеграции нужны особые ограничения или административный перевыпуск существующего токена, обратитесь в поддержку.

Покупки идут по текущей розничной цене товара. Автоматическая выдача поддерживает text и link, количество от 1 до 10 за запрос. Ручная оптовая выдача, Telegram-файлы и промокоды в этом методе не поддерживаются. Партнёр назначает свою цену покупателю у себя. Пополнение баланса выполняется через существующий профиль/бот магазина. Не выдавайте покупателю API-токен партнёра.

МетодРазрешениеНазначение
GET /statusshop_read или разрешение старого ключа checkСостояние API, права и ограничения текущего ключа
GET /catalogshop_readТовары, цены, свободные остатки
GET /balanceshop_readТекущий баланс партнёра
POST /ordersshop_purchase и включённый shop_readПокупка и автоматическая выдача
GET /orders/{order_id}shop_readПовторное получение заказа и выдачи
GET /ordersshop_readИстория заказов этого API-клиента

Все суммы — целые сотые USDT: 1234 означает 12.34 USDT. API не списывает рубли или показанную посетителю цену перепродажи. Не используйте floating point для расчёта expected_total_usdt_cents: умножьте целое значение цены из каталога на количество.

Проверка подключения и ограничения

Начните с GET /status: этот метод не покупает товар и не списывает баланс. Он возвращает сведения о текущем API-ключе. Это состояние API SupplyMe; оно не подтверждает работоспособность сторонних сервисов или наличие нужного товара.

curl 'https://supply-me.ru/api/v1/status' \
  -H "Authorization: Bearer $SUPPLYME_API_KEY"
{"success":true,"request_id":"req_status_demo","code":"service.status","message":"API SupplyMe работает","data":{"status":"normal","api":{"version":"v1","status":"operational","currency":"USDT"},"permissions":{"shop_read":true,"shop_purchase":false},"limits":{"rate_limit_per_minute":60,"daily_limit":10000},"account":{"bound":true}}}

Значения лимитов в примере иллюстративные; используйте значения своего ключа. Лимиты действуют суммарно на методы текущего API-клиента. Суточный счётчик сбрасывается по границе суток UTC. Запрос, прошедший авторизацию и принятый в пределах лимита, расходует квоту, включая запрос с ошибочными параметрами, неуспешную покупку и идемпотентный повтор. 429 rate.minute_exceeded и 429 rate.daily_exceeded содержат заголовок Retry-After в секундах. Дополнительно действует ограничение частоты по исходящему IP.

Во время технических работ GET /status возвращает 503 shop.maintenance, data.status=maintenance и data.api.status=maintenance; новые покупки также могут возвращать 503 shop.maintenance. Каталог, баланс, история и повтор ранее сохранённой покупки остаются доступны при действующем ключе. Сохраняйте Idempotency-Key и исходное тело покупки для восстановления результата.

Проверка и активация сторонних CDK, массовая проверка, обновление Claude и ChatGPT через старые методы не предоставляются в SupplyMe. Пути /keys/check, /keys/bulk-check, /activate, /claude/refresh и /chatgpt/subscription возвращают 410 feature_retired; ключ из профиля не включает эти разрешения. Для закупки используйте методы магазина ниже.

Каталог партнёра и баланс

GET /catalog?limit=100&after_id=0 возвращает товары по возрастанию ID. limit от 1 до 100; after_id — ID последнего полученного товара, по умолчанию 0. Повторяйте с next_after_id, пока он не станет null. Товары без остатка могут присутствовать с available_quantity=0. Скрытые товары/категории и товары без автоматической выдачи не включаются.

{"success":true,"request_id":"req_catalog_demo","code":"shop.catalog","message":"Каталог получен","data":{"products":[{"id":42,"title":"Пример подписки","description":"Условия и срок подписки","category_id":3,"price_usdt_cents":1250,"currency":"USDT","delivery_type":"text","available_quantity":25,"max_quantity_per_order":10}],"next_after_id":null}}

Цена и остаток актуальны на момент чтения, но чтение их не резервирует. Между оплатой покупателем у партнёра и API-покупкой товар может закончиться. Интеграция должна предусмотреть уведомление оператора, ожидание пополнения или возврат в своей платёжной системе; возврат нельзя автоматически делать при неопределённом результате API-покупки.

GET /balance возвращает текущий остаток только привязанного аккаунта; параметры чужого пользователя не предусмотрены.

{"success":true,"request_id":"req_balance_demo","code":"shop.balance","message":"Баланс получен","data":{"balance_usdt_cents":10000,"currency":"USDT"}}

Покупка и получение ключей

POST /orders. Обязательны Bearer-токен, Content-Type: application/json, Idempotency-Key и JSON-тело до 8192 байт. Неизвестные поля отклоняются. Строки и дробные числа вместо целых недопустимы.

ПолеТипОписание
product_idinteger, > 0, обязательноID из /catalog
quantityinteger, 1–10По умолчанию 1
expected_total_usdt_centsinteger, 1–1000000000000, обязательноОжидаемая цена за единицу × количество

Idempotency-Key — от 8 до 128 символов: латинские буквы, цифры, _, ., :, -. Сохраните ключ вместе с параметрами в своей БД до первого запроса. Удобно использовать стабильный ID оплаченного заказа, например myshop-order-8457. Один ключ относится к одной покупке. Использование другого API-клиента или нового ключа создаёт независимую покупку, даже если продукт тот же.

curl --connect-timeout 10 --max-time 30 \
  'https://supply-me.ru/api/v1/orders' \
  -H "Authorization: Bearer $SUPPLYME_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: myshop-order-8457' \
  --data '{"product_id":42,"quantity":1,"expected_total_usdt_cents":1250}'
{"success":true,"request_id":"req_purchase_demo","code":"shop.order","message":"Заказ получен","data":{"replayed":false,"order":{"id":1901,"idempotency_key":"myshop-order-8457","product_id":42,"product_title":"Пример подписки","quantity":1,"status":"delivered","total_usdt_cents":1250,"currency":"USDT","balance_after_usdt_cents":8750,"delivery":{"type":"text","content":"EXAMPLE-KEY-NOT-REAL","items":["EXAMPLE-KEY-NOT-REAL"],"post_purchase_info":"Инструкция по активации"},"created_at":"2026-09-15T00:00:00+00:00"}}}

HTTP 201 означает новый оплаченный и выданный заказ. Повтор с тем же ключом и параметрами возвращает 200, data.replayed=true и прежний заказ. Списание, заказ, товарные остатки и квитанция повтора сохраняются одной транзакцией. После обрыва ответа или перезапуска сервера повторная покупка не создаётся.

Выдавайте товар своему покупателю только при data.order.status=delivered и delivery != null. delivery.items содержит отдельные выданные единицы с сохранением переносов строк; не разбивайте content по строкам, поскольку одна единица может включать логин, пароль и инструкцию. content — полная выдача заказа. post_purchase_info — дополнительная инструкция. Если поддержка вручную заменила содержимое заказа, items может быть null; актуальная выдача находится в content. Отображайте текст безопасно, без исполнения HTML/JavaScript из содержимого товара.

idempotency_key в заказе позволяет сопоставить запись из истории с заказом вашего магазина. balance_after_usdt_cents — остаток сразу после этой покупки; повтор возвращает то же значение. Для текущего баланса используйте /balance. Баланс и выдача также видны владельцу в обычной истории покупок SupplyMe.

Повторы, ошибки покупки и история

СитуацияДействие интеграции
Тайм-аут, разрыв, не-JSON, HTTP 502/503/504Результат может быть неопределённым. Повторяйте тот же POST с тем же ключом и телом, с паузой. Не создавайте новый ключ и не объявляйте покупку неоплаченной
429Соблюдайте Retry-After, сохраняйте ключ и тело
shop.idempotency_conflict, 409С этим ключом ранее отправлено другое тело. Восстановите исходные параметры; не обходите конфликт новым ключом без проверки прежней покупки
shop.price_changed, 409Цена не совпала, списания нет; data.current_total_usdt_cents содержит актуальную сумму. Согласуйте новую цену; для новой попытки нужен новый ключ
shop.insufficient_balance, 409Списания нет; доступны balance_usdt_cents и required_usdt_cents. После пополнения — осознанная новая попытка с новым ключом
shop.out_of_stock, 409Списания нет; data.available_quantity — остаток. После пополнения склада — новая попытка с новым ключом
shop.fulfillment_unavailable, 409Списание и выделение ключей отменены транзакцией. Перед новой попыткой проверьте товар с поддержкой
shop.product_unavailable, 404Товар скрыт, удалён, без цены или не относится к автоматической выдаче
shop.terms_required, shop.email_required, shop.balance_disabled, 403Покупка не совершена; отказ сохраняется за ключом. После устранения причины нужна осознанная новая попытка с новым Idempotency-Key
401 / 403Проверьте срок/отзыв ключа, разрешения, исходящий IP, привязку аккаунта, блокировку и принятие правил

Успешные покупки и определённые бизнес-ошибки покупки сохраняются за ключом без автоматического срока удаления. Повтор бизнес-ошибки вернёт тот же код с data.replayed=true, даже если баланс, цена, склад или принятие правил изменились. Ошибки формата до принятия покупки, ошибки auth.*, ограничения rate.*, отключённый/непривязанный аккаунт и временные 503 не фиксируют неуспешную покупку; после устранения причины допустим прежний ключ. Отказы shop.terms_required, shop.email_required и shop.balance_disabled сохраняются, как и ошибки цены, остатков и баланса. Даже при 503 ранее совершённая покупка могла сохраниться — ключ менять нельзя. Успех success=true не заменяет проверку статуса выдачи, особенно после действий поддержки.

GET /orders/{order_id} возвращает data.order той же формы. Чужой заказ, включая заказ другого API-клиента с тем же владельцем или покупку через сайт/бот, возвращает 404 shop.order_not_found. Для отменённого администратором заказа статус cancelled, выдача скрыта; новых списаний при повторе не происходит.

GET /orders?limit=100&after_id=0 возвращает data.orders и data.next_after_id. Порядок — возрастание ID заказа; передавайте next_after_id для следующей страницы до null. В списке только реально созданные заказы этого API-клиента, включая изменённые поддержкой. Отказанные попытки без заказа в список не входят. При утрате ID заказа повторите исходный POST с сохранённым ключом либо восстановите историю через список.

Пример покупки на Python

В примере requests установлен у партнёра. Функция ограничивает число попыток; при исчерпании попыток нужно оставить задачу в очереди своего магазина и позднее вызвать её с тем же ключом и тем же телом. Не генерируйте новый ключ в обработчике повтора. До вызова проверьте подпись/статус оплаты в своей платёжной системе.

import os
import time
import requests

def purchase_paid_order(saved_key, saved_body):
    headers = {"Authorization": "Bearer " + os.environ["SUPPLYME_API_KEY"],
               "Idempotency-Key": saved_key, "Accept-Language": "ru"}
    for attempt in range(4):
        try:
            response = requests.post("https://supply-me.ru/api/v1/orders",
                headers=headers, json=saved_body, timeout=(10, 30))
        except (requests.Timeout, requests.ConnectionError):
            time.sleep(min(2 ** attempt, 15))
            continue
        try:
            result = response.json()
        except ValueError:
            raise RuntimeError("Unknown result: queue the SAME key and body")
        if response.status_code == 429:
            # Queue this same operation for the indicated time; do not sleep a worker for a whole day.
            raise RuntimeError("Retry same key after " + response.headers.get("Retry-After", "60") + " seconds")
        if response.status_code >= 500:
            time.sleep(min(2 ** attempt, 15))
            continue
        if response.status_code not in (200, 201) or not result.get("success"):
            raise RuntimeError(f"{result.get('code')} request_id={result.get('request_id')}")
        order = result["data"]["order"]
        if order["status"] != "delivered" or order["delivery"] is None:
            raise RuntimeError("Order needs review; do not create another purchase")
        return order
    raise RuntimeError("Unknown result: queue the SAME key and body")

# These values must already be durably associated with your paid order:
# saved_key = "myshop-order-8457"
# saved_body = {"product_id": 42, "quantity": 1, "expected_total_usdt_cents": 1250}
# purchased = purchase_paid_order(saved_key, saved_body)
# Save purchased["id"] and delivery in your DB, then deliver to your customer exactly once.

В своём магазине также защитите повтор webhook и повтор выдачи: один оплаченный заказ → одна сохранённая операция закупки → одна выдача покупателю. Автоматическое списание у SupplyMe не заменяет эту защиту в сервисе партнёра. Проверяйте интеграцию на согласованном тестовом товаре: рабочий POST /orders действительно списывает баланс; sandbox/dry-run отсутствует.

Помощь с интеграцией

API-ключ можно создать самостоятельно в «Профиль → API». Если нужна помощь с подключением или восстановлением результата покупки, обратитесь в поддержку SupplyMe и укажите request_id, метод, код ответа и время UTC. Не передавайте токены или содержимое выданных товаров в публичных сообщениях.