API de Embalaje

Envía una lista de mercancías y recibe un plan de carga optimizado y físicamente válido: ubicaciones, metros de carga, pies lineales y posiciones de palets facturables. El mismo motor que impulsa la aplicación, validado continuamente con diseños reales de despachadores. Acceso al entorno de pruebas en todos los planes; acceso en producción con Enterprise.

Primeros pasos

  1. Inicia sesión → haz clic en tu nombre → API → genera una clave.
  2. Envía un trabajo de embalaje (este se ejecuta en el entorno de pruebas — gratuito en todos los planes):
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-..."
}

Consulta status_url (con el mismo encabezado de autenticación) hasta que status sea "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/..."
  }
}

Endpoints

POST /api/v1/pack

Valida y pone en cola un trabajo de embalaje. Devuelve 202 con un job_id. Admite el encabezado Idempotency-Key: los reintentos con la misma clave devuelven el trabajo original en lugar de procesarlo dos veces.

GET /api/v1/jobs/{id}

Estado del trabajo y, al finalizar, el resultado completo. Los resultados se conservan durante 30 días; en los planes de producción, permanecen en tu espacio de trabajo de forma permanente.

GET /api/v1/openapi.json

El contrato OpenAPI 3.1 legible por máquina: impórtalo en Postman, generadores de código o úsalo con herramientas de IA para desarrollo. Los códigos de vehículos se inyectan desde el motor en tiempo real, por lo que siempre está actualizado. Abrir la especificación ↗

Campos de respuesta

El objeto result de un trabajo finalizado:

CampoTipoDescripción
placed_count / unplaced_countintegerCantidad de artículos que caben / no caben.
units"metric" | "imperial"Unidades en las que se expresan todos los valores numéricos a continuación (eco de la solicitud).
metrics.ldm_mnumberMetros de carga — extensión del bloque de mercancías (máximo final − mínimo inicial).
metrics.linear_ftnumberLa misma extensión en pies lineales (LTL en EE.UU.).
metrics.span_mmintegerExtensión en mm, siempre en sistema métrico.
metrics.pallet_positions_eurinteger | nullPosiciones de palets EUR facturables. null cuando el diseño es demasiado grande para medir.
metrics.total_weight_kgnumberPeso total de los artículos colocados, siempre en kg.
metrics.overlapsintegerPares con solapamiento — siempre 0 en un diseño válido.
items[].placedbooleanIndica si el artículo se incluyó en el diseño.
items[].x / y / znumber | nullPosición en las unidades de la solicitud: x desde el extremo de la puerta, y desde la pared izquierda, z desde el suelo. Los tres valores son null cuando placed es false.
items[].rotation_deg / tilt_deg0 | 90Orientación: rotación sobre el eje vertical; tilt = colocado de lado.
items[].length / width / height / weightnumberDimensiones del artículo tal como se enviaron, en las unidades de la solicitud.
plan_urlstring | nullEl plan creado en la aplicación. null para trabajos en el entorno de pruebas.

Versionado y estabilidad

El contrato se versiona en la ruta (/api/v1/). Dentro de v1, los cambios son solo aditivos: nuevos campos opcionales en la solicitud, nuevos campos en la respuesta, nuevos códigos de vehículos y códigos de error pueden aparecer, y los clientes deben ignorar los campos que no reconozcan. Los campos existentes nunca cambian de significado o tipo, y nada se elimina. Un cambio disruptivo implica una nueva ruta de versión, con v1 mantenido en paralelo durante al menos 12 meses y notificación de obsolescencia por correo electrónico a cada espacio de trabajo con una clave activa.

Campos de solicitud

CampoTipoDescripción
vehiclestringCódigo de vehículo de las tablas siguientes. También puedes usar {customVehicleId} (un vehículo de tu flota en el espacio de trabajo).
objective"ldm" | "pallets"Minimizar metros de carga o minimizar posiciones de palets facturables. Por defecto "ldm".
units"metric" | "imperial"Unidades en las que se interpretan y devuelven las dimensiones y pesos de los artículos: mm/kg (por defecto) o in/lb. Las posiciones en la respuesta siguen las mismas unidades.
itemsarray, requiredManifiesto de carga (campos detallados a continuación).
sandboxbooleanModo de prueba: resultado completo, sin persistencia. Disponible en todos los planes.
namestringNombre del plan (modo producción).
ldm_limit_mnumberLimitar la carga a los primeros N metros de carga (camiones).
budget_msnumberTiempo máximo de optimización (producción; por defecto 30000, máximo 300000).
callback_urlhttps URLURL a la que se enviará el resultado mediante POST cuando finalice el trabajo, firmado (consulta Webhooks).

