Packing API
Geef lading op en ontvang een geoptimaliseerd, fysiek geldig laadplan — posities, laadmeters, lineaire meters en gefactureerde palletposities. Dezelfde engine als in de app, continu gevalideerd aan de hand van echte dispatcher-indelingen. Sandbox-toegang op elk abonnement; productietoegang op Enterprise.
Snel starten
- Log in → klik op je naam → API → genereer een sleutel.
- Dien een pack-taak in (deze wordt in de sandbox uitgevoerd — gratis op elk abonnement):
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 de status_url (zelfde auth-header) totdat status "done" is:
{
"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/..."
}
}Eindpunten
POST /api/v1/pack
Valideert en plaatst een pack-taak in de wachtrij. Retourneert 202 met een job_id. Ondersteunt een Idempotency-Key-header — herhalingen met dezelfde sleutel retourneren de oorspronkelijke taak in plaats van dubbel te packen.
GET /api/v1/jobs/{id}
Taakstatus en, indien voltooid, het volledige resultaat. Resultaten worden 30 dagen bewaard; productieplannen blijven permanent in je werkruimte beschikbaar.
GET /api/v1/openapi.json
De machineleesbare OpenAPI 3.1-specificatie — importeer deze in Postman, codegenerators of richt je AI-coderingstool erop. Voertuigcodes worden ingevoegd vanuit de live-engine, dus deze is altijd actueel. Bekijk de specificatie ↗
Antwoordvelden
Het result-object bij een voltooide taak:
| Veld | Type | Omschrijving |
|---|---|---|
| placed_count / unplaced_count | integer | Aantal items dat past / niet past. |
| units | "metric" | "imperial" | De eenheden waarin alle onderstaande getallen worden uitgedrukt (overeenkomstig het verzoek). |
| metrics.ldm_m | number | Laadmeters — de omvang van het laadblok (max. einde − min. begin). |
| metrics.linear_ft | number | Dezelfde omvang in lineaire voet (US LTL). |
| metrics.span_mm | integer | De omvang in mm, altijd metrisch. |
| metrics.pallet_positions_eur | integer | null | Gefactureerde EUR-palletposities. null als de indeling te groot is om te meten. |
| metrics.total_weight_kg | number | Gewicht van de geplaatste lading, altijd in kg. |
| metrics.overlaps | integer | Overlappende paren — altijd 0 bij een geldige indeling. |
| items[].placed | boolean | Of het item in de indeling is geplaatst. |
| items[].x / y / z | number | null | Positie in de eenheden van het verzoek: x vanaf de deurzijde, y vanaf de linkermuur, z vanaf de vloer. Alle drie zijn null als placed false is. |
| items[].rotation_deg / tilt_deg | 0 | 90 | Oriëntatie: rotatie om de verticale as; tilt = op de zijde gelegd. |
| items[].length / width / height / weight | number | Het item zoals opgegeven, herhaald in de eenheden van het verzoek. |
| plan_url | string | null | Het aangemaakte plan in de app. null voor sandbox-taken. |
Versiebeheer en stabiliteit
Het contract is versiebeheerd in het pad (/api/v1/). Binnen v1 zijn wijzigingen alleen additief — nieuwe optionele aanvraagvelden, nieuwe antwoordvelden, nieuwe voertuigcodes en foutcodes kunnen verschijnen, en clients moeten velden negeren die ze niet herkennen. Bestaande velden veranderen nooit van betekenis of type, en niets wordt verwijderd. Een breaking change betekent een nieuw versiepad, waarbij v1 minimaal 12 maanden parallel wordt onderhouden en er een deprecation-melding per e-mail wordt verzonden naar elke werkruimte met een actieve sleutel.
Aanvraagvelden
| Veld | Type | Omschrijving |
|---|---|---|
| vehicle | string | Een voertuigcode uit de onderstaande tabellen. Of geef {customVehicleId} op (een voertuig uit je werkruimte-vloot). |
| objective | "ldm" | "pallets" | Minimaliseer laadmeters of minimaliseer gefactureerde palletposities. Standaard "ldm". |
| units | "metric" | "imperial" | Hoe itemafmetingen en -gewichten worden gelezen EN geretourneerd: mm/kg (standaard) of in/lb. Posities in het antwoord volgen dezelfde eenheden. |
| items | array, required | De ladingmanifest (velden hieronder). |
| sandbox | boolean | Testmodus: volledig resultaat, niets wordt opgeslagen. Beschikbaar op elk abonnement. |
| name | string | Naam van het plan (productiemodus). |
| ldm_limit_m | number | Beperk de lading tot de eerste N laadmeters (vrachtwagens). |
| budget_ms | number | Optimalisatie-tijdsbudget (productie; standaard 30000, max. 300000). |
| callback_url | https URL | Wordt via POST verzonden wanneer de taak is voltooid, ondertekend (zie Webhooks). |
Itemvelden
| Veld | Type | Omschrijving |
|---|---|---|
| length / width / height | number, required | Afmetingen van het item, gelezen in de eenheden van het verzoek (standaard mm, inches bij "units": "imperial"). |
| weight | number, required | Gewicht van het item (standaard kg, lb bij "units": "imperial"). |
| quantity | integer, default 1 | Wordt uitgevouwen naar individuele eenheden. |
| name | string, optional | Wordt weergegeven in het plan en het antwoord. |
| stackable | boolean, default true | Andere lading mag bovenop dit item worden geplaatst. |
| max_stack | number, optional | Maximaal gewicht dat dit item kan dragen (zelfde eenheden als gewicht). |
| fragile | boolean, default false | Breekbare items worden alleen op de bovenste lagen geplaatst. |
| tiltable | boolean, default true | Mag het item op de zijde worden gelegd. |
| destination_stop | integer, default 1 | Afleverstop voor multi-stop LIFO-laden. |
Voertuigcodes
Gegenereerd vanuit de live-engine-specificaties. Aangepaste voertuigen uit je werkruimte-vloot werken via custom_vehicle_id.
Vrachtwagens & opleggers
| Code | Voertuig | Interieur (L×B×H) | Laadvermogen |
|---|---|---|---|
| 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 |
Containers
| Code | Container | Interieur (L×B×H) | Laadvermogen |
|---|---|---|---|
| 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 |
Toegangsniveaus en limieten
| Sandbox (elk abonnement) | Productie (Enterprise) | |
|---|---|---|
| Aanroepen | 25 geslaagd / maand | 5.000 succesvolle / maand |
| Items per manifest | 20 | 5,000 |
| Gelijktijdige taken | 1 | 10 |
| Optimalisatiebudget | 10 s | 30 s standaard, tot 300 s |
| Persistentie | Niets opgeslagen | Elke pack creëert een echt plan in je werkruimte |
Alleen succesvolle pakketten tellen mee — mislukte validaties en mislukte taken worden niet in rekening gebracht voor een quotum. Beide tellers worden op de 1e (UTC) gereset. Sandbox-resultaten zijn volledig en onbeperkt — de limieten zijn de drempel, niet de uitkomst. Meer dan 5.000 pakketten per maand nodig? Neem contact met ons op voor volumekorting en OEM-prijzen.
Webhooks
Geef callback_url op om het resultaat via POST te ontvangen wanneer de taak is voltooid. Elke callback bevat een X-Hansatic-Signature: een HMAC-SHA256 van de onbewerkte body met het webhook-geheim van je sleutel (eenmalig getoond bij het aanmaken van de sleutel). Verifieer deze:
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 gebeurt in één poging met een time-out van 5s — de status_url blijft altijd de bron van waarheid.
Fouten
Alle fouten hebben de vorm { "error": { "code", "message", ... } } — een machineleesbare code, een menselijk leesbaar bericht en field als een specifiek invoerveld de fout veroorzaakt.
| Code | HTTP | Betekenis |
|---|---|---|
| invalid_key | 401 | Ontbrekende, onjuist gevormde of ingetrokken API-sleutel. |
| invalid_json | 400 | Body is geen geldige JSON. |
| invalid_vehicle | 400 | Onbekende voertuigcode / {customVehicleId}. |
| invalid_items | 400 | Een itemveld ontbreekt, is niet-numeriek of buiten het bereik. |
| suspicious_dimensions | 400 | Alle afmetingen onder 100 mm — waarschijnlijk inches verzonden als mm. Geef "units": "imperial" op. |
| invalid_units | 400 | units moet "metric" of "imperial" zijn. |
| invalid_objective | 400 | objective moet "ldm" of "pallets" zijn. |
| invalid_callback | 400 | callback_url moet https zijn. |
| too_many_items | 400 | Manifest overschrijdt de itemlimiet voor je toegangsniveau. |
| upgrade_required | 402 | Productiemodus vereist het Enterprise-abonnement. Gebruik de sandbox of upgrade. |
| sandbox_limit_reached | 402 | Maandelijks sandbox-contingent verbruikt — reset op de 1e van de maand. |
| quota_exceeded | 402 | Maandelijks productiequota van 5.000 pakketten bereikt — reset op de 1e. Voor hogere volumes: neem contact met ons op. |
| too_many_jobs | 429 | Limiet voor gelijktijdige taken bereikt. Poll actieve taken en probeer opnieuw. |
| not_found | 404 | Geen dergelijke taak voor deze werkruimte. |
Vragen, hogere limieten of een connector die je nodig hebt (Zapier, Excel, MCP)? hello@hansatic.com