Новое API Слуха для модулей и интеграций. API v1 работает параллельно и без срока отключения.
- Адрес:
https://slyh.ru/api/v2 - Формат: JSON на входе и выходе, кодировка UTF-8, заголовок
Content-Type: application/json. - Авторизация: токен сайта в заголовке
Authorization: Bearer <токен>. Токены выпускаются в кабинете, раздел «Интеграция»: у сайта есть основной токен и можно создать дополнительные с названием (например, отдельный для модуля или склада); дополнительный токен отзывается сразу, прежний основной после перевыпуска действует ещё 24 часа. - Лимит запросов: 600 в минуту на токен (у каждого токена сайта свой). При превышении —
429 Too Many Requests.
Ответы и ошибки
Успех: {"data": {...}}. Ошибка: {"error": {"code": "...", "message": "...", "details": {...}}}.
| HTTP | code |
Когда |
|---|---|---|
| 401 | missing_token |
нет заголовка Authorization |
| 401 | invalid_token |
токен неверный, сайт отключён, тариф не оплачен или закончился |
| 403 | feature_not_available |
возможность не входит в тариф (для POST /statuses вместо 403 возвращается 202 с processed: false) |
| 404 | not_found |
посылка, сообщение или уведомление не найдены |
| 409 | request_in_progress |
запрос с тем же Idempotency-Key ещё выполняется |
| 422 | validation_failed |
тело запроса не прошло проверку; в details — ошибки по полям |
| 422 | idempotency_conflict |
Idempotency-Key уже использован с другим запросом |
| 422 | template_not_found |
шаблон с таким кодом не найден |
| 429 | — | превышен лимит запросов |
| 503 | api_disabled |
API временно выключен |
Идемпотентность
Добавьте заголовок Idempotency-Key (до 128 символов, например UUID) к POST-запросам. Повтор запроса с тем же ключом и тем же телом возвращает прежний ответ с заголовком Idempotent-Replayed: true и не выполняет действие снова. Это безопасно при обрывах связи и повторах. Ключ хранится 24 часа.
Независимо от заголовка, повторы не создают дублей: трек уникален в рамках сайта, а пара «заказ + статус» не отправляется покупателю дважды.
Покупатель
Везде, где нужен покупатель, передаётся объект customer; обязателен телефон или email.
{"name": "Анна Петрова", "phone": "+7 900 111-22-33", "email": "anna@example.ru"}
Телефон приводится к виду +7XXXXXXXXXX.
GET /ping — проверка токена
curl https://slyh.ru/api/v2/ping -H "Authorization: Bearer $TOKEN"
{"data": {"site": "shop.ru", "rate": "Бизнес", "features": ["tracking", "statuses"], "valid_until": "2026-12-01T00:00:00+05:00", "events_this_month": 128, "tracks_this_month": 41, "limits": {"events_per_month": 300, "events_used": 128, "events_left": 172, "sites": 1}}}
| Поле | Значение |
|---|---|
site |
домен сайта, к которому относится токен |
rate |
название тарифа |
features |
возможности тарифа: tracking, statuses, sms, channels |
valid_until |
до какой даты оплачен тариф; null — без ограничения срока |
events_this_month |
событий принято в текущем месяце (треки, статусы, сообщения) |
tracks_this_month |
треков (посылок) принято в текущем месяце |
limits.events_per_month |
лимит событий тарифа в месяц; null — без ограничения |
limits.events_used, limits.events_left |
израсходовано и осталось событий (по всем сайтам фирмы); events_left — null, если лимита нет |
limits.sites |
сколько сайтов допускает тариф; null — без ограничения |
Когда лимит исчерпан, события принимаются и сохраняются, но уведомления встают на паузу до следующего месяца или продления тарифа.
POST /tracking — принять трек
Требует в тарифе возможность tracking.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
track_number |
строка до 64 | да | трек-номер |
carrier |
строка до 64 | нет | служба доставки (например, sdek); если задана, определение службы не выполняется |
order |
строка до 191 | нет | номер заказа в магазине |
customer |
объект | нет | покупатель: name, phone, email. Все поля необязательны: магазин может не передавать данные клиента. Трек тогда отслеживается и доступен сайту, но уведомлений по нему нет. Повторная передача того же трека с phone или email привязывает покупателя к уже принятой посылке |
curl -X POST https://slyh.ru/api/v2/tracking \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-H "Idempotency-Key: 7d1f0c34-0c5e-4f6e-9a39-2a1c1d3f0001" \
-d '{"track_number":"RB123456789CN","carrier":"sdek","order":"A-1001","customer":{"name":"Анна","phone":"+79001112233"}}'
Ответ 201 (трек принят) или 200 (такой трек у сайта уже есть, duplicate: true):
{"data": {"id": 15, "tracking_number": "RB123456789CN", "carrier": "sdek", "status": "in_transit", "status_code": 0, "created_at": "2026-10-02T12:00:00+05:00", "last_polled_at": null, "duplicate": false}}
GET /shipments/{track_number} — состояние посылки
Статусы (status / status_code): in_transit / 0 — в пути, delivered / 1 — доставлена, untrackable / 2 — отследить не удалось, return_or_long / 3 — возврат или долгая доставка, carrier_unknown / 4 — служба доставки не опознана.
{"data": {"id": 15, "tracking_number": "RB123456789CN", "status": "delivered", "status_code": 1, "checkpoints": [{"time": "2026-10-03T10:00:00+05:00", "status_code": "delivered", "message": "Вручена", "location": "Москва"}]}}
POST /statuses — статус заказа
Требует в тарифе возможность statuses.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
order |
строка до 191 | да | номер заказа; связывает статусы одного заказа |
status |
строка до 1000 | да | текст статуса |
customer |
объект | да | покупатель |
Ответ 201, либо 200 с duplicate: true, если эта пара «заказ + статус» уже принята.
{"data": {"order": "A-1001", "status": "Передан в доставку", "duplicate": false, "processed": true}}
Тариф без статусов (бесплатный). Запрос не отклоняется: статус записывается (в журнал и в заказ, виден в кабинете), но не обрабатывается. Ответ 202 с processed: false и stored: true; покупатель, события и уведомления не создаются, лимит событий не расходуется, повтор той же пары «заказ + статус» даёт duplicate: true. Поле customer при этом необязательно. Так магазин может отправлять статусы всегда, а отправка покупателям включится после перехода на тариф со статусами (прежние статусы задним числом не отправляются).
{"data": {"order": "A-1001", "status": "Передан в доставку", "duplicate": false, "processed": false, "stored": true, "reason": "feature_not_in_plan", "message": "Статусы заказов не входят в ваш тариф: статус записан, но покупателю не отправляется."}}
POST /messages — сообщение по шаблону
Заменяет POST /api/sms_wa из API v1. Отправляется по каналам, подключённым у покупателя, как и остальные уведомления.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
template |
строка | либо template, либо text |
код шаблона из кабинета («Интеграция» → «Шаблоны для API v2») |
variables |
объект | нет | значения для {переменных} шаблона |
text |
строка до 2000 | либо template, либо text |
готовый текст без шаблона |
channel |
строка | нет | принудительный канал: telegram, max, vk, whatsapp, email, sms |
customer |
объект | да | получатель |
curl -X POST https://slyh.ru/api/v2/messages \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"template":"order_ready","variables":{"name":"Анна"},"customer":{"phone":"+79001112233"}}'
Ответ 202: {"data": {"id": 42, "status": "queued"}}. Состояние: GET /messages/42.
{"data": {"id": 42, "processed": true, "created_at": "2026-10-02T12:00:00+05:00", "notifications": [{"id": 77, "channel": "telegram", "status": "delivered", "attempts": 1, "error": null}]}}
GET /notifications/{id} — статус уведомления
Статусы: queued — в очереди, sent — отправлено, delivered — доставлено, failed — не доставлено (причина в error).
Вебхуки
Если в кабинете указан адрес вебхука, Слух отправит POST с JSON:
{"id": "1f6c...", "event": "shipment.delivered", "created_at": "2026-10-03T10:00:05+05:00", "data": {"tracking_number": "RB123456789CN", "carrier": "sdek", "status": "delivered"}}
События и поля data:
| Событие | Поля data |
|---|---|
shipment.delivered — посылка доставлена |
tracking_number, carrier, status, shipment_id, order (номер заказа магазина или null) |
notification.failed — уведомление не доставлено ни по основному, ни по запасному каналу |
notification_id, channel, event, error, tracking_number и order (если событие относится к посылке или заказу, иначе null) |
Персональные данные покупателя (телефон, email, имя) в вебхуки не включаются: связывайте по tracking_number или order.
Подпись: заголовок X-Slyh-Signature: sha256=<HMAC-SHA256 от тела запроса с вашим секретом>. Проверяйте её, прежде чем доверять запросу. Ответ 2xx — принято; иначе повторы через 1, 5, 30 и 120 минут (всего 5 попыток).
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (!hash_equals($expected, $_SERVER['HTTP_X_SLYH_SIGNATURE'] ?? '')) {
http_response_code(403);
exit;
}
Примеры
PHP
$ch = curl_init('https://slyh.ru/api/v2/tracking');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $token,
'Content-Type: application/json',
'Idempotency-Key: ' . $orderId . '-track',
],
CURLOPT_POSTFIELDS => json_encode([
'track_number' => 'RB123456789CN',
'order' => $orderId,
'customer' => ['name' => $name, 'phone' => $phone, 'email' => $email],
], JSON_UNESCAPED_UNICODE),
]);
$response = json_decode(curl_exec($ch), true);
JavaScript
const response = await fetch('https://slyh.ru/api/v2/statuses', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
'Idempotency-Key': `${orderId}-${status}`,
},
body: JSON.stringify({ order: orderId, status, customer: { phone, email } }),
});
const result = await response.json(); // { data: {...} } или { error: {...} }
Подключение сайта модулем (connect/start, connect/confirm)
Модуль может сам подключить сайт и получить токен, без ручной регистрации. Токен в запросах не нужен, лимиты: 10 заявок в час с одного IP и 5 в час на один домен, 30 подтверждений в час с IP. Сообщения об ошибках приходят по-русски в error.message.
1. POST /api/v2/connect/start: {"domain": "shop.ru", "email": "admin@shop.ru"}; необязательно token_name (имя дополнительного токена, по умолчанию «ReadyScript tracking» для платформы ReadyScript, иначе «Модуль <имя модуля>»). Домен можно передавать с www, схемой и путём: он нормализуется; IP-адреса, порты, localhost и домены slyh.ru отвергаются (422).
{"data": {"request_id": "kV3x…", "code": "slyh-4f1c…", "verify_url": "https://shop.ru/tracking-verify", "expires_at": "2026-10-05T14:30:00+05:00", "expires_in": 1800, "existing": false}}
Ответ 202. existing: true, если сайт уже есть в Слухе. Код действует 30 минут.
2. Модуль отдаёт код по адресу https://<сайт>/tracking-verify: ответ 200 с телом, равным коду (без HTML, пробелы по краям допустимы). Страница должна открываться без авторизации.
3. POST /api/v2/connect/confirm: {"request_id": "kV3x…"}. Слух сам запрашивает страницу: только https, адрес сайта должен вести на публичный IP (внутренние адреса отвергаются), редиректы допустимы лишь между shop.ru и www.shop.ru (не больше двух), таймаут 5 секунд. Не более пяти попыток на заявку.
Ответ 201:
{"data": {"token": "…48 знаков…", "existing": false, "site": "shop.ru", "token_name": null, "message": "Сайт подключён на бесплатном тарифе. Доступ в кабинет отправлен на admin@shop.ru."}}
- Новый сайт (
existing: false): создаётся фирма на бесплатном тарифе, владелец кабинета с этим e-mail (ему уходит письмо со ссылкой для создания пароля),token— основной токен сайта. - Сайт уже в Слухе (
existing: true): основной токен и кабинет не затрагиваются; выпускается дополнительный токен с именемtoken_name, он действует наравне с основным и отзывается в кабинете («Интеграция» → токены API). Прежний токен с тем же именем отзывается (переустановка модуля). Владельцу кабинета уходит письмо «для сайта выпущен токен модуля». Токен выдаётся один раз.
| HTTP | code |
Когда |
|---|---|---|
| 422 | validation_failed, invalid_domain |
не указан или некорректен домен либо e-mail |
| 403 | site_disabled |
сайт отключён в Слухе |
| 404 | request_not_found |
заявка не найдена |
| 409 | request_used |
заявка уже использована; email_taken: e-mail уже занят в кабинете другим сайтом; token_limit: у сайта максимум токенов |
| 422 | request_expired, verification_failed |
срок кода истёк; страница не открылась, ответила не 200 или код не совпал |
| 429 | too_many_requests, too_many_attempts |
исчерпан лимит заявок на домен или попыток подтверждения |
Заголовки модулей и платформ
Модули для CMS добавляют в каждый запрос заголовки, по которым видно, откуда пришли данные и какая версия работает у магазина:
| Заголовок | Пример | Значение |
|---|---|---|
X-Slyh-Module |
woocommerce/1.0.0 |
название и версия модуля |
X-Slyh-Platform |
WordPress/6.7 WooCommerce/9.4 |
платформа и её версия |
Заголовки необязательны для собственных интеграций. Слух записывает значения в журнал запросов (до 64 знаков, только латиница, цифры и . _ / + -): так видно, какие версии модулей работают у клиентов. Готовые модули: WordPress / WooCommerce, Tilda, JS-решение.
Совместимость с API v1
Адреса и поля API v1 (/api/tracking, /api/statuses, /readyscript.php и другие) не менялись и работают без срока отключения. Описание — в документации API v1.