Партнёрский API
Проводите грузы, деньги и заказы через Садарак
Версионированный REST API (/v1), источник истины — OpenAPI: читайте назначенные вам заказы, сообщайте о событиях доставки и получайте подписанные вебхуки. Оплата при доставке — полноценный способ, а все суммы целые в гяпиках.
Что даёт партнёрский API
Чтение заказов
Получайте назначенные вам заказы с позициями, временным окном, зоной, суммой наложенного платежа и полной хронологией статусов. Имя, телефон и адрес клиента приходят только со скоупом orders:pii.
События логистики
Сообщайте нам PICKED_UP, EN_ROUTE, DELIVERED и FAILED. На хабе вы забираете заказ в статусе PACKED; каждое событие проходит через машину состояний заказа, поэтому невозможный переход отклоняется, а не портит заказ.
Вебхуки
order.placed, order.status_changed, order.delivered, order.cancelled, batch.completed и order.assigned_to_partner — каждый подписан HMAC-SHA256 и повторяется с задержками до 12 часов.
Песочница
Второй API со своей заполненной базой и своими ключами. Ключ песочницы никогда не работает с боевыми данными, а боевой — в песочнице.
Базовые URL
https://api.turanyol.comhttp://localhost:3050Ключ привязан к одной среде. Ключ песочницы, отправленный в боевой API, отклоняется с ERR_API_KEY_ENVIRONMENT.
Быстрый старт
Две вещи, которые надо сделать правильно: передавать ключ в каждом запросе и проверять подпись каждого вебхука.
1. Аутентификация запроса
Передавайте ключ в заголовке X-Api-Key. Никакого OAuth и bearer-токена — ключ и есть учётные данные, поэтому храните его на сервере.
curl -sS "https://api.turanyol.com/v1/partner/orders?status=EN_ROUTE&page=1" \
-H "X-Api-Key: $ESADARAK_API_KEY" \
-H "Accept: application/json"2. Сообщить о событии доставки
Нужен скоуп logistics:write и заказ, назначенный вам. Деньги — целые гяпики: 4750 это 47,50 ₼.
curl -sS -X POST "https://api.turanyol.com/v1/partner/orders/ES-1042/events" \
-H "X-Api-Key: $ESADARAK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"DELIVERED","codCollectedQepik":4750}'3. Проверка подписи вебхука
HMAC-SHA256 над меткой времени, точкой и сырым телом запроса. Сравнивайте за постоянное время и отклоняйте всё старше пяти минут.
import crypto from "node:crypto";
const SECRET = process.env.ESADARAK_WEBHOOK_SECRET;
const TOLERANCE_SEC = 300;
/** rawBody MUST be the exact bytes we sent (express: express.raw({ type: "application/json" })). */
export function verify(rawBody, signatureHeader) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((part) => part.trim().split("=", 2)),
);
const t = Number(parts.t);
if (!Number.isInteger(t)) return false;
if (Math.abs(Date.now() / 1000 - t) > TOLERANCE_SEC) return false; // replay window
const expected = crypto
.createHmac("sha256", SECRET)
.update(`${t}.${rawBody}`)
.digest("hex");
const received = Buffer.from(parts.v1 ?? "", "hex");
const digest = Buffer.from(expected, "hex");
return received.length === digest.length && crypto.timingSafeEqual(received, digest);
}Соглашения
- Все суммы — целые в гяпиках (младшая единица AZN), имя поля заканчивается на Qepik. Никогда не float.
- Ошибки — JSON со стабильным кодом (ERR_*) и никогда не локализованы: сопоставьте код со своими строками.
- Названия товаров и категорий — объект с полями az, ru и en. Выбирайте локаль на своей стороне.
- Телефоны в E.164 (+994XXXXXXXXX), метки времени ISO-8601 UTC, идентификаторы — UUID, коды — ES-1042 / B-2081.
- Списочные эндпоинты возвращают массив items вместе с page, pageSize и total и ограничивают pageSize значением 50.
Дальше
Ключ показывается один раз при создании. При ротации старый ключ живёт ещё 24 часа, чтобы выкатить без простоя.
До пяти эндпоинтов на ключ, у каждого свой секрет и полный журнал доставок с повтором.
Все коды ERR_*, которые может вернуть API, сгруппированные по областям.
{
"statusCode": 403,
"code": "ERR_API_KEY_SCOPE",
"message": "key is missing scope logistics:write",
"details": { "required": "logistics:write" }
}