API заказов и вебхуки (RU)
Подключите склад, службу фулфилмента или ИИ-агента к заказам — читайте их, отмечайте оплаченными или отправленными и получайте подписанный вебхук о каждом изменении.
Tiny Shops даёт внешним системам две вещи:
- HTTP API, чтобы прочитать заказ, изменить его статус и отправить его с трекингом.
- Вебхук, который отправляет (POST) каждый новый заказ и каждое изменение статуса или трекинга на выбранный вами URL.
Оба используют одну и ту же структуру заказа, поэтому всё, что пришло в вебхуке, можно поле в поле перечитать через API.
Reading in English? See the English version of this page.
Хотите, чтобы агент управлял не только заказами? Откройте инструкцию по подключению ИИ-агента.
1. Создайте API-токен
Откройте API-токены
В панели откройте Настройки → API-токены (/settings/api-tokens). Эту страницу видит только владелец магазина.
Создайте токен с нужным доступом
- Чтение — только
get_order. - Запись — всё на этой странице:
get_order,set_order_status,ship_order.
Скопируйте токен (tsh_live_…), когда он появится. Повторно он показан не будет.
Токен передаётся в каждом запросе как Bearer:
Authorization: Bearer tsh_live_…2. Три вызова
Все вызовы — POST https://mcp.tiny-shops.com/v1/<вызов> с JSON-телом. Те же вызовы доступны как MCP-инструменты с теми же именами на https://mcp.tiny-shops.com/mcp.
У каждого ответа одинаковая обёртка:
{ "ok": true, "data": { … } }
{ "ok": false, "error": { "code": "not_found", "message": "Order '42' not found" } }| HTTP | error.code | Значение |
|---|---|---|
| 400 | invalid_input | Тело не соответствует входным данным вызова |
| 401 | invalid_token | Токен отсутствует, некорректен, истёк или отозван |
| 403 | forbidden | Недостаточно прав у токена (например, токен на чтение вызывает ship_order) |
| 404 | not_found | Такого заказа нет в вашем магазине — заказы других магазинов никогда не видны |
| 404 | unknown_tool | Такого вызова нет |
| 429 | rate_limited | Слишком много вызовов; подождите Retry-After секунд |
Лимиты — на токен: 100 вызовов чтения и 30 вызовов записи в минуту.
get_order — прочитать заказ
curl -X POST https://mcp.tiny-shops.com/v1/get_order \
-H "Authorization: Bearer $TINYSHOPS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"orderId": 1042}'data — объект заказа.
set_order_status — изменить статус
curl -X POST https://mcp.tiny-shops.com/v1/set_order_status \
-H "Authorization: Bearer $TINYSHOPS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"orderId": 1042, "status": "PROCESSING"}'data — { "orderId", "status", "order" }. Смена статуса применяет те же правила магазина, что и в панели, — например, кэшбэк, который начисляется при определённом статусе.
| Статус | Значение |
|---|---|
PENDING | Новый заказ, ещё не подтверждён и не оплачен |
PROCESSING | Оплачен / собирается. «Отметить оплаченным» — значит установить этот статус. |
SHIPPED | Передан перевозчику — лучше используйте ship_order, он сохраняет и трекинг |
DELIVERED | Получен покупателем |
CANCELLED | Отменён |
ship_order — отметить отправленным с трекингом
curl -X POST https://mcp.tiny-shops.com/v1/ship_order \
-H "Authorization: Bearer $TINYSHOPS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"orderId": 1042, "carrier": "СДЭК", "trackingNumber": "1234567890", "trackingUrl": "https://www.cdek.ru/ru/tracking?order_id=1234567890", "notify": true}'| Поле | Обязательно | Примечания |
|---|---|---|
orderId | да | |
trackingUrl | одно из трёх | Должен начинаться с http:// или https:// |
carrier | одно из трёх | До 100 символов |
trackingNumber | одно из трёх | До 100 символов |
notify | нет, по умолчанию false | true отправляет покупателю то же сообщение в Telegram, что и кнопка Отправить и уведомить в панели |
Статус становится SHIPPED, поля трекинга сохраняются. С notify: true покупатель получает сообщение об отправке вашего магазина; кнопка Отследить заказ появляется, только если есть trackingUrl, иначе перевозчик и трек-номер пишутся в тексте сообщения.
data — { "order", "notified", "notifyFailureReason" }. notified отсутствует, если уведомление не запрашивали, и равно false с причиной (bot_not_configured, unreachable, send_failed), если сообщение отправить не удалось, — заказ в любом случае отмечен отправленным.
3. Вебхуки
Настройка
Откройте Настройки → Вебхуки заказов, укажите публичный https://-адрес и сохраните. Вы один раз получите секрет подписи (whsec_…) — сохраните его. Потеряли? Нажмите Сменить секрет; старый сразу перестанет работать. На странице также видны последние доставки.
Кнопка Отправить тестовое событие синхронно отправляет подписанный пример order.created. В тестовой обёртке есть "test": true и демонстрационные данные; настоящий заказ не создаётся. Ваш адрес всё равно должен проверить подпись и вернуть 2xx.
У каждого магазина один URL вебхука.
События
| Событие | Когда |
|---|---|
order.created | Каждый новый заказ, при любом способе оформления и оплаты |
order.updated | Изменился статус, трекинг или состав заказа — в панели, через API или через MCP. Если выставить заказу тот же статус, что у него уже есть, событие не отправляется |
Запрос
POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: TinyShops-Webhooks/1
X-TinyShops-Event: order.updated
X-TinyShops-Delivery: 3b0c4f7e-5a41-4d8e-9f0e-2d6b1c1a9e27
X-TinyShops-Signature: 5f1c…e9a2
{
"id": "3b0c4f7e-5a41-4d8e-9f0e-2d6b1c1a9e27",
"event": "order.updated",
"createdAt": "2026-09-23T10:15:02.114Z",
"data": { …объект заказа… }
}X-TinyShops-Signature— HMAC-SHA256 от тела запроса как есть, в нижнем регистре hex, с секретом подписи в качестве ключа.X-TinyShops-Deliveryиidв теле — идентификатор доставки. Он одинаков при всех повторах этой доставки.
Проверка подписи
Считайте HMAC по сырым байтам полученного тела, до разбора JSON, и сравнивайте за постоянное время.
import { createHmac, timingSafeEqual } from 'node:crypto';
import express from 'express';
const app = express();
app.post(
'/tinyshops/orders',
express.raw({ type: 'application/json' }),
(req, res) => {
const expected = createHmac('sha256', process.env.TINYSHOPS_WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
const received = req.get('X-TinyShops-Signature') ?? '';
const valid =
received.length === expected.length &&
timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!valid) return res.status(401).end();
const event = JSON.parse(req.body.toString('utf8'));
res.status(204).end(); // ответьте быстро, работу сделайте потом
handleOrderEvent(event);
},
);import hashlib, hmac, json, os
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["TINYSHOPS_WEBHOOK_SECRET"].encode()
@app.post("/tinyshops/orders")
def tinyshops_orders():
expected = hmac.new(SECRET, request.get_data(), hashlib.sha256).hexdigest()
received = request.headers.get("X-TinyShops-Signature", "")
if not hmac.compare_digest(received, expected):
abort(401)
event = json.loads(request.get_data())
handle_order_event(event)
return "", 204Повторы
- Доставка успешна, если ваш адрес отвечает любым кодом 2xx в течение 10 секунд.
- Иначе она повторяется до 5 раз: через 1 минуту, 5 минут, 30 минут, 2 часа и 6 часов. После шестой неудачной попытки доставка отмечается как неудачная и показывается на странице настроек.
- События отправляются примерно в течение минуты после изменения.
- Редиректы не выполняются: URL должен отвечать сам.
Идемпотентность и порядок
- Используйте идентификатор доставки (
X-TinyShops-Deliveryилиidв теле), чтобы отсеивать повторы. Сохраняйте состояние с самым новымdata.updatedAt. Не убирайте дубликаты только по ID заказа и статусу: трекинг или состав заказа могут измениться без смены статуса. - Если установить заказу тот же статус, который уже установлен, событие не отправляется.
- Что-то пропустили? Вызовите
get_order— он возвращает ровно тот объект, который пришёл бы в вебхуке.
Объект заказа
{
"id": 1042,
"status": "SHIPPED",
"paymentMethod": "Stripe",
"totalPrice": 459000,
"tipAmount": null,
"currency": "RUB",
"telegramUserId": "5566778899",
"shippingAddress": { "name": "Иван Петров", "phone_number": "+79991234567" },
"checkoutData": [{ "id": "f1", "label": "Адрес", "type": "text", "value": "ул. Ленина, 1" }],
"items": [
{
"productId": "sneaker-01",
"title": "Кроссовки для бега",
"quantity": 1,
"price": 459000,
"size": "42",
"variantOptionTitle": null,
"variantValue": null
}
],
"trackingUrl": "https://www.cdek.ru/ru/tracking?order_id=1234567890",
"carrier": "СДЭК",
"trackingNumber": "1234567890",
"createdAt": "2026-09-23T09:58:40.512Z",
"updatedAt": "2026-09-23T10:15:02.101Z"
}| Поле | Примечания |
|---|---|
totalPrice, items[].price, tipAmount | В минимальных единицах currency (копейки, центы; целые звёзды для XTR) |
currency | Код валюты магазина |
telegramUserId | Telegram user id покупателя, строкой (может превышать 2^53) |
shippingAddress | Данные доставки, собранные при оплате (например, order info от Telegram), или null |
checkoutData | Заполненные покупателем поля формы оформления, или null |
trackingUrl, carrier, trackingNumber | null, пока не заданы |