Packing API

Invia il carico e ricevi un piano di carico ottimizzato e fisicamente valido — posizionamenti, metri di carico, piedi lineari e posizioni dei pallet fatturabili. Lo stesso motore utilizzato nell'app, continuamente validato rispetto ai layout reali dei dispatcher. Accesso sandbox su ogni piano; accesso in produzione su Enterprise.

Guida rapida

  1. Accedi → clicca sul tuo nome → API → genera una chiave.
  2. Invia un job di packing (questo viene eseguito in sandbox — gratuito su ogni piano):
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-..."
}

Interroga status_url (stesso header di autenticazione) finché status non è "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/..."
  }
}

Endpoint

POST /api/v1/pack

Convalida e mette in coda un job di packing. Restituisce 202 con un job_id. Supporta l'header Idempotency-Key — i tentativi ripetuti con la stessa chiave restituiscono il job originale invece di eseguire un nuovo packing.

GET /api/v1/jobs/{id}

Stato del job e, al termine, il risultato completo. I risultati vengono conservati per 30 giorni; i piani di produzione rimangono permanentemente nel tuo workspace.

GET /api/v1/openapi.json

Il contratto OpenAPI 3.1 leggibile dalla macchina — importalo in Postman, generatori di codice o indirizza il tuo strumento di coding AI. I codici dei veicoli sono iniettati dal motore live, quindi è sempre aggiornato. Apri la specifica ↗

Campi della risposta

L'oggetto result di un job completato:

CampoTipoDescrizione
placed_count / unplaced_countintegerQuanti articoli sono stati caricati / non sono stati caricati.
units"metric" | "imperial"Le unità di misura in cui sono espressi tutti i valori numerici (riprende la richiesta).
metrics.ldm_mnumberMetri di carico — l'estensione del blocco di carico (max fine − min inizio).
metrics.linear_ftnumberLa stessa estensione in piedi lineari (US LTL).
metrics.span_mmintegerL'estensione in mm, sempre metrica.
metrics.pallet_positions_eurinteger | nullPosizioni pallet EUR fatturabili. null se il layout è troppo grande per essere misurato.
metrics.total_weight_kgnumberPeso caricato, sempre in kg.
metrics.overlapsintegerCoppie interpenetranti — sempre 0 per un layout valido.
items[].placedbooleanIndica se l'articolo è stato inserito nel layout.
items[].x / y / znumber | nullPosizione nelle unità della richiesta: x dall'estremità della porta, y dalla parete sinistra, z dal pavimento. Tutti e tre i valori sono null se placed è false.
items[].rotation_deg / tilt_deg0 | 90Orientamento: rotazione attorno all'asse verticale; tilt = appoggiato su un lato.
items[].length / width / height / weightnumberL'articolo come inviato, riportato nelle unità della richiesta.
plan_urlstring | nullIl piano creato nell'app. null per i job in sandbox.

Versionamento e stabilità

Il contratto è versionato nel percorso (/api/v1/). All'interno di v1, le modifiche sono solo additive — nuovi campi opzionali nella richiesta, nuovi campi nella risposta, nuovi codici di veicoli e codici di errore possono apparire, e i client devono ignorare i campi che non riconoscono. I campi esistenti non cambiano mai significato o tipo, e nulla viene rimosso. Una modifica breaking comporta un nuovo percorso di versione, con v1 mantenuto in parallelo per almeno 12 mesi e avviso di deprecazione inviato via email a ogni workspace con una chiave attiva.

Campi della richiesta

CampoTipoDescrizione
vehiclestringUn codice veicolo dalle tabelle seguenti. Oppure passa {customVehicleId} (un veicolo dalla flotta del tuo workspace).
objective"ldm" | "pallets"Minimizza i metri di carico o le posizioni pallet fatturabili. Predefinito "ldm".
units"metric" | "imperial"Come vengono interpretate e restituite le dimensioni e i pesi degli articoli: mm/kg (predefinito) o in/lb. Le posizioni nella risposta seguono le stesse unità.
itemsarray, requiredIl manifesto del carico (campi sotto).
sandboxbooleanModalità test: risultato completo, nulla viene salvato. Disponibile su ogni piano.
namestringNome del piano (modalità produzione).
ldm_limit_mnumberLimita il carico ai primi N metri di carico (camion).
budget_msnumberBudget di tempo per l'ottimizzazione (produzione; predefinito 30000, massimo 300000).
callback_urlhttps URLRisultato inviato tramite POST al completamento del job, firmato (vedi Webhook).

