API

Документация API v2

Методы, заголовки, коды ошибок и примеры.

Новое 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.

Документация API v2

Методы, заголовки, коды ошибок и примеры.