Pakke-API
Indsend gods, få en optimeret og fysisk gyldig lastplan tilbage — placeringer, lastmeter, lineære fod og fakturerede pallplaceringer. Samme motor som i appen, løbende valideret mod virkelige dispatchers layouter. Sandbox-adgang på alle abonnementer; produktionsadgang på Enterprise.
Hurtig start
- Log ind → klik på dit navn → API → generér en nøgle.
- Indsend en pakkeopgave (denne kører i sandbox — gratis på alle abonnementer):
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-..."
}Poll status_url (samme autentificeringsheader) indtil status er "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/..."
}
}Endepunkter
POST /api/v1/pack
Validerer og sætter en pakkeopgave i kø. Returnerer 202 med et job_id. Understøtter en Idempotency-Key-header — gentagne forespørgsler med samme nøgle returnerer den oprindelige opgave i stedet for at pakke to gange.
GET /api/v1/jobs/{id}
Opgavestatus og, når den er færdig, det fulde resultat. Resultater gemmes i 30 dage; produktionsplaner ligger permanent i dit workspace.
GET /api/v1/openapi.json
Den maskinlæsbare OpenAPI 3.1-kontrakt — importer den i Postman, kodegeneratorer eller peg dit AI-kodningsværktøj på den. Køretøjskoder hentes fra den aktive motor, så den er altid opdateret. Åbn specifikationen ↗
Svarfelter
result-objektet for en afsluttet opgave:
| Felt | Type | Beskrivelse |
|---|---|---|
| placed_count / unplaced_count | integer | Antal varer, der passer / ikke passer. |
| units | "metric" | "imperial" | De enheder, alle nedenstående tal er angivet i (gentager forespørgslen). |
| metrics.ldm_m | number | Lastmeter — godsets udstrækning (maks. slut − min. start). |
| metrics.linear_ft | number | Samme udstrækning i lineære fod (US LTL). |
| metrics.span_mm | integer | Udstrækningen i mm, altid metrisk. |
| metrics.pallet_positions_eur | integer | null | Fakturerede EUR-pallplaceringer. null, hvis layoutet er for stort til at måle. |
| metrics.total_weight_kg | number | Placeret vægt, altid kg. |
| metrics.overlaps | integer | Gennemtrængende par — altid 0 for et gyldigt layout. |
| items[].placed | boolean | Om varen kom med i layoutet. |
| items[].x / y / z | number | null | Position i forespørgslens enheder: x fra dørsiden, y fra venstre væg, z fra gulvet. Alle tre er null, når placed er false. |
| items[].rotation_deg / tilt_deg | 0 | 90 | Orientering: rotation omkring lodret akse; tilt = lagt på siden. |
| items[].length / width / height / weight | number | Varen som indsendt, gentaget i forespørgslens enheder. |
| plan_url | string | null | Den oprettede plan i appen. null for sandbox-opgaver. |
Versionering og stabilitet
Kontrakten er versioneret i stien (/api/v1/). Inden for v1 er ændringer kun additive — nye valgfrie forespørgselsfelter, nye svarsfelter, nye køretøjskoder og fejlkoder kan forekomme, og klienter bør ignorere felter, de ikke genkender. Eksisterende felter ændrer aldrig betydning eller type, og intet fjernes. En brydende ændring betyder en ny versionssti, hvor v1 vedligeholdes parallelt i mindst 12 måneder med afviklingsmeddelelse pr. e-mail til alle workspaces med en aktiv nøgle.
Forespørgselsfelter
| Felt | Type | Beskrivelse |
|---|---|---|
| vehicle | string | En køretøjskode fra tabellerne nedenfor. Eller angiv {customVehicleId} (et køretøj fra din workspace-flåde). |
| objective | "ldm" | "pallets" | Minimer lastmeter eller fakturerede pallplaceringer. Standard "ldm". |
| units | "metric" | "imperial" | Hvordan varernes dimensioner og vægte læses OG returneres: mm/kg (standard) eller in/lb. Positioner i svaret følger samme enheder. |
| items | array, required | Godsmanifestet (felter nedenfor). |
| sandbox | boolean | Testtilstand: fuldt resultat, intet gemmes. Tilgængelig på alle abonnementer. |
| name | string | Plannavn (produktionstilstand). |
| ldm_limit_m | number | Begræns lasten til de første N lastmeter (lastbiler). |
| budget_ms | number | Optimeringsbudget i tid (produktion; standard 30000, maks. 300000). |
| callback_url | https URL | POSTes resultatet, når opgaven er færdig, underskrevet (se Webhooks). |
Varerfelter
| Felt | Type | Beskrivelse |
|---|---|---|
| length / width / height | number, required | Varens dimensioner, læst i forespørgslens enheder (mm som standard, tommer med "units": "imperial"). |
| weight | number, required | Varens vægt (kg som standard, lb med "units": "imperial"). |
| quantity | integer, default 1 | Udvider til individuelle enheder. |
| name | string, optional | Vises i planen og svaret. |
| stackable | boolean, default true | Andre varer må stables ovenpå denne vare. |
| max_stack | number, optional | Maks. vægt, denne vare kan bære ovenpå (samme enheder som vægt). |
| fragile | boolean, default false | Fragile varer placeres kun i de øverste lag. |
| tiltable | boolean, default true | Om varen må lægges på siden. |
| destination_stop | integer, default 1 | Leveringsstop for flerstop-LIFO-lastning. |
Køretøjskoder
Genereret ud fra de aktuelle motorspecifikationer. Brugerdefinerede køretøjer fra din workspace-flåde fungerer via custom_vehicle_id.
Lastbiler og trailere
| Kode | Køretøj | Indvendig (L×B×H) | Nyttelast |
|---|---|---|---|
| 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 |
Containere
| Kode | Container | Indvendig (L×B×H) | Nyttelast |
|---|---|---|---|
| 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 |
Adgangsniveauer og begrænsninger
| Sandbox (alle abonnementer) | Produktion (Enterprise) | |
|---|---|---|
| Forespørgsler | 25 succesfulde / måned | 5.000 vellykkede / måned |
| Varer pr. manifest | 20 | 5,000 |
| Samtidige opgaver | 1 | 10 |
| Optimeringsbudget | 10 s | 30 s standard, op til 300 s |
| Persistens | Intet gemmes | Hver pakning opretter en reel plan i dit workspace |
Kun vellykkede pakninger tæller — mislykkede valideringer og fejlede jobs trækker ikke fra kvoten. Begge tællere nulstilles den 1. (UTC). Sandbox-resultater er komplette og ubegrænsede — grænserne er adgangsporten, ikke outputtet. Har du brug for mere end 5.000 pakninger om måneden? Kontakt os for at høre om volumen- og OEM-priser.
Webhooks
Angiv callback_url for at modtage resultatet via POST, når opgaven er færdig. Hver callback indeholder X-Hansatic-Signature: en HMAC-SHA256 af den rå body med din nøgles webhook-hemmelighed (vises én gang ved nøglegenerering). Verificér den:
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));
}Levering sker i ét forsøg med 5 s timeout — status_url er altid den endelige sandhedskilde.
Fejl
Alle fejl er { "error": { "code", "message", ... } } — maskinlæsbar kode, menneskeligt læsbar besked og field, når et bestemt input er fejlbehæftet.
| Kode | HTTP | Betydning |
|---|---|---|
| invalid_key | 401 | Manglende, forkert formateret eller tilbagekaldt API-nøgle. |
| invalid_json | 400 | Body er ikke gyldig JSON. |
| invalid_vehicle | 400 | Ukendt køretøjskode / {customVehicleId}. |
| invalid_items | 400 | Et varerfelt mangler, er ikke-numerisk eller uden for gyldigt interval. |
| suspicious_dimensions | 400 | Alle dimensioner under 100 mm — sandsynligvis tommer sendt som mm. Angiv "units": "imperial". |
| invalid_units | 400 | units skal være "metric" eller "imperial". |
| invalid_objective | 400 | objective skal være "ldm" eller "pallets". |
| invalid_callback | 400 | callback_url skal være https. |
| too_many_items | 400 | Manifestet overskrider varergrænsen for dit adgangsniveau. |
| upgrade_required | 402 | Produktionstilstand kræver Enterprise-abonnement. Brug sandbox eller opgrader. |
| sandbox_limit_reached | 402 | Månedlig sandbox-kvote opbrugt — nulstilles den 1. |
| quota_exceeded | 402 | Månedlig produktionskvote på 5.000 pakninger er opbrugt — nulstilles den 1. Større volumen: kontakt os. |
| too_many_jobs | 429 | Begrænsning for samtidige opgaver nået. Poll kørende opgaver og prøv igen. |
| not_found | 404 | Ingen sådan opgave for dette workspace. |
Spørgsmål, højere grænser eller en connector, du har brug for (Zapier, Excel, MCP)? hello@hansatic.com