Campi degli articoli

CampoTipoDescrizione
length / width / heightnumber, requiredDimensioni dell'articolo, lette nelle unità della richiesta (mm per impostazione predefinita, pollici con "units": "imperial").
weightnumber, requiredPeso dell'articolo (kg per impostazione predefinita, lb con "units": "imperial").
quantityinteger, default 1Espande in unità individuali.
namestring, optionalMostrato nel piano e nella risposta.
stackableboolean, default trueAltro carico può essere appoggiato sopra questo articolo.
max_stacknumber, optionalPeso massimo che questo articolo può sostenere sopra (stesse unità del peso).
fragileboolean, default falseGli articoli fragili vengono posizionati solo sugli strati superiori.
tiltableboolean, default trueL'articolo può essere appoggiato su un lato.
destination_stopinteger, default 1Fermata di consegna per il carico LIFO multi-fermata.

Codici veicolo

Generati dalle specifiche del motore live. I veicoli personalizzati dalla flotta del tuo workspace funzionano tramite custom_vehicle_id.

Camion e rimorchi

CodiceVeicoloInterno (L×L×A)Carico utile
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

Container

CodiceContainerInterno (L×L×A)Carico utile
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

Livelli di accesso e limiti

Sandbox (ogni piano)Produzione (Enterprise)
Chiamate25 riuscite / mese5.000 operazioni riuscite / mese
Articoli per manifesto205,000
Job simultanei110
Budget di ottimizzazione10 s30 s predefinito, fino a 300 s
PersistenzaNiente viene salvatoOgni packing crea un piano reale nel tuo workspace

Vengono conteggiati solo gli imballaggi riusciti — le validazioni fallite e i job non completati non vengono addebitati sulla quota. Entrambi i contatori si azzerano il 1° del mese (UTC). I risultati della sandbox sono completi e non limitati — il limite riguarda l'accesso, non l'output. Hai bisogno di più di 5.000 imballaggi al mese? Contattaci per soluzioni su volumi elevati e prezzi OEM.

Webhook

Passa callback_url per ricevere il risultato tramite POST al completamento del job. Ogni callback include X-Hansatic-Signature: un HMAC-SHA256 del corpo grezzo con il segreto webhook della tua chiave (mostrato una sola volta alla creazione della chiave). Verificalo:

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));
}

La consegna avviene con un singolo tentativo e timeout di 5s — status_url rimane sempre la fonte di verità.

Errori

Tutti gli errori sono { "error": { "code", "message", ... } } — codice leggibile dalla macchina, messaggio leggibile dall'utente e field quando un input specifico è errato.

CodiceHTTPSignificato
invalid_key401Chiave API mancante, malformata o revocata.
invalid_json400Il corpo non è un JSON valido.
invalid_vehicle400Codice veicolo / {customVehicleId} sconosciuto.
invalid_items400Un campo dell'articolo è mancante, non numerico o fuori intervallo.
suspicious_dimensions400Tutte le dimensioni inferiori a 100 mm — probabilmente pollici inviati come mm. Passa "units": "imperial".
invalid_units400units deve essere "metric" o "imperial".
invalid_objective400objective deve essere "ldm" o "pallets".
invalid_callback400callback_url deve essere https.
too_many_items400Il manifesto supera il limite di articoli per il tuo livello di accesso.
upgrade_required402La modalità produzione richiede il piano Enterprise. Usa la sandbox o effettua l'upgrade.
sandbox_limit_reached402Limite mensile sandbox raggiunto — si ripristina il 1° del mese.
quota_exceeded402Quota mensile di produzione di 5.000 imballaggi esaurita — si azzera il 1°. Per volumi superiori: contattaci.
too_many_jobs429Limite di job simultanei raggiunto. Interroga i job in esecuzione e riprova.
not_found404Nessun job trovato per questo workspace.

Domande, limiti più alti o un connettore di cui hai bisogno (Zapier, Excel, MCP)? hello@hansatic.com