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 | Оплачувані позиції європалети. 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" | Як інтерпретувати та повертати розміри та масу предметів: мм/кг (за замовчуванням) або дюйми/фунти. Позиції у відповіді використовують ті самі одиниці. |
| items | array, required | Маніфест вантажу (поля нижче). |
| sandbox | boolean | Тестовий режим: повний результат, нічого не зберігається. Доступно на кожному тарифі. |
| name | string | Назва плану (у виробничому режимі). |
| ldm_limit_m | number | Обмежити завантаження першими N вантажними метрами (для вантажівок). |
| budget_ms | number | Часовий бюджет оптимізації (виробничий режим; за замовчуванням 30000, максимум 300000). |
| callback_url | https URL | Результат буде надіслано POST-запитом на {callbackUrl}, коли завдання завершиться (підписаний, див. Вебхуки). |
Поля предметів
| Поле | Тип | Опис |
|---|---|---|
| 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