적재 API
화물을 제출하면 물리적으로 유효한 최적화된 적재 계획(위치, 적재 미터, 피트 단위 길이, 청구 팔레트 위치)을 반환합니다. 앱의 핵심 엔진과 동일하며, 실제 디스패처 레이아웃으로 지속 검증됩니다. 모든 플랜에서 샌드박스 이용 가능, 엔터프라이즈 플랜에서 프로덕션 이용 가능.
빠른 시작
- 로그인 → 이름 클릭 → 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, 코드 생성기 또는 AI 코딩 도구에 가져올 수 있습니다. 차량 코드는 실시간 엔진에서 주입되므로 항상 최신 상태입니다. 스펙 보기 ↗
응답 필드
완료된 작업의 result 객체:
| 필드 | 유형 | 설명 |
|---|---|---|
| placed_count / unplaced_count | integer | 적재된 항목 수 / 적재되지 않은 항목 수. |
| units | "metric" | "imperial" | 이하 모든 숫자의 단위(요청과 동일). |
| metrics.ldm_m | number | 적재 미터 — 화물 블록의 길이(최대 끝 지점 − 최소 시작 지점). |
| metrics.linear_ft | number | 동일한 길이의 피트 단위(미국 LTL). |
| metrics.span_mm | integer | mm 단위의 길이(항상 미터법 사용). |
| metrics.pallet_positions_eur | integer | null | 청구 EUR 팔레트 위치. 레이아웃이 너무 커서 측정할 수 없을 경우 null. |
| metrics.total_weight_kg | number | 적재된 총 중량(항상 kg). |
| metrics.overlaps | integer | 겹치는 항목 쌍 — 유효한 레이아웃에서는 항상 0. |
| items[].placed | boolean | 항목이 레이아웃에 포함되었는지 여부. |
| items[].x / y / z | number | null | 요청 단위의 위치: x는 문 쪽 끝에서, y는 왼쪽 벽에서, z는 바닥에서. placed가 false일 경우 세 값 모두 null. |
| 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 | 항목 치수(요청의 단위 기준, 기본값 mm, "units": "imperial"일 경우 인치). |
| weight | number, required | 항목 중량(기본값 kg, "units": "imperial"일 경우 lb). |
| quantity | integer, default 1 | 개별 단위로 확장됩니다. |
| name | string, optional | 계획 및 응답에 표시됩니다. |
| stackable | boolean, default true | 이 항목 위에 다른 화물을 쌓을 수 있습니다. |
| max_stack | number, optional | 이 항목 위에 쌓을 수 있는 최대 중량(weight와 동일한 단위). |
| fragile | boolean, default false | 깨지기 쉬운 항목은 최상층에만 배치됩니다. |
| tiltable | boolean, default true | 항목을 옆으로 눕힐 수 있습니다. |
| destination_stop | integer, default 1 | 다중 정차 LIFO 적재 시 배송 정류장. |
차량 코드
실시간 엔진 사양에서 생성됩니다. 워크스페이스의 사용자 지정 차량은 custom_vehicle_id로 사용 가능합니다.
트럭 및 트레일러
| 코드 | 차량 | 내부 치수 (L×W×H) | 적재 중량 |
|---|---|---|---|
| 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 |
컨테이너
| 코드 | 컨테이너 | 내부 치수 (L×W×H) | 적재 중량 |
|---|---|---|---|
| 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 |
접근 수준 및 제한
| 샌드박스(모든 플랜) | 프로덕션(엔터프라이즈) | |
|---|---|---|
| 호출 | 월 25회 성공 호출 | 월 5,000건 성공 처리 |
| 목록당 항목 수 | 20 | 5,000 |
| 동시 작업 | 1 | 10 |
| 최적화 예산 | 10초 | 기본 30초, 최대 300초 |
| 영속성 | 저장되지 않음 | 모든 적재 작업이 워크스페이스에 실제 계획으로 생성됨 |
성공적으로 완료된 패킹 작업만 카운트되며, 유효성 검사 실패 또는 작업 실패 건은 할당량에 포함되지 않습니다. 두 카운터는 매월 1일(UTC 기준) 초기화됩니다. 샌드박스 결과는 완전하며 기능 제한이 없습니다 — 제한은 접근 제어일 뿐, 결과물에는 영향을 주지 않습니다. 월 5,000건 이상의 패킹이 필요한 경우, 대량 및 OEM 가격에 대해 문의해 주시기 바랍니다.
웹훅
작업 완료 시 결과를 POST로 수신하려면 callback_url을(를) 전달하세요. 모든 콜백에는 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 | 모든 치수가 100mm 미만입니다 — 인치를 mm로 전송했을 가능성이 있습니다. "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 | 프로덕션 모드는 엔터프라이즈 플랜이 필요합니다. 샌드박스를 사용하거나 플랜을 업그레이드하세요. |
| sandbox_limit_reached | 402 | 월간 샌드박스 허용량을 모두 사용했습니다 — 매월 1일에 초기화됩니다. |
| quota_exceeded | 402 | 월간 생산 할당량 5,000건을 모두 사용했습니다 — 매월 1일에 초기화됩니다. 더 많은 용량이 필요하면 문의해 주시기 바랍니다. |
| too_many_jobs | 429 | 동시 작업 제한에 도달했습니다. 실행 중인 작업을 폴링하고 재시도하세요. |
| not_found | 404 | 이 워크스페이스에 해당 작업이 없습니다. |
질문, 더 높은 제한, 또는 필요한 커넥터(Zapier, Excel, MCP)가 있으신가요? hello@hansatic.com