パッキング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

積載ジョブを検証しキューに入れます。202job_id を返します。Idempotency-Key ヘッダーをサポート — 同じキーでの再試行は、重複実行せず元のジョブを返します。

GET /api/v1/jobs/{id}

ジョブのステータスと、完了時には完全な結果を返します。結果は30日間保持され、本番プランではワークスペース内に永続的に保存されます。

GET /api/v1/openapi.json

機械可読なOpenAPI 3.1仕様 — Postmanやコードジェネレーターにインポートしたり、AIコーディングツールで利用できます。車両コードはライブエンジンから注入されるため、常に最新です。 仕様を開く ↗

レスポンスフィールド

完了したジョブの result オブジェクト:

フィールド説明
placed_count / unplaced_countinteger積載できたアイテム数 / できなかったアイテム数。
units"metric" | "imperial"以下のすべての数値の単位(リクエストに準拠)。
metrics.ldm_mnumber積載メートル — 貨物ブロックの長さ(最大端 − 最小端)。
metrics.linear_ftnumber同じ長さをリニアフィートで表したもの(米国LTL)。
metrics.span_mminteger長さをミリメートルで表したもの(常にメートル法)。
metrics.pallet_positions_eurinteger | null請求対象のEURパレット位置数。レイアウトが大きすぎて測定できない場合はnull。
metrics.total_weight_kgnumber積載重量(常にkg)。
metrics.overlapsinteger重なり合うペア数 — 有効なレイアウトでは常に0。
items[].placedbooleanアイテムがレイアウトに積載されたかどうか。
items[].x / y / znumber | nullリクエスト単位での位置:xはドア側から、yは左壁から、zは床からの高さ。placedがfalseの場合はすべてnull。
items[].rotation_deg / tilt_deg0 | 90方向:垂直軸周りの回転、tiltは横置き。
items[].length / width / height / weightnumber送信されたアイテムの寸法(リクエスト単位に準拠)。
plan_urlstring | nullアプリで作成されたプランのURL。サンドボックスジョブの場合はnull。

バージョニングと安定性

API仕様はパス(/api/v1/)でバージョン管理されています。v1内では、変更は追加のみ — 新しいオプションのリクエストフィールド、新しいレスポンスフィールド、新しい車両コードやエラーコードが追加されることがありますが、クライアントは認識しないフィールドを無視する必要があります。既存のフィールドの意味や型が変更されることはなく、削除も行われません。破壊的変更がある場合は新しいバージョンパスが作成され、v1は少なくとも12か月間並行して維持され、アクティブなキーを持つすべてのワークスペースに非推奨通知がメールで送信されます。

リクエストフィールド

フィールド説明
vehiclestring以下の表から車両コードを指定。または、custom_vehicle_id(ワークスペースの車両フリートから)を渡します。
objective"ldm" | "pallets"積載メートルの最小化、または請求パレット位置の最小化。デフォルトは「ldm」。
units"metric" | "imperial"アイテムの寸法と重量の単位、およびレスポンスの単位:mm/kg(デフォルト)またはin/lb。レスポンスの位置も同じ単位で返されます。
itemsarray, required貨物のマニフェスト(以下のフィールド)。
sandboxbooleanテストモード:完全な結果が返されますが、何も保存されません。すべてのプランで利用可能。
namestringプラン名(本番モード)。
ldm_limit_mnumber積載を最初のNメートルに制限(トラックの場合)。
budget_msnumber最適化の時間制限(本番モード、デフォルト30000、最大300000)。
callback_urlhttps URLジョブ完了時に結果をPOSTで送信(署名付き、Webhookを参照)。

アイテムフィールド

フィールド説明
length / width / heightnumber, requiredアイテムの寸法。リクエストの単位(デフォルトはmm、「units」:「imperial」の場合はインチ)で読み取られます。
weightnumber, requiredアイテムの重量(デフォルトはkg、「units」:「imperial」の場合はlb)。
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 で利用可能。

トラック・トレーラー

コード車両内寸 (L×W×H)積載量
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

コンテナ

コードコンテナ内寸 (L×W×H)積載量
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価格についてはお問い合わせください。

Webhook

ジョブ完了時に結果をPOSTで受け取るには、callback_url を指定します。すべてのコールバックには X-Hansatic-Signature が含まれます:生のボディをキーのWebhookシークレット(キー作成時に一度表示)で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秒のタイムアウトで1回のみ試行されます — status_url が常に正確な情報源です。

エラー

すべてのエラーは { "error": { "code", "message", ... } } 形式 — 機械可読なコード、人間が読めるメッセージ、および問題のある入力フィールドを示す field で返されます。

コードHTTP意味
invalid_key401APIキーが不足、不正な形式、または無効化されています。
invalid_json400ボディが有効なJSONではありません。
invalid_vehicle400不明な車両コードまたはcustom_vehicle_idです。
invalid_items400アイテムフィールドが不足、数値でない、または範囲外です。
suspicious_dimensions400すべての寸法が100mm未満 — おそらくインチをmmとして送信しています。「units」:「imperial」を指定してください。
invalid_units400unitsは「metric」または「imperial」でなければなりません。
invalid_objective400objectiveは「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