Campos de artículos

CampoTipoDescripción
length / width / heightnumber, requiredDimensiones del artículo, interpretadas en las unidades de la solicitud (mm por defecto, pulgadas con "units": "imperial").
weightnumber, requiredPeso del artículo (kg por defecto, lb con "units": "imperial").
quantityinteger, default 1Se expande en unidades individuales.
namestring, optionalSe muestra en el plan y en la respuesta.
stackableboolean, default trueIndica si otros artículos pueden apilarse sobre este.
max_stacknumber, optionalPeso máximo que este artículo puede soportar encima (mismas unidades que weight).
fragileboolean, default falseLos artículos frágiles se colocan solo en las capas superiores.
tiltableboolean, default trueIndica si el artículo puede colocarse de lado.
destination_stopinteger, default 1Parada de entrega para carga LIFO con múltiples paradas.

Códigos de vehículos

Generados a partir de las especificaciones del motor en tiempo real. Los vehículos personalizados de tu flota en el espacio de trabajo funcionan mediante custom_vehicle_id.

Camiones y remolques

CódigoVehículoInterior (L×A×H)Carga útil
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

Contenedores

CódigoContenedorInterior (L×A×H)Carga útil
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

Niveles de acceso y límites

Entorno de pruebas (todos los planes)Producción (Enterprise)
Llamadas25 exitosas / mes5.000 envíos exitosos / mes
Artículos por manifiesto205,000
Trabajos simultáneos110
Tiempo de optimización10 s30 s por defecto, hasta 300 s
PersistenciaNada almacenadoCada embalaje crea un plan real en tu espacio de trabajo

Solo se contabilizan los empaques exitosos — las validaciones fallidas y los trabajos fallidos nunca se descuentan de la cuota. Ambos contadores se reinician el día 1 (UTC). Los resultados en el entorno de pruebas son completos y sin restricciones — los límites son la barrera, no el resultado. ¿Necesita más de 5.000 empaques al mes? Consulte con nosotros sobre precios por volumen y OEM.

Webhooks

Proporciona callback_url para recibir el resultado mediante POST cuando el trabajo finalice. Cada llamada incluye X-Hansatic-Signature: un HMAC-SHA256 del cuerpo sin procesar con el secreto de webhook de tu clave (mostrado una vez al crear la clave). Verifícalo:

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

El envío se realiza en un solo intento con un tiempo de espera de 5 s — status_url sigue siendo la fuente de verdad.

Errores

Todos los errores tienen la forma { "error": { "code", "message", ... } }: código legible por máquina, mensaje legible por humanos y field cuando un campo de entrada específico es el problema.

CódigoHTTPSignificado
invalid_key401Clave API ausente, mal formada o revocada.
invalid_json400El cuerpo no es un JSON válido.
invalid_vehicle400Código de vehículo o {customVehicleId} desconocido.
invalid_items400Falta un campo de artículo, no es numérico o está fuera de rango.
suspicious_dimensions400Todas las dimensiones son menores a 100 mm — probablemente pulgadas enviadas como mm. Usa "units": "imperial".
invalid_units400units debe ser "metric" o "imperial".
invalid_objective400objective debe ser "ldm" o "pallets".
invalid_callback400callback_url debe ser https.
too_many_items400El manifiesto supera el límite de artículos para tu nivel de acceso.
upgrade_required402El modo producción requiere el plan Enterprise. Usa el entorno de pruebas o actualiza.
sandbox_limit_reached402Límite mensual del entorno de pruebas alcanzado — se reinicia el día 1.
quota_exceeded402Se ha agotado la cuota mensual de 5.000 empaques — se reinicia el día 1. Para mayor volumen: contáctenos.
too_many_jobs429Límite de trabajos simultáneos alcanzado. Consulta los trabajos en ejecución y reintenta.
not_found404No existe ese trabajo para este espacio de trabajo.

¿Preguntas, límites más altos o necesitas un conector (Zapier, Excel, MCP)? hello@hansatic.com