Socrate Store API
Каталог, баланс и закупка товаров из вашего магазина. Один запрос оформляет заказ, списывает деньги и возвращает доступный товар. Разрешённые предзаказы выдаются после поступления.
https://api.socrate.store- Авторизация
X-API-Key- Деньги
- RUB · копейки
- Данные
- JSON / UTF-8
- Выдача
- Текст · предзаказы
API работает между серверами. Покупатель платит вашему магазину, а закупка списывается с вашего баланса в Socrate Store.
Быстрый старт
Сначала проверьте доступ и баланс. Этот запрос ничего не покупает.
- 1
Получите API-ключ
Откройте в боте «Профиль → API для реселлеров → Получить API-ключ» и подтвердите создание. Одобрение администратора не требуется. Команда
/requestapiоткрывает тот же раздел. - 2
Пополните баланс
Используется баланс того же аккаунта в боте. API не создаёт отдельный кошелёк.
- 3
Проверьте подключение
Сохраните ключ в переменной окружения
SOCRATE_API_KEYна своём сервере.
curl --fail-with-body 'https://api.socrate.store/v1/account' \
-H "X-API-Key: $SOCRATE_API_KEY"
Пример ответа · 200 OK
{
"user_id": 123456789,
"active": true,
"currency": "RUB",
"balance_minor": 50000,
"max_quantity": 100,
"rate_limit_per_minute": 60,
"accept_preorders": false
}Числа и товары в примерах условные. 50000 копеек = 500 ₽. Python использует стандартную библиотеку; Node.js — встроенный fetch (18+). Пример cURL рассчитан на Bash.
Доступ и ключи
Каждый реселлер получает собственный ключ, привязанный к его Telegram-аккаунту. Все методы /v1/ требуют этот заголовок:
X-API-Key: sr_YOUR_SECRET_KEYПервое подключение
Зарегистрируйтесь командой /start и откройте «Профиль → API для реселлеров». Доступ открыт зарегистрированным пользователям без блокировки аккаунта или отзыва API-доступа. Нажмите «Получить API-ключ» и подтвердите. Бот отправит ключ только в ваш личный чат; повторное получение не заменяет уже выданный ключ.
Замена ключа
В том же разделе нажмите «Заменить API-ключ» и подтвердите. Старый ключ перестанет работать, новый придёт в личный чат. Самостоятельная замена доступна не чаще раза в минуту. Администратор может отозвать доступ; получить новый ключ в обход отзыва нельзя.
Не вставляйте его в браузерный JavaScript, URL, публичный код или логи. Храните ключ в секретах сервера. При утечке замените ключ в профиле бота и обновите интеграцию. Для отключения доступа обратитесь к администратору.
Блокировка аккаунта в магазине или отзыв API-доступа запрещают новые API-запросы. При 401 проверьте ключ; при 403 свяжитесь с администратором. Настройки предзаказов доступны через /api_settings в боте или PATCH /v1/account/settings.
Схема подключения
Ваш сервер отвечает за заказ покупателя и свою наценку. Socrate Store отвечает за закупку и выдачу доступного товара.
X-API-Key/v1/ordersCOMMITorder_id и items[].content. Ваш сервер сохраняет их и выдаёт товар покупателю.Публичная граница
Интеграция обращается только к HTTPS-адресу API. Прямой доступ к базе магазина не нужен и не предоставляется.
Граница ответственности
Успешная закупка не подтверждает оплату в вашем магазине. Проверка платежа клиента и защита от повторной выдачи клиенту остаются на вашей стороне.
Методы API
Адреса ниже добавляются к https://api.socrate.store. Ключ передаётся в каждом запросе.
PATCH /v1/account/settings — настройка приёма предзаказов своего аккаунта. Тело: {"accept_preorders": false} для отключения или true для включения.
/v1/accountБаланс и лимиты
GET/v1/productsКаталог товаров
GET/v1/products/{sku}Карточка товара
POST/v1/ordersПокупка и выдача
GET/v1/orders/{order_id}Заказ по ID магазина
GET/v1/orders?external_order_id=...Заказ по вашему ID
GET/v1/orders/recentИстория с пагинацией
Машиночитаемая спецификация: скачать OpenAPI 3.0. Браузерная отправка запросов с ключом на этой странице не предусмотрена.
Каталог и цены
/v1/products?language=ruПо умолчанию возвращается русский текст. Для английского передайте language=en. Если перевод товара не заполнен, используется русский текст.
{
"products": [{
"sku": "g-7",
"name": "Пример товара",
"description": "Описание товара",
"currency": "RUB",
"unit_price_minor": 7900,
"shop_unit_price_minor": 7900,
"available_quantity": 20,
"min_quantity": 1,
"max_quantity": 100,
"bulk_discounts": [{"min_quantity": 5, "percent": "5.00"}],
"personal_discounts": [],
"pricing_mode": "public",
"fixed_price_expired": false,
"preorder_enabled": true,
"preorder_available": false,
"delivery_type": "text"
}]
}Карточка GET /v1/products/g-7 возвращает объект товара без обёртки products. sku имеет формат g-<ID>: всегда берите его из каталога, не составляйте из названия.
Остаток
available_quantity — доступные для API текстовые единицы с учётом оплаченной очереди магазина. Остаток может измениться между просмотром и покупкой. Товары с нулевым остатком могут присутствовать в каталоге.
Оптовая скидка
Применяется подходящий порог из bulk_discounts. Цена unit_price_minor — базовая, до скидки. Итог берите из charged_minor ответа на покупку.
charged_minor: 37525Это пример расчёта, не действующее предложение. Пустой массив bulk_discounts: [] означает отсутствие оптовых скидок.
Персональные условия реселлера
Администратор может назначить процентные пороги или фиксированную цену для конкретного товара и вашего аккаунта. Проценты из personal_discounts зависят от количества в одном заказе, а не от накопленных покупок. Общая и персональная скидки не складываются: применяется более выгодная.
При pricing_mode: personal_fixed поле unit_price_minor уже содержит вашу фиксированную цену; дополнительные проценты не применяются. shop_unit_price_minor показывает текущую цену магазина. Каталог персонализирован по API-ключу.
Если цена магазина выросла на 10% или больше от цены на момент фиксации, фиксация снимается и бот отправляет уведомление. Например: база 300 ₽, новая цена 330 ₽. Новые покупки идут по обычным условиям и требуют max_unit_price_minor. При fixed_price_expired: true обратитесь к администратору для новой фиксации. Уже оплаченные заказы не дорожают.
Создание заказа
/v1/ordersСписание с балансаДо отправки сохраните в своей системе ID заказа, ключ повтора и тело запроса. Для одного заказа они должны оставаться неизменными.
| Поле | Формат | Назначение |
|---|---|---|
external_order_idобязательно | Строка, 1–128 символов | Уникальный ID заказа в вашей системе. |
skuобязательно | Строка вида g-7 | SKU из каталога. |
quantityобязательно | Целое число, 1–100 | Дополнительно ограничено лимитом аккаунта и остатком. |
max_unit_price_minor | Целое число ≥ 0 | Верхний предел unit_price_minor до процентных скидок либо действующей фиксированной цены. Обязателен для предзаказа и после снятия фиксации; рекомендуется всегда. |
allow_preorder | Boolean, по умолчанию false | Явное согласие на списание всей суммы сейчас и выдачу недостающего товара после поступления. Требует разрешения у товара и аккаунта. |
Idempotency-Keyзаголовок, обязательно | Строка, 1–128 символов | Ключ повтора. Уникален в пределах вашего аккаунта; для нового заказа создаётся новый. |
curl --fail-with-body 'https://api.socrate.store/v1/orders' \
-H "X-API-Key: $SOCRATE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: partner-order-1001' \
-d '{"external_order_id":"1001","sku":"g-7","quantity":2,"max_unit_price_minor":7900}'{
"order_id": 123,
"external_order_id": "1001",
"status": "completed",
"sku": "g-7",
"quantity": 2,
"delivered_quantity": 2,
"pending_quantity": 0,
"refunded_minor": 0,
"is_preorder": false,
"pricing": {"unit_price_minor": 7900, "charged_minor": 15800, "source": "public", "discount_percent": "0.00"},
"charged_minor": 15800,
"balance_minor": 34200,
"items": [
{"position": 1, "content": "EXAMPLE-ITEM-001"},
{"position": 2, "content": "EXAMPLE-ITEM-002"}
],
"idempotency_replayed": false
}items[].content — полученный товар. Сохраните его в защищённой базе своего магазина. Не отправляйте содержимое в публичные логи.
balance_minor фиксирует баланс после этой покупки. При повторе возвращается сохранённое значение, а не текущий баланс; актуальный баланс запрашивается через /v1/account.
Предзаказы и ожидание товара
По умолчанию предзаказы аккаунта выключены. Для покупки с ожиданием нужны одновременно: preorder_enabled: true у товара, accept_preorders: true у аккаунта, allow_preorder: true и лимит цены в запросе покупки. Без этих разрешений нехватка остатка не приводит к списанию.
Включение через API означает согласие на немедленное списание полной суммы при разрешённом предзаказе. Доступный товар выдаётся сразу, недостающий попадает в общую очередь магазина по порядку оплаты. Срок поступления не гарантирован. Бот уведомляет об оформленном предзаказе.
curl --fail-with-body -X PATCH 'https://api.socrate.store/v1/account/settings' \
-H "X-API-Key: $SOCRATE_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"accept_preorders":false}'Эта команда запрещает новые предзаказы; уже оплаченные не отменяются. Аналогичная настройка есть в боте: /api_settings.
У заказа в ожидании status: pending. Проверяйте GET /v1/orders/{order_id} с разумными паузами в пределах лимита API: items содержит всю уже выданную часть, pending_quantity — остаток. Новые единицы выдавайте клиенту один раз по паре order_id + position. При завершении статус станет completed. Повтор POST возвращает актуальную выдачу без нового списания.
Отмену необработанного остатка согласуйте с администратором. Полная отмена имеет статус cancelled; при частичной выдаче и возврате остатка — completed. quantity и charged_minor хранят исходную покупку, refunded_minor — возврат. Поле pricing хранит исходный расчёт; у старых заказов оно может быть null.
Повторы и сбои
Таймаут не означает, что покупки не было. Сервер мог провести заказ, а соединение прервалось до получения ответа.
- 1Отправьте POST /v1/ordersПокупка
Сохранённые ID, ключ и тело запроса.
- 2Ответ потерян или пришёл 5xx?Проверка
Запросите
GET /v1/orders?external_order_id=1001. - 3Заказ найден: сохраните результатВосстановление
Заказ не найден: повторите исходный POST с теми же двумя ID и тем же телом.
- 4Выдайте каждую единицу один разЗавершение
Защитите выдачу по паре
order_id + position, в том числе при поступлении частей предзаказа.
201 — новый заказ
Успешная первая покупка. Товар, списание и запись заказа фиксируются одной транзакцией.
200 — повтор
idempotency_replayed: true. Возвращаются прежний заказ и выданные единицы без нового списания.
Для повтора должны совпадать оба идентификатора и всё тело запроса, включая max_unit_price_minor и allow_preorder. Изменение любого из них при повторном использовании другого вызывает IDEMPOTENCY_CONFLICT.
После 429 дождитесь времени из Retry-After. При сетевой ошибке или 5xx используйте ограниченное число повторов с растущими паузами, сохраняя идентификаторы. Ротация API-ключа не меняет привязку заказов к аккаунту.
История заказов
Ключ даёт доступ только к API-заказам своего аккаунта. Заказы других пользователей недоступны.
GET /v1/orders/123
GET /v1/orders?external_order_id=1001
GET /v1/orders/recent?limit=50Первые два метода возвращают тот же формат заказа, что и покупка. У обычного чтения idempotency_replayed равно false: этот флаг отмечает именно повторный POST.
{
"orders": [],
"next_before_id": null
}Выше показана пустая история. Каждый элемент orders имеет формат ответа покупки. Заказы идут от новых к старым. Если ответ содержит next_before_id: 123, следующая страница: /v1/orders/recent?limit=50&before_id=123. Значение next_before_id: null означает конец списка. limit: 1–100, по умолчанию 50.
Ошибки
Обрабатывайте error.code, а не текст message. Для обращения в поддержку сохраните request_id, не прикладывая ключ и содержимое товара.
| HTTP | Код | Действие |
|---|---|---|
| 400 | INVALID_REQUEST | Исправьте JSON, заголовки или параметры запроса. |
| 401 | INVALID_API_KEY | Проверьте полный ключ и отсутствие лишних символов. Старый ключ после замены недействителен. |
| 402 | INSUFFICIENT_BALANCE | Пополните баланс. Покупка не проведена. |
| 403 | API_ACCESS_INACTIVE | Доступ отключён или аккаунт заблокирован. Обратитесь к администратору. |
| 404 | PRODUCT_UNAVAILABLE | Товар отсутствует, скрыт, архивирован или SKU некорректен. Обновите каталог. |
| 404 | ORDER_NOT_FOUND | Заказ с таким ID не найден среди ваших API-заказов. |
| 404 | NOT_FOUND | Проверьте путь метода API. |
| 409 | OUT_OF_STOCK | Не хватает доступных текстовых единиц. Обновите остаток; списания нет. |
| 409 | PREORDER_DISABLED | Предзаказы запрещены у товара или аккаунта. Списания нет. |
| 409 | PRICE_LIMIT_REQUIRED | Передайте max_unit_price_minor: он обязателен для предзаказа и после снятия фиксации. Списания нет. |
| 409 | PRICE_CHANGED | Базовая цена выше переданного предела. Проверьте новую цену перед покупкой. |
| 409 | IDEMPOTENCY_CONFLICT | Проверьте прежний заказ: один из ID уже использован с другим запросом. Не меняйте ID вслепую. |
| 429 | RATE_LIMITED | Выдержите паузу из Retry-After и повторите тот же запрос. |
| 500 | INTERNAL_ERROR | Сначала проверьте заказ по ID, затем повторяйте с прежними идентификаторами. |
{
"error": {
"code": "OUT_OF_STOCK",
"message": "Not enough text stock.",
"request_id": "e6df1835a9112a72",
"retryable": false,
"details": {"available_quantity": 0}
}
}Прокси может вернуть не JSON, например при 413 (слишком большое тело) или 502/504. Проверяйте HTTP-статус и формат ответа до разбора JSON. Флаг retryable сам по себе не доказывает, что списания не было.
Лимиты и ограничения
- Запросы
- По умолчанию 60 в минуту на ключ. Текущее значение —
rate_limit_per_minuteв/v1/account. Чтение, настройки и покупка используют общий лимит. - Количество
- 1–100 единиц за запрос, не больше
max_quantityаккаунта. Недостающий остаток можно предзаказать только с тремя разрешениями. - Тело запроса
- До 8 КиБ,
Content-Type: application/json. - Деньги
- Целые копейки,
currency: RUB. Значение7900означает 79 ₽, не 7 900 ₽. - Доставка
- Текстовые товары из наличия и разрешённые предзаказы. Файловая выдача через API не поддерживается.
- Webhooks
- Отсутствуют. Результат и готовность предзаказа проверяются методами чтения заказа.
- Скидки
- Общие и персональные пороги либо индивидуальная фиксированная цена. Промокоды через API не применяются.
Проверьте баланс, сохранение выдачи, обработку недостатка товара и точный повтор одного тестового заказа. Тестовой среды с бесплатными покупками нет: успешный POST в рабочее API списывает реальные средства с баланса.