Ciclo de vida de órdenes
Las órdenes representan pedidos de picking en Pickwise. Viajan por una secuencia de estados desde que entran hasta que son despachadas, y tu integración las trackea vía webhook o polling.
Conceptos clave
Sección titulada «Conceptos clave»Upsert por externalId
Sección titulada «Upsert por externalId»POST /orders es upsert: si el externalId ya existe y la orden está en PENDING, se actualiza. Si ya está en proceso (IN_PICKING o posterior), recibís 409 CONFLICT.
Validación cross productExternalId + productSku
Sección titulada «Validación cross productExternalId + productSku»Cada item de una orden debe referenciar un producto del catálogo por dos campos simultáneos: productExternalId y productSku. Pickwise valida que ambos coincidan con un producto existente (cross-reference) para prevenir desincronización entre tu sistema y el catálogo.
Issues y PENDING_VALIDATION
Sección titulada «Issues y PENDING_VALIDATION»Si algún item no resuelve contra el catálogo (producto inexistente, SKU mal pareado con externalId, stock insuficiente), la orden se crea igual pero en estado PENDING_VALIDATION con hasIssues: true. El equipo de almacén o una integración posterior resuelve el problema. Recibís el webhook order.issue_resolved cuando se completa.
Crear una orden
Sección titulada «Crear una orden»POST /orders — permisos: orders:write
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
externalId | string (max 100) | Sí | ID único en tu sistema |
orderNumber | string (max 100) | Sí | Número visible (debe ser único) |
items | array (min 1) | Sí | Items de la orden |
items[].productExternalId | string | Sí | externalId del producto |
items[].productSku | string | Sí | SKU del producto (validado cross) |
items[].quantity | number (≥ 1) | Sí | Cantidad |
priority | enum | No | low | medium | high | urgent |
channel | string (max 100) | No | Canal de venta |
orderDate | ISO 8601 | No | Fecha original en tu sistema |
dueDate | ISO 8601 | No | Fecha límite de despacho |
shippingMethod | string (max 100) | No | Método de envío |
shippingAddress | string (max 500) | No | Dirección de entrega |
notes | string (max 1000) | No | Notas internas |
customer | object | No | Datos del cliente |
customer.externalId | string | Sí* | *Requerido si customer presente |
customer.name | string | No | |
customer.email | string | No | |
customer.phone | string | No | |
metadata | object | No | Campos custom |
Ejemplos
Sección titulada «Ejemplos»curl -X POST https://api-{CLIENTE}.pickwise.com.ar/api/v1/public/orders \ -H "Authorization: Bearer pk_live_xxxx" \ -H "Content-Type: application/json" \ -d '{ "externalId": "ERP-ORD-98765", "orderNumber": "OC-2026-00543", "priority": "high", "channel": "MercadoLibre", "orderDate": "2026-03-07T10:00:00Z", "dueDate": "2026-03-08T18:00:00Z", "customer": { "externalId": "CLI-001", "name": "Juan Perez", "email": "juan@email.com" }, "items": [ { "productExternalId": "ERP-PROD-00123", "productSku": "AURICULAR-BT500", "quantity": 2 } ] }'const res = await fetch( 'https://api-{CLIENTE}.pickwise.com.ar/api/v1/public/orders', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.PICKWISE_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ externalId: 'ERP-ORD-98765', orderNumber: 'OC-2026-00543', priority: 'high', channel: 'MercadoLibre', orderDate: '2026-03-07T10:00:00Z', dueDate: '2026-03-08T18:00:00Z', customer: { externalId: 'CLI-001', name: 'Juan Perez', email: 'juan@email.com' }, items: [{ productExternalId: 'ERP-PROD-00123', productSku: 'AURICULAR-BT500', quantity: 2 }] }) });<?php$payload = json_encode([ 'externalId' => 'ERP-ORD-98765', 'orderNumber' => 'OC-2026-00543', 'priority' => 'high', 'channel' => 'MercadoLibre', 'orderDate' => '2026-03-07T10:00:00Z', 'dueDate' => '2026-03-08T18:00:00Z', 'customer' => [ 'externalId' => 'CLI-001', 'name' => 'Juan Perez', 'email' => 'juan@email.com' ], 'items' => [[ 'productExternalId' => 'ERP-PROD-00123', 'productSku' => 'AURICULAR-BT500', 'quantity' => 2 ]]]);
$ch = curl_init('https://api-{CLIENTE}.pickwise.com.ar/api/v1/public/orders');curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . getenv('PICKWISE_API_KEY'), 'Content-Type: application/json']);$response = curl_exec($ch);Respuesta exitosa (201)
Sección titulada «Respuesta exitosa (201)»{ "success": true, "action": "created", "data": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "externalId": "ERP-ORD-98765", "orderNumber": "OC-2026-00543", "status": "PENDING", "hasIssues": false, "itemsCount": 1, "unresolvedProducts": [] }, "requestId": "..."}Respuesta con productos no resueltos (201 con issues)
Sección titulada «Respuesta con productos no resueltos (201 con issues)»La orden se acepta igual, pero queda en PENDING_VALIDATION:
{ "success": true, "action": "created", "data": { "externalId": "ERP-ORD-98765", "status": "PENDING_VALIDATION", "hasIssues": true, "unresolvedProducts": [ { "productExternalId": "ERP-PROD-UNKNOWN", "productSku": "SKU-NO-EXISTE" } ] }, "warnings": [ "1 producto(s) no encontrados. La orden queda en estado PENDING_VALIDATION hasta resolver." ], "requestId": "..."}Respuesta con advertencia de stock (201)
Sección titulada «Respuesta con advertencia de stock (201)»{ "success": true, "action": "created", "data": { "status": "PENDING", "hasIssues": true }, "warnings": [ "Item 'AURICULAR-BT500': cantidad solicitada (100) supera stock disponible (5)" ]}Estados y transiciones
Sección titulada «Estados y transiciones»Diagrama
Sección titulada «Diagrama» ┌──→ IN_PICKING ──→ PICKED ──→ PACKED ──→ DISPATCHED │ PENDING ────┤ │ └──→ CANCELLED
PENDING_VALIDATION ──(issues resueltos)──→ PENDING │ └──→ CANCELLEDTabla de transiciones
Sección titulada «Tabla de transiciones»| Estado actual | Transiciones válidas | Quién la dispara |
|---|---|---|
PENDING | IN_PICKING, CANCELLED | Sistema (asignación) o integrador (cancel) |
PENDING_VALIDATION | PENDING, CANCELLED | Sistema (resolución) o integrador (cancel) |
IN_PICKING | PICKED | Sistema (picker completa) |
PICKED | PACKED | Sistema (packing) |
PACKED | DISPATCHED | Sistema (logística) |
DISPATCHED | — | Estado terminal |
CANCELLED | — | Estado terminal |
Consultar órdenes
Sección titulada «Consultar órdenes»Por externalId
Sección titulada «Por externalId»GET /orders/{externalId} — permisos: orders:read
{ "success": true, "data": { "id": "...", "externalId": "ERP-ORD-98765", "orderNumber": "OC-2026-00543", "status": "PICKED", "hasIssues": false, "itemsCount": 2, "createdAt": "2026-03-07T10:15:00Z", "updatedAt": "2026-03-07T14:30:00Z" }}Listado con filtros
Sección titulada «Listado con filtros»GET /orders — paginación por cursor.
Query parameters
Sección titulada «Query parameters»| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
limit | integer | 50 | Max 100 |
cursor | string | - | Token de nextCursor |
status | enum | - | Filtrar por estado (ver abajo) |
has_issues | boolean | - | Solo órdenes con / sin issues |
created_since | ISO 8601 | - | Creadas desde esa fecha |
updated_since | ISO 8601 | - | Actualizadas desde esa fecha |
Valores de status: PENDING | PENDING_VALIDATION | IN_PICKING | PICKED | PACKED | DISPATCHED | CANCELLED.
Delta sync vs webhooks
Sección titulada «Delta sync vs webhooks»Para enterarte de cambios de estado:
- Webhooks (recomendado): configurá un endpoint y recibí
order.status_changeden tiempo real. Ver guía de webhooks. - Polling con
updated_since: llamá periódicamente aGET /orders?updated_since=<ISO>&limit=100. Más simple pero consume rate limit.
Actualizar una orden
Sección titulada «Actualizar una orden»Hacé otro POST /orders con el mismo externalId. La orden se actualiza únicamente si está en PENDING. Si está en PENDING_VALIDATION, podés actualizar items para resolver los issues; si está en estados posteriores, recibís 409 CONFLICT.
Campos que se pueden cambiar: items, customer, notes, priority, shippingAddress, shippingMethod, dueDate, metadata.
Campos inmutables después de creada: externalId, orderNumber.
Cancelar una orden
Sección titulada «Cancelar una orden»POST /orders/{externalId}/cancel — permisos: orders:write
Sólo en PENDING o PENDING_VALIDATION.
curl -X POST https://api-{CLIENTE}.pickwise.com.ar/api/v1/public/orders/ERP-ORD-98765/cancel \ -H "Authorization: Bearer pk_live_xxxx"const res = await fetch( `https://api-{CLIENTE}.pickwise.com.ar/api/v1/public/orders/${externalId}/cancel`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.PICKWISE_API_KEY}` } });<?php$url = 'https://api-{CLIENTE}.pickwise.com.ar/api/v1/public/orders/' . $externalId . '/cancel';$ch = curl_init($url);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_POST, true);curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . getenv('PICKWISE_API_KEY')]);$response = curl_exec($ch);Respuesta (200)
Sección titulada «Respuesta (200)»{ "success": true, "data": { "externalId": "ERP-ORD-98765", "status": "CANCELLED", "cancelledAt": "2026-03-07T16:00:00Z" }}Error si está en proceso (409)
Sección titulada «Error si está en proceso (409)»{ "success": false, "error": { "code": "ORDER_IN_PROGRESS", "message": "La orden ya está en proceso de picking y no puede cancelarse" }}Issues y resolución
Sección titulada «Issues y resolución»Una orden entra en estado PENDING_VALIDATION (con hasIssues: true) cuando algún item no resuelve contra el catálogo. Casos típicos:
UNRESOLVED_PRODUCT:productExternalIdno existe, o no coincide con elproductSkuenviado.INSUFFICIENT_STOCK: stock insuficiente (warning; la orden sigue enPENDINGpero conhasIssues).
- Tu sistema envía la orden.
- Pickwise detecta el issue, crea la orden en
PENDING_VALIDATIONy dispara el webhookorder.issue_detected. - El equipo de almacén (o una integración) resuelve el issue — típicamente cargando el producto faltante o corrigiendo el SKU.
- Pickwise transiciona la orden a
PENDINGy disparaorder.issue_resolved.
Ver guía de webhooks para los payloads.
Crear órdenes en batch
Sección titulada «Crear órdenes en batch»POST /orders/batch — hasta 50 órdenes por request, máximo 10 MB.
{ "orders": [ { "externalId": "ERP-ORD-001", "orderNumber": "OC-001", "items": [{ "productExternalId": "P1", "productSku": "SKU1", "quantity": 1 }] }, { "externalId": "ERP-ORD-002", "orderNumber": "OC-002", "items": [{ "productExternalId": "P2", "productSku": "SKU2", "quantity": 3 }] } ]}Respuesta con contadores y detalle de errores por índice — mismo patrón que products/batch.
Errores comunes
Sección titulada «Errores comunes»| Código | Caso típico | Acción |
|---|---|---|
400 VALIDATION_ERROR | Item con quantity ≤ 0, sin productSku | Revisar details |
409 CONFLICT al cancelar | Orden ya en IN_PICKING o posterior | No se puede cancelar vía API |
409 CONFLICT al upsert | Orden existente no está en PENDING | Cancelar o esperar finalización |
413 PAYLOAD_TOO_LARGE | Batch > 10 MB o > 50 items | Partir el batch |