Packing API

Надішліть вантаж, отримайте оптимізований, фізично коректний план завантаження — розміщення, вантажні метри, лінійні фути та оплачувані позиції палет. Той самий алгоритм, що й у додатку, постійно перевіряється на реальних планах диспетчерів. Доступ до пісочниці на кожному тарифному плані; виробничий доступ — на тарифі Enterprise.

Швидкий старт

  1. Увійдіть → натисніть на своє ім'я → API → згенеруйте ключ.
  2. Надішліть завдання на пакування (це завдання виконується в пісочниці — безкоштовно на кожному тарифі):
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_countintegerСкільки предметів помістилося / не помістилося.
units"metric" | "imperial"Одиниці виміру, в яких подано всі числові значення нижче (повторюють запит).
metrics.ldm_mnumberВантажні метри — протяжність блоку вантажу (максимальний кінець − мінімальний початок).
metrics.linear_ftnumberТа сама протяжність у лінійних футах (американські LTL-перевезення).
metrics.span_mmintegerПротяжність у міліметрах, завжди метрична система.
metrics.pallet_positions_eurinteger | nullОплачувані позиції європалети. null, якщо розташування занадто велике для вимірювання.
metrics.total_weight_kgnumberЗагальна маса завантажених предметів, завжди в кілограмах.
metrics.overlapsintegerПари предметів, що перетинаються — завжди 0 для коректного розташування.
items[].placedbooleanЧи помістився предмет у план завантаження.
items[].x / y / znumber | nullПозиція в одиницях запиту: x від торця дверей, y від лівої стінки, z від підлоги. Усі три значення — null, якщо placed має значення false.
items[].rotation_deg / tilt_deg0 | 90Орієнтація: поворот навколо вертикальної осі; tilt = покладено на бік.
items[].length / width / height / weightnumberРозміри предмета, як зазначено в запиті, в одиницях запиту.
plan_urlstring | nullСтворений план у додатку. null для завдань у пісочниці.

Версіонування та стабільність

Контракт версіонується в шляху (/api/v1/). У межах v1 зміни лише додаткові — нові необов'язкові поля запиту, нові поля відповіді, нові коди транспортних засобів та коди помилок можуть з'являтися, а клієнти повинні ігнорувати поля, які не розпізнають. Існуючі поля ніколи не змінюють значення або тип, і нічого не видаляється. Зміни, що порушують сумісність, означають новий шлях версії, при цьому v1 підтримується паралельно щонайменше 12 місяців, а про застарення повідомляється електронною поштою кожному робочому простору з активним ключем.

Поля запиту

ПолеТипОпис
vehiclestringКод транспортного засобу з наведених нижче таблиць. Або передайте {customVehicleId} (транспортний засіб з вашого парку).
objective"ldm" | "pallets"Мінімізувати вантажні метри або оплачувані позиції палет. За замовчуванням — "ldm".
units"metric" | "imperial"Як інтерпретувати та повертати розміри та масу предметів: мм/кг (за замовчуванням) або дюйми/фунти. Позиції у відповіді використовують ті самі одиниці.
itemsarray, requiredМаніфест вантажу (поля нижче).
sandboxbooleanТестовий режим: повний результат, нічого не зберігається. Доступно на кожному тарифі.
namestringНазва плану (у виробничому режимі).
ldm_limit_mnumberОбмежити завантаження першими N вантажними метрами (для вантажівок).
budget_msnumberЧасовий бюджет оптимізації (виробничий режим; за замовчуванням 30000, максимум 300000).
callback_urlhttps URLРезультат буде надіслано POST-запитом на {callbackUrl}, коли завдання завершиться (підписаний, див. Вебхуки).

Поля предметів

ПолеТипОпис
length / width / heightnumber, requiredРозміри предмета, інтерпретуються в одиницях запиту (за замовчуванням мм, дюйми при "units": "imperial").
weightnumber, requiredМаса предмета (за замовчуванням кг, фунти при "units": "imperial").
quantityinteger, default 1Розгортається в окремі одиниці.
namestring, optionalВідображається у плані та відповіді.
stackableboolean, default trueЧи може інший вантаж бути покладений зверху на цей предмет.
max_stacknumber, optionalМаксимальна маса, яку цей предмет може витримати зверху (в тих самих одиницях, що й маса).
fragileboolean, default falseКрихкі предмети розміщуються лише на верхніх рівнях.
tiltableboolean, default trueЧи можна покласти предмет на бік.
destination_stopinteger, default 1Пункт призначення для завантаження за принципом LIFO (кілька зупинок).

Коди транспортних засобів

Згенеровані на основі актуальних специфікацій движка. Кастомні транспортні засоби з вашого парку працюють через custom_vehicle_id.

Вантажівки та причепи

КодТранспортний засібВнутрішні розміри (Д×Ш×В)Вантажопідйомність
CURTAINSIDER_13613.6m Curtainsider13.62 × 2.48 × 2.70 m24 t
BOX_13613.6m Box Trailer13.62 × 2.46 × 2.68 m24 t
MEGA_13613.6m Mega Trailer13.62 × 2.48 × 3.00 m22.5 t
MEGA_CURTAIN_13613.6m Mega Curtainsider13.62 × 2.48 × 3.00 m22 t
FLATBED_13613.6m Flatbed13.62 × 2.48 × 3.00 m25 t
REEFER_13613.6m Reefer13.32 × 2.44 × 2.54 m22 t
CURTAINSIDER_757.5m City Curtainsider7.50 × 2.48 × 2.70 m12 t
SWAPBODY_7157.15m Swap Body7.15 × 2.48 × 2.70 m12 t
SWAPBODY_7457.45m Swap Body7.45 × 2.48 × 2.70 m12 t
DRY_VAN_5353ft Dry Van16.15 × 2.59 × 2.74 m20 t
FLATBED_5353ft Flatbed16.15 × 2.59 × 3.66 m22 t
REEFER_5353ft Reefer15.85 × 2.46 × 2.59 m18.5 t
CURTAINSIDER_125_CN12.5m Curtainsider (CN)12.50 × 2.50 × 2.80 m27 t
FLATBED_40_IN40ft Flatbed (IN)12.19 × 2.50 × 3.50 m26 t
BOX_138_BR13.8m Box Van (BR)13.80 × 2.50 × 2.90 m28 t
CURTAINSIDER_12_ZA12m Curtainsider (ZA)12.00 × 2.48 × 2.70 m28 t

Контейнери

КодКонтейнерВнутрішні розміри (Д×Ш×В)Вантажопідйомність
20DC20' Dry Container5.89 × 2.35 × 2.39 m21.727 t
20HC20' High Cube5.89 × 2.35 × 2.70 m21.58 t
40DC40' Dry Container12.03 × 2.35 × 2.39 m26.63 t
40HC40' High Cube12.03 × 2.35 × 2.70 m26.58 t
45HC45' High Cube13.56 × 2.35 × 2.70 m25.68 t
20OT20' Open Top5.89 × 2.35 × 2.39 m21.64 t
40OT40' Open Top12.03 × 2.35 × 2.39 m26.58 t
20RF20' Reefer5.44 × 2.29 × 2.27 m21 t
40RF40' Reefer11.58 × 2.29 × 2.21 m25.6 t
40RFHC40' Reefer High Cube11.58 × 2.29 × 2.54 m25.88 t
53DC53' Domestic16.15 × 2.59 × 2.90 m26 t

Рівні доступу та обмеження

Пісочниця (на кожному тарифі)Виробничий режим (Enterprise)
Запити25 успішних / місяць5 000 успішних пакувань / місяць
Предметів у маніфесті205,000
Одночасні завдання110
Бюджет оптимізації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_key401Відсутній, некоректний або відкликаний ключ API.
invalid_json400Тіло запиту не є коректним JSON.
invalid_vehicle400Невідомий код транспортного засобу або {customVehicleId}.
invalid_items400Одне з полів предмета відсутнє, не є числом або виходить за межі допустимого діапазону.
suspicious_dimensions400Усі розміри менше 100 мм — ймовірно, дюйми передані як міліметри. Передайте "units": "imperial".
invalid_units400Поле units має бути "metric" або "imperial".
invalid_objective400Поле objective має бути "ldm" або "pallets".
invalid_callback400callback_url має використовувати протокол https.
too_many_items400Маніфест перевищує ліміт предметів для вашого рівня доступу.
upgrade_required402Виробничий режим вимагає тарифу Enterprise. Використовуйте пісочницю або оновіть тариф.
sandbox_limit_reached402Місячний ліміт пісочниці вичерпано — оновлюється 1-го числа.
quota_exceeded402Місячний ліміт у 5 000 пакувань вичерпано — скидається 1-го числа. Для більших обсягів: зв'яжіться з нами.
too_many_jobs429Досягнуто ліміт одночасних завдань. Перевірте статус поточних завдань і повторіть спробу.
not_found404Завдання з таким ідентифікатором не існує для цього робочого простору.

Питання, потреба в більших лімітах або інтеграція, якої вам бракує (Zapier, Excel, MCP)? hello@hansatic.com