API Logtor
Подключите интернет-магазин к доставке: расчёт тарифов, пункты выдачи, подсказки городов и адресов, создание заказа, статусы и вебхуки. REST/JSON, авторизация по API-ключу. Сейчас работают СДЭК и DPD (пункт → пункт); Достависта (курьер по адресам) временно скрыта, КСЭ — в подключении; Деловые Линии и ПЭК — в планах. Новые перевозчики подключаются без изменения контракта.
Быстрый старт
Минимальный рабочий путь: расчёт → пункты выдачи → заказ → этикетка → статусы. Всё, что нужно — один API-ключ и пять запросов.
# 1. посчитать варианты (габариты нужны, иначе DPD не посчитается)
curl -s https://logtor.ru/api/v1/public/calculate -H "X-Api-Key: $KEY" -H "Content-Type: application/json" -d '{"sender_city":"Москва","receiver_city":"Казань","weight":1,
"length":20,"width":15,"height":10}'
# 2. взять пункт приёма и пункт выдачи
curl -s "https://logtor.ru/api/v1/public/pickup-points?city=Москва&purpose=shipment" -H "X-Api-Key: $KEY"
curl -s "https://logtor.ru/api/v1/public/pickup-points?city=Казань&purpose=delivery" -H "X-Api-Key: $KEY"
# 3. создать заказ (Idempotency-Key обязателен)
curl -s https://logtor.ru/api/v1/public/orders -H "X-Api-Key: $KEY" -H "Idempotency-Key: shop-1001" -H "Content-Type: application/json" -d '{"tc_id":1,"tariff_code":136,
"sender_name":"Иванов Иван","sender_phone":"+79990001122",
"sender_city":"Москва","sender_address":"Тверская 1","sender_pvz":"MSK2567",
"receiver_name":"Петров Пётр","receiver_phone":"+79991234567",
"receiver_city":"Казань","receiver_address":"Баумана 1","receiver_pvz":"KZN3",
"weight":1,"length":20,"width":15,"height":10}'
# 4. этикетка (PDF)
curl -s https://logtor.ru/api/v1/public/orders/{uuid}/label -H "X-Api-Key: $KEY" -o label.pdf- галками отмечено обязательное: Idempotency-Key при создании и габариты в расчёте
- сейчас работают только тарифы пункт → пункт: посылку сдают в пункт приёма, получатель забирает в пункте выдачи
- статусы лучше получать вебхуком, чем опросом — см. раздел 05
Авторизация
Каждому магазину выдаётся свой API-ключ (ms_live_…). Он показывается один раз — при создании или перевыпуске в кабинете; у нас хранится только отпечаток, поэтому потерянный ключ не восстановить, а только перевыпустить. Передавайте ключ в заголовке запроса:
X-Api-Key: <ваш_ключ>Если ключ неверный или не указан — сервер ответит HTTP 401. Если аккаунт ещё не подтверждён оператором — тоже 401: ключи начинают работать после подтверждения.
Защита от дублей (идемпотентность)
При создании заказа обязательно передавайте заголовок Idempotency-Key — уникальный идентификатор вашей заявки. Один и тот же ключ = один заказ, повторный запрос не создаст дубликат ни в Logtor, ни у перевозчика.
Idempotency-Key: <уникальный_идентификатор_заявки>Расчёт тарифов
Тело запроса:
{
"sender_city": "Москва",
"receiver_city": "Казань",
"weight": 1.2,
"length": 15,
"width": 15,
"height": 15,
"declared_value": 300
}Габариты передавайте всегда. Без длины, ширины и высоты тариф DPD не возвращается: его расчёт без габаритов не учитывает объёмный вес и занижает цену (Москва → Сочи, 1 кг: 234 ₽ без габаритов против 308 ₽ с 40×30×20). Лучше честно не показать тариф, чем назвать цену, которую перевозчик потом пересчитает.
Ответ — массив тарифов с итоговой ценой (уже с учётом наценки):
[
{
"tc_id": 1,
"tc_name": "СДЭК",
"tariff_code": 136,
"tariff_name": "Посылка · ПВЗ → ПВЗ",
"cost": 345.0,
"delivery_days_min": 1,
"delivery_days_max": 4,
"requires_pickup_point": true
}
]- tariff_code — код тарифа (передаётся в заказ)
- requires_pickup_point: true — для этого тарифа нужен пункт выдачи (receiver_pvz)
- cost — итоговая цена, фиксируется в заказе
Пункты выдачи и приёма
Передайте заголовок X-Api-Key — вернутся пункты тех перевозчиков, которые подключены вашей организации (без ключа — только для формы на лендинге). Чтобы получить пункты одного перевозчика, добавьте tc_id из ответа расчёта: /pickup-points?city=Казань&tc_id=7.
purpose=delivery — пункты выдачи для получателя (ПВЗ), purpose=shipment — пункты приёма, куда сдать отправление (склад перевозчика).
[
{
"id": "KZN3",
"name": "KZN3, Казань, ул. Спартаковская",
"address": "ул. Спартаковская, 2, корп.1, 112",
"city": "Казань",
"work_hours": "Пн-Пт 09:00-20:00"
}
]Поле id — код пункта, который нужно передавать в заказ в sender_pvz / receiver_pvz.
Создание заказа
Заголовки:
X-Api-Key: <ключ>
Idempotency-Key: <уникальный_идентификатор_заявки>Тело:
{
"tc_id": 1,
"tariff_code": 136,
"sender_name": "Иванов Иван",
"sender_phone": "+79990001122",
"sender_city": "Москва",
"sender_pvz": "MSK2567",
"receiver_name": "Петров Пётр",
"receiver_phone": "+79991234567",
"receiver_city": "Казань",
"receiver_pvz": "KZN3",
"weight": 1.2,
"length": 15,
"width": 15,
"height": 15,
"declared_value": 300,
"callback_url": "https://your-site.ru/logtor/webhook"
}- для тарифов «от станции/склада» обязателен sender_pvz
- receiver_pvz обязателен, если тариф требует пункт выдачи
- цена не передаётся — сервер вычисляет и проверяет её сам (защита от подмены)
- callback_url — сюда придут уведомления о статусах
Сейчас доступны ПВЗ-тарифы «склад → склад»: отправитель сдаёт посылку в пункт приёма выбранного города, получатель забирает в пункте выдачи. Курьерские тарифы «от двери» пока не предлагаются — как только появятся, для них потребуется дата забора intake_date (в API уже поддерживается).
Ответ:
{
"id": 42,
"uuid": "…",
"internal_number": "MS-0004-00001",
"tc_name": "СДЭК",
"tc_tracking_number": "…",
"client_cost": 345.0,
"status": "confirmed",
"created_at": "…"
}Статусы / трекинг
tracking_number — номер из поля tc_tracking_number.
{
"order": {
"id": 42,
"tc_tracking_number": "…",
"status": "in_transit",
"client_cost": 345.0
},
"tracking": [
{ "status": "created", "description": "Заказ создан", "event_time": "…" },
{ "status": "in_transit", "description": "В пути", "location": "Москва", "event_time": "…" }
]
}Уведомления о статусах (callback)
{
"event": "status_changed",
"event_id": "…",
"order_uuid": "…",
"internal_number": "MS-0004-00001",
"tc_tracking_number": "…",
"status": "in_transit",
"updated_at": "…"
}Заголовки подписи (защита от подделки запросов):
X-Logtor-Signature: sha256=HMAC(секрет_подписи_магазина, "{timestamp}.{raw_body}")
X-Logtor-Event-Id: <uuid события>
X-Logtor-Timestamp: <ts>Проверка: вычислите HMAC-SHA256 от строки "{ts}.{body}" с секретом подписи магазина и сравните с заголовком. Секрет (whsec_…) у каждого магазина свой, он виден администратору в кабинете: «Настройки → API и магазины», там же его можно перевыпустить. Для магазинов, созданных до обновления, подпись прежняя — по ключу организации, пока вы не перевыпустите секрет.
Список заказов, карточка и этикетка
Заказы вашей организации, новые сверху. Фильтры: status, search (номер, телефон или имя получателя), date_from / date_to (YYYY-MM-DD), tc_id; page_size — до 100.
{ "orders": [ { "id": 42, "uuid": "…", "status": "in_transit", … } ],
"total": 1, "page": 1, "page_size": 20 }GET/orders/{id}Заказ с историей статусов — по id, uuid, номеру отправления или внутреннему номеру. Формат ответа тот же, что у /tracking/….
GET/orders/{id}/labelPDF для печати. По умолчанию — официальный штрихкод перевозчика, а если он ещё не готов — запасная этикетка Logtor (заголовок ответа X-Label-Source: cdek или logtor). Параметр kind: auto (по умолчанию), cdek — только официальная (до готовности ответ 503), logtor — только запасная.
Отмена заказа
Магазин может отменить заказ, пока отправление ещё не передано перевозчику в работу. Вместо {id} подойдёт id, uuid, номер отправления или внутренний номер заказа. Статус меняется только после подтверждения отмены перевозчиком; сумма возвращается на ваш счёт.
POST /api/v1/public/orders/42/cancel
X-Api-Key: <ключ>
→ 200 { "status": "cancelled", "order_id": 42 }Если перевозчик уже принял заказ в работу и отмена невозможна через API, либо подтверждения отмены пока нет — ответ будет 400 с понятным объяснением, статус и деньги не меняются.
Повторная доставка уведомлений (retry)
Если ваш сервер в момент отправки недоступен — Logtor гарантированно повторяет доставку уведомления:
- до 8 попыток с экспоненциальной паузой (до 6 часов)
- у каждого события свой event_id — повтор не создаст дублей у вас
- после исчерпания попыток доставка помечается как неуспешная (dead-letter)
- вы всегда можете получить актуальный статус сами (см. ниже)
Самостоятельный запрос статуса (pull)
Если уведомление потерялось или вы хотите синхронизироваться вручную — просто запросите текущий статус заказа по трек-номеру:
GET/tracking/{tracking_number}GET /api/v1/public/tracking/1234567890
X-Api-Key: <ключ>
→ 200
{
"order": { "id": 42, "tc_tracking_number": "1234567890",
"status": "in_transit", "client_cost": 345.0 },
"tracking": [
{ "status": "created", "description": "Заказ создан", "event_time": "…" },
{ "status": "in_transit","description": "В пути", "location": "Москва", "event_time": "…" }
]
}Это pull-механизм: вы всегда можете получить свежий статус и историю, даже если вам показалось, что какой-то вебхук потерялся.
Ошибки
{ "detail": "Текст понятной ошибки" }- 400неверный запрос / бизнес-правило (нет ПВЗ, нет согласия ПДн)
- 401неверный API-ключ или аккаунт ещё не подтверждён оператором
- 402недостаточно средств на балансе или исчерпан лимит постоплаты — оплатите счёт и повторите
- 404заказ / отправление не найдено
- 429слишком много запросов (rate limit)
- 503перевозчик временно недоступен
Оплата и баланс
По умолчанию отправления оформляются по договору Logtor и оплачиваются постоплатой: стоимость каждого заказа учитывается на вашем счёте в момент его создания, а за период мы выставляем счёт по выписке. Размер лимита задолженности согласуется при подтверждении аккаунта. При отмене заказа или отказе перевозчика сумма возвращается на счёт.
- если лимит задолженности исчерпан (или баланса не хватает при работе по балансу), создание заказа вернёт 402 — заказ не создаётся
- новый аккаунт подтверждает оператор: до этого API-ключи отвечают 401, а создание заказа в кабинете — 403
- выписку за период (JSON или CSV для Excel) можно получить в кабинете или через GET /api/v1/tenants/me/billing/statement
- остаток и историю операций видно в личном кабинете, раздел «Баланс и договор»
- есть собственный договор с перевозчиком — подключите его там же: заказы пойдут от вашего имени, без наценки Logtor и без списаний с баланса
Rate limits
Для магазинов (с API-ключом): 120 запросов в минуту на ключ. Для крупных магазинов лимит поднимается по заявке, без смены кода. Запросы с неверным ключом считаются отдельно по IP (30 в минуту).
Публичные эндпоинты (без ключа):
- расчёт — 20/мин с IP
- пункты выдачи — 60/мин с IP
- трекинг — 30/мин с IP
- анонимные заказы — 5/час с IP + общий суточный лимит 50
Какие перевозчики показывать клиенту
Logtor — агрегатор: под одной учёткой можно подключить несколько транспортных компаний. Сейчас работают СДЭК и DPD; Достависта, КСЭ и остальные появятся по мере запуска.
Для каждого клиента оператор платформы решает, какие перевозчики будут видны в его расчёте и кабинете:
- подключено у платформы 5 ТК — а клиенту доступны только 1–2, остальные скрыты
- у каждого перевозчика своя наценка (в % и/или в ₽), она видна в итоговой цене расчёта
- клиент всегда видит «чистые» тарифы только тех перевозчиков, которые ему открыты
Смена набора перевозчиков для клиента не ломает кабинет: скрытые ТК остаются подключёнными, но не участвуют в расчёте. Это удобно, когда магазину нужна только одна служба доставки, а вы хотите потом открыть ему остальные.
Подсказка городов в калькуляторе
В калькуляторе (на сайте и в кабинете) поля городов имеют подсказки: вводите первые буквы — появляется список. Список берётся из справочника подключённых перевозчиков, поэтому в нём есть и малые населённые пункты (Одинцово, Батайск и т.п.), а не только крупные города. Это убирает ошибки в написании и сразу даёт корректный расчёт.
GET/cities?q=ОдинОтвет — массив (с заголовком X-Api-Key — по вашим перевозчикам):
[
{ "name": "Одинцово", "full_name": "Одинцово, Одинцовский р-н, Московская обл., Россия" },
{ "name": "Одинцовский", "full_name": "Одинцовский, Одинцовский р-н, Московская обл., Россия" }
]name подставляется в поле расчёта, full_name — подпись с регионом для списка. Без ключа адрес /api/v1/public/cities?q=… работает для лендинга с лимитом 60 запросов в минуту на IP.
Подсказка улиц и домов
У перевозчиков справочника улиц нет — они отдают только города и пункты выдачи. Поэтому подсказки адресов приходят из отдельного справочника и работают так же, как подсказки городов: вводите первые буквы, появляется список.
GET/addresses?q=Тверская 7&city=Москва{
"available": true,
"items": [
{ "value": "Тверская улица, 7", "street": "Тверская улица", "house": "7", "kind": "house" }
],
"provider": "photon"
}- value подставляется в поле адреса как есть
- kind: пока в запросе нет цифры — street, появилась цифра — house
- city сужает выдачу; без него подсказки могут прийти из другого региона
- available: false — справочник отключён; это не ошибка, поле работает как обычный ввод
- минимум 3 символа, ответы кешируются на 15 минут
Выбранный из подсказки адрес — это строка для документов. Перевозчик всё равно сверит её со своим справочником при создании заказа.
Готовы подключаться?
Заведите кабинет и получите API-ключ магазина
Администратор аккаунта выдаёт ключ в настройках. Наценка показывается в расчёте и фиксируется в заказе.