Packing API
Отправьте груз и получите оптимизированный, физически корректный план загрузки — с указанием позиций, погрузочных метров, линейных футов и расчётных паллетных мест. Тот же движок, что и в приложении, постоянно проверяемый на реальных схемах диспетчеров. Доступ к песочнице на каждом тарифном плане; продакшен-доступ — на тарифе Enterprise.
Быстрый старт
- Войдите в систему → нажмите на своё имя → API → сгенерируйте ключ.
- Отправьте задание на упаковку (этот пример выполняется в песочнице — бесплатно на каждом тарифном плане):
curl -X POST https://hansatic.com/api/v1/pack \
-H "Authorization: Bearer hk_live_..." \
-H "Content-Type: application/json" \
-d '{
"vehicle": "CURTAINSIDER_136",
"objective": "ldm",
"sandbox": true,
"items": [{
"name": "Machine crate",
"length": 2300, "width": 750, "height": 1400,
"weight": 300, "quantity": 7,
"stackable": false, "tiltable": false
}]
}'{
"job_id": "5e3617d1-abe4-4549-b7e6-d18c6baf814f",
"status": "queued",
"sandbox": true,
"status_url": "https://hansatic.com/api/v1/jobs/5e3617d1-..."
}Проверяйте status_url (с тем же заголовком авторизации), пока status не станет "done":
{
"job_id": "5e3617d1-...",
"status": "done",
"result": {
"placed_count": 7,
"unplaced_count": 0,
"units": "metric",
"metrics": {
"ldm_m": 5.25,
"span_mm": 5250,
"linear_ft": 17.2,
"pallet_positions_eur": 14,
"total_weight_kg": 2100,
"overlaps": 0
},
"items": [
{ "id": "...", "name": "Machine crate", "placed": true,
"x": 8370, "y": 0, "z": 0,
"rotation_deg": 90, "tilt_deg": 0, "...": "..." }
],
"plan_url": "https://hansatic.com/en/app/plans/..."
}
}Эндпоинты
POST /api/v1/pack
Проверяет и ставит в очередь задание на упаковку. Возвращает 202 с job_id. Поддерживает заголовок Idempotency-Key — повторные запросы с тем же ключом возвращают исходное задание вместо повторной упаковки.
GET /api/v1/jobs/{id}
Статус задания и, по завершении, полный результат. Результаты хранятся 30 дней; на продакшен-тарифах данные остаются в вашем рабочем пространстве навсегда.
GET /api/v1/openapi.json
Машинно-читаемая спецификация OpenAPI 3.1 — импортируйте её в Postman, генераторы кода или используйте с инструментами ИИ-программирования. Коды транспортных средств подгружаются из работающего движка, поэтому спецификация всегда актуальна. Открыть спецификацию ↗
Поля ответа
Объект result для завершённого задания:
| Поле | Тип | Описание |
|---|---|---|
| placed_count / unplaced_count | integer | Количество размещённых / неразмещённых предметов. |
| units | "metric" | "imperial" | Единицы измерения, в которых представлены все числовые значения ниже (дублируются из запроса). |
| metrics.ldm_m | number | Погрузочные метры — протяжённость грузового блока (максимальный конец − минимальное начало). |
| metrics.linear_ft | number | Та же протяжённость в линейных футах (для американских LTL-перевозок). |
| metrics.span_mm | integer | Протяжённость в миллиметрах, всегда в метрической системе. |
| metrics.pallet_positions_eur | integer | null | Расчётные позиции EUR-паллет. Значение null, если схема слишком велика для измерения. |
| metrics.total_weight_kg | number | Общий вес размещённых предметов, всегда в килограммах. |
| metrics.overlaps | integer | Пары пересекающихся предметов — всегда 0 для корректной схемы. |
| items[].placed | boolean | Удалось ли разместить предмет в схеме. |
| items[].x / y / z | number | null | Позиция в единицах измерения запроса: x — от торца двери, y — от левой стенки, z — от пола. Все три значения равны null, если placed — false. |
| items[].rotation_deg / tilt_deg | 0 | 90 | Ориентация: поворот вокруг вертикальной оси; tilt — предмет положен на бок. |
| items[].length / width / height / weight | number | Размеры предмета из запроса, дублируются в единицах измерения запроса. |
| plan_url | string | null | Созданный план в приложении. Значение null для заданий в песочнице. |
Версионирование и стабильность
Контракт версионируется в пути (/api/v1/). В рамках v1 изменения только аддитивные — новые необязательные поля запроса, новые поля ответа, новые коды транспортных средств и коды ошибок. Клиенты должны игнорировать нераспознанные поля. Существующие поля никогда не меняют значение или тип, и ничто не удаляется. Критические изменения ведут к созданию нового пути версии, при этом v1 поддерживается параллельно не менее 12 месяцев с уведомлением об устаревании по электронной почте каждому рабочему пространству с активным ключом.
Поля запроса
| Поле | Тип | Описание |
|---|---|---|
| vehicle | string | Код транспортного средства из таблиц ниже. Или передайте {customVehicleId} (транспорт из вашего парка). |
| objective | "ldm" | "pallets" | Минимизировать погрузочные метры или расчётные паллетные позиции. По умолчанию — "ldm". |
| units | "metric" | "imperial" | Единицы измерения для размеров и веса предметов, а также возвращаемых данных: mm/kg (по умолчанию) или in/lb. Позиции в ответе используют те же единицы. |
| items | array, required | Манифест груза (поля описаны ниже). |
| sandbox | boolean | Тестовый режим: полный результат, данные не сохраняются. Доступен на каждом тарифном плане. |
| name | string | Название плана (в продакшен-режиме). |
| ldm_limit_m | number | Ограничение загрузки первыми N погрузочными метрами (для грузовиков). |
| budget_ms | number | Бюджет времени на оптимизацию (в продакшен-режиме; по умолчанию 30000, максимум 300000). |
| callback_url | https URL | Адрес для POST-запроса с результатом по завершении задания, подписанный (см. Вебхуки). |
Поля предметов
| Поле | Тип | Описание |
|---|---|---|
| length / width / height | number, required | Размеры предмета в единицах измерения запроса (по умолчанию — миллиметры, дюймы при "units": "imperial"). |
| weight | number, required | Вес предмета (по умолчанию — килограммы, фунты при "units": "imperial"). |
| quantity | integer, default 1 | Раскладывается на отдельные единицы. |
| name | string, optional | Отображается в плане и ответе. |
| stackable | boolean, default true | Может ли другой груз размещаться поверх этого предмета. |
| max_stack | number, optional | Максимальный вес, который может выдержать предмет сверху (в тех же единицах, что и вес). |
| fragile | boolean, default false | Хрупкие предметы размещаются только на верхних уровнях. |
| tiltable | boolean, default true | Можно ли положить предмет на бок. |
| destination_stop | integer, default 1 | Пункт доставки для загрузки по принципу LIFO (последним пришёл — первым вышел) при нескольких остановках. |
Коды транспортных средств
Сгенерированы на основе актуальных спецификаций движка. Пользовательские транспортные средства из вашего парка работают через custom_vehicle_id.
Грузовики и прицепы
| Код | Транспорт | Внутренние размеры (Д×Ш×В) | Грузоподъёмность |
|---|---|---|---|
| CURTAINSIDER_136 | 13.6m Curtainsider | 13.62 × 2.48 × 2.70 m | 24 t |
| BOX_136 | 13.6m Box Trailer | 13.62 × 2.46 × 2.68 m | 24 t |
| MEGA_136 | 13.6m Mega Trailer | 13.62 × 2.48 × 3.00 m | 22.5 t |
| MEGA_CURTAIN_136 | 13.6m Mega Curtainsider | 13.62 × 2.48 × 3.00 m | 22 t |
| FLATBED_136 | 13.6m Flatbed | 13.62 × 2.48 × 3.00 m | 25 t |
| REEFER_136 | 13.6m Reefer | 13.32 × 2.44 × 2.54 m | 22 t |
| CURTAINSIDER_75 | 7.5m City Curtainsider | 7.50 × 2.48 × 2.70 m | 12 t |
| SWAPBODY_715 | 7.15m Swap Body | 7.15 × 2.48 × 2.70 m | 12 t |
| SWAPBODY_745 | 7.45m Swap Body | 7.45 × 2.48 × 2.70 m | 12 t |
| DRY_VAN_53 | 53ft Dry Van | 16.15 × 2.59 × 2.74 m | 20 t |
| FLATBED_53 | 53ft Flatbed | 16.15 × 2.59 × 3.66 m | 22 t |
| REEFER_53 | 53ft Reefer | 15.85 × 2.46 × 2.59 m | 18.5 t |
| CURTAINSIDER_125_CN | 12.5m Curtainsider (CN) | 12.50 × 2.50 × 2.80 m | 27 t |
| FLATBED_40_IN | 40ft Flatbed (IN) | 12.19 × 2.50 × 3.50 m | 26 t |
| BOX_138_BR | 13.8m Box Van (BR) | 13.80 × 2.50 × 2.90 m | 28 t |
| CURTAINSIDER_12_ZA | 12m Curtainsider (ZA) | 12.00 × 2.48 × 2.70 m | 28 t |
Контейнеры
| Код | Контейнер | Внутренние размеры (Д×Ш×В) | Грузоподъёмность |
|---|---|---|---|
| 20DC | 20' Dry Container | 5.89 × 2.35 × 2.39 m | 21.727 t |
| 20HC | 20' High Cube | 5.89 × 2.35 × 2.70 m | 21.58 t |
| 40DC | 40' Dry Container | 12.03 × 2.35 × 2.39 m | 26.63 t |
| 40HC | 40' High Cube | 12.03 × 2.35 × 2.70 m | 26.58 t |
| 45HC | 45' High Cube | 13.56 × 2.35 × 2.70 m | 25.68 t |
| 20OT | 20' Open Top | 5.89 × 2.35 × 2.39 m | 21.64 t |
| 40OT | 40' Open Top | 12.03 × 2.35 × 2.39 m | 26.58 t |
| 20RF | 20' Reefer | 5.44 × 2.29 × 2.27 m | 21 t |
| 40RF | 40' Reefer | 11.58 × 2.29 × 2.21 m | 25.6 t |
| 40RFHC | 40' Reefer High Cube | 11.58 × 2.29 × 2.54 m | 25.88 t |
| 53DC | 53' Domestic | 16.15 × 2.59 × 2.90 m | 26 t |
Уровни доступа и ограничения
| Песочница (на каждом тарифном плане) | Продакшен (тариф Enterprise) | |
|---|---|---|
| Запросы | 25 успешных в месяц | 5 000 успешных упаковок / месяц |
| Предметов в манифесте | 20 | 5,000 |
| Одновременных заданий | 1 | 10 |
| Бюджет оптимизации | 10 с | 30 с по умолчанию, до 300 с |
| Сохранение данных | Данные не сохраняются | Каждая упаковка создаёт реальный план в вашем рабочем пространстве |
Счёт идёт только по успешно выполненным упаковкам — неудачные проверки и задания не расходуют квоту. Оба счётчика сбрасываются 1-го числа (UTC). Результаты в песочнице полные и не урезаны — ограничения касаются только количества запросов, а не качества выходных данных. Нужно больше 5 000 упаковок в месяц? Свяжитесь с нами, чтобы обсудить условия для крупных объёмов и OEM-партнёрства.
Вебхуки
Передайте callback_url, чтобы получить результат через POST при завершении задания. Каждый вебхук содержит X-Hansatic-Signature: HMAC-SHA256 от исходного тела запроса с использованием вебхук-секрета вашего ключа (отображается однократно при создании ключа). Проверяйте подпись:
const crypto = require('crypto');
function verify(rawBody, signatureHeader, webhookSecret) {
const expected = crypto.createHmac('sha256', webhookSecret)
.update(rawBody).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected), Buffer.from(signatureHeader));
}Доставка выполняется однократно с тайм-аутом 5 с — status_url всегда остаётся источником истины.
Ошибки
Все ошибки имеют формат { "error": { "code", "message", ... } } — машинно-читаемый код, понятное человеку сообщение и field, если проблема связана с конкретным полем ввода.
| Код | HTTP | Значение |
|---|---|---|
| invalid_key | 401 | Отсутствует, некорректный или отозванный API-ключ. |
| invalid_json | 400 | Тело запроса не является допустимым JSON. |
| invalid_vehicle | 400 | Неизвестный код транспортного средства или {customVehicleId}. |
| invalid_items | 400 | Отсутствует, нечисловое или выходящее за допустимый диапазон поле предмета. |
| suspicious_dimensions | 400 | Все размеры менее 100 мм — вероятно, дюймы переданы как миллиметры. Укажите "units": "imperial". |
| invalid_units | 400 | Поле units должно быть "metric" или "imperial". |
| invalid_objective | 400 | Поле objective должно быть "ldm" или "pallets". |
| invalid_callback | 400 | callback_url должен использовать протокол https. |
| too_many_items | 400 | Манифест превышает лимит предметов для вашего уровня доступа. |
| upgrade_required | 402 | Для продакшен-режима требуется тариф Enterprise. Используйте песочницу или обновите тариф. |
| sandbox_limit_reached | 402 | Месячный лимит песочницы исчерпан — сбрасывается 1-го числа. |
| quota_exceeded | 402 | Месячная квота в 5 000 упаковок исчерпана — сброс счётчика 1-го числа. Для увеличения объёма обратитесь к нам. |
| too_many_jobs | 429 | Достигнут лимит одновременных заданий. Проверьте статус текущих заданий и повторите попытку. |
| not_found | 404 | Задание с таким идентификатором не найдено в этом рабочем пространстве. |
Вопросы, увеличение лимитов или нужный коннектор (Zapier, Excel, MCP)? hello@hansatic.com