# Guía de actualizaciones de integración

Todos los cambios que se detallan a continuación son estrictamente aditivos: los endpoints existentes, los campos de respuesta, los códigos de estado HTTP, los bytes de la carga útil de los webhooks y el encabezado heredado `Signature` permanecen sin cambios. Las integraciones que no hagan nada siguen funcionando exactamente igual que antes. Adopte cada funcionalidad de forma independiente, en cualquier orden.

Servido en vivo en https://api.superlabel.ca/api/documentation/integration-updates?lang=es (`?download=1` para guardarlo). Documentos complementarios: OpenAPI (https://api.superlabel.ca/api/documentation?lang=es), colección de Postman (https://api.superlabel.ca/api/documentation/postman-collection), diccionario y flujo de estados (https://api.superlabel.ca/api/documentation/order-status-flow?lang=es).

---

## 1. Cancelación por número de seguimiento (idempotente)

`POST https://api.superlabel.ca/api/v1/orders/cancel` — proporcione exactamente uno de `order_id`, `tracking_number`, `external_tracking_number`.

```json
POST /api/v1/orders/cancel
Authorization: Bearer <token>
{ "external_tracking_number": "WP1234567890" }
```

- Éxito: `200 {"result":true,"id":123456,"already_cancelled":false,...}`
- Ya cancelado (reintento seguro): `200` con `"already_cancelled": true`
- El número coincide con varios pedidos activos: `409` con `"matched_order_ids": [...]` — reintente con `order_id`.
- El endpoint heredado `GET /v1/orders/{orderId}/cancel` permanece sin cambios.

## 2. Fuentes de reconciliación incremental

Recorra todo lo que cambió dentro de una ventana de tiempo; nunca omita ni cuente dos veces un registro gracias a la paginación por cursor.

- `GET https://api.superlabel.ca/api/v1/orders-reconciliation?updated_from=&updated_to=&per_page=&cursor=`
- `GET https://api.superlabel.ca/api/v1/tracking-events/reconciliation?...`

`updated_from` / `updated_to` aceptan marcas de tiempo unix o cadenas `Y-m-d H:i:s` en la zona horaria de la plataforma. Siga `next_cursor` hasta que `has_more` sea false; compare con los campos unix `*_timestamp`, nunca con cadenas de hora local. Los elementos de eventos de seguimiento incluyen `occurred_at` / `occurred_timestamp` (hora de ocurrencia de negocio; igual a la hora de creación para las filas históricas).

## 3. Códigos de error legibles por máquina y trazabilidad de solicitudes

Las respuestas de error de alta frecuencia de creación/cancelación ahora incluyen un campo `code` estable junto al `message` sin cambios:
`VALIDATION_FAILED`, `MISSING_IDENTIFIER`, `ORDER_NOT_FOUND`,
`ORDER_CANCEL_UNAUTHORIZED`, `ORDER_STATUS_NOT_CANCELLABLE`,
`ORDER_CANCEL_BLOCKED_THIRD_PARTY`, `LABEL_CANCEL_FAILED`,
`DUPLICATE_TRACKING_NUMBER`, `MULTIPLE_ORDERS_MATCHED`.
Los códigos son identificadores estables: pueden aparecer nuevos, pero los existentes nunca cambian de significado. Cada respuesta de la API también devuelve `X-Request-ID`; cítelo al reportar un problema.

## 4. Mejoras en la detección de duplicados

Con `auto_deduplication=1`, las entradas `exist_package_ref` / `exist_external_tracking_number` de una creación bloqueada ahora incluyen el `order_id` y el `order_ref` existentes, y el sobre incluye `"duplicate": true`. Modo estricto opcional: envíe `strict_duplicate_check=1` para recibir HTTP `409` en lugar del heredado `200` + `result:false` (omita el indicador para mantener el comportamiento heredado).

## 5. Opciones de creación por lotes

- `per_order_transaction: 1` (en el nivel superior del cuerpo del lote): cada pedido se confirma de forma independiente — un fallo ya no revierte a sus hermanos. Si el procesamiento se interrumpe antes de tiempo, seguirá recibiendo filas por todo lo que se completó, más una fila final `{"result":false,"batch_aborted":true}`.
- Los lotes de más de 100 pedidos reciben un encabezado de respuesta consultivo `X-Batch-Size-Warning`; prefiera `POST /v1/client/batchOrderCreateAsync` para grandes volúmenes.

## 6. Sincronización de archivos de prueba de entrega

Las entradas `proofs[]` de las respuestas de seguimiento ahora también incluyen:

```json
{ "url": "...", "full_url": "...", "type": 2,
  "file_id": 234567, "uploaded_at": "2026-07-20 14:30:05",
  "uploaded_timestamp": 1784745005,
  "signed_url": "https://.../files/pod/234567?expires=...&signature=...",
  "signed_url_expires_at": 1784745005 }
```

Utilice `file_id` como clave de deduplicación / sincronización incremental. `signed_url` es un enlace con caducidad (7 días) — vuelva a consultar el seguimiento para obtener uno nuevo tras su expiración. Los enlaces permanentes `url` / `full_url` permanecen sin cambios.

## 7. Webhooks: encabezados de firma v2 (todas las entregas)

Cada webhook ahora TAMBIÉN envía, junto al encabezado heredado `Signature` sin cambios:

| Encabezado | Significado |
|---|---|
| `X-Webhook-Event-Id` | UUID, estable entre reintentos — utilícelo para deduplicar |
| `X-Webhook-Timestamp` | segundos unix del primer envío |
| `X-Webhook-Signature-V2` | HMAC-SHA256 de `"<timestamp>.<raw body>"` |

Verificación (en cualquier lenguaje): `expected = HMAC_SHA256(timestamp + "." + raw_body, your_secret)`; compare con el encabezado en tiempo constante. La marca de tiempo se fija en el primer envío y se reutiliza en los reintentos (los reintentos pueden extenderse hasta ~3 horas), así que combine una ventana de tolerancia generosa con la deduplicación por `X-Webhook-Event-Id` en lugar de un corte de repetición estricto. Su verificación existente del encabezado heredado `Signature` sigue funcionando sin cambios — adopte la v2 cuando lo desee. Pruebe ambas firmas contra su endpoint desde la página de la guía de webhooks (`/webhooks-guide`).

## 8. Webhooks: sobre de carga útil opcional

Establezca `webhook_payload_envelope = 1` en la configuración de sus webhooks para recibir, dentro del cuerpo JSON de los eventos con forma de objeto: `event_id`, `event_time` (ISO8601 con desfase horario), `event_timestamp` (unix), además — cuando corresponda — de `is_correction: true` (un pedido previamente entregado/traspasado volvió a entrar en el flujo) y `occurred_at` / `occurred_timestamp` en los eventos de seguimiento. Sin el indicador, su carga útil permanece byte a byte idéntica a la anterior. Las cargas útiles con forma de lista (`order.create_async`) nunca se modifican.

## 9. Nuevos eventos de webhook (URLs de suscripción opcional)

- `pod.files_updated` — se añadió o eliminó una foto/firma de entrega a posteriori. Configure `pod_files_webhook_url`. Carga útil:
  `{"action":"added|removed","order_id":...,"order_ref":...,
  "tracking_number":[...],"external_tracking_number":[...],
  "file":{"file_id":...,"type":1|2,"note":null}, "event_id":..., ...}`
- `order.deleted` — un pedido fue eliminado permanentemente. Configure `order_deleted_webhook_url`. Carga útil: `{"action":"deleted","order_id":...,
  "order_ref":...,"tracking_number":[...],"external_tracking_number":[...],
  "event_id":..., ...}`

Ambos eventos incluyen siempre los campos del sobre y solo se envían cuando su URL está configurada.

## 10. Webhooks: opciones de entrega

- **Múltiples endpoints por evento**: cada ajuste de URL de webhook acepta una única URL (como antes), una lista separada por comas o un arreglo JSON. Cada endpoint recibe su propio ciclo de entrega y reintentos.
- **Verificación TLS**: establezca `webhook_verify_ssl = 1` para que las llamadas salientes verifiquen su certificado. El valor predeterminado permanece desactivado (comportamiento histórico).
- **order.created para todos los tipos de pedido**: establezca `order_created_webhook_all_types = 1` para extender el evento de pedido creado más allá de los pedidos de entrega local. El valor predeterminado mantiene el alcance histórico.
- **Secretos de firma**: las configuraciones iniciales reciben un secreto aleatorio robusto; los secretos existentes nunca se rotan automáticamente.

## 11. Alcances de tokens de API y listas de IP permitidas (opcional)

Los tokens individuales pueden limitarse a `orders:read`, `orders:write` y/o `webhooks:manage`, así como a una lista de IPs permitidas. Los tokens sin restricciones (el valor predeterminado, y todos los tokens preexistentes) se comportan exactamente como antes. Un token restringido que llame fuera de sus alcances/IPs recibe `403`. Póngase en contacto con soporte para restringir un token.

## 12. Envío de paquetes del transportista (Smart Locker)

Los transportistas externos envían paquetes al área de preparación de un almacén en una sola llamada por lotes. Opcionalmente se puede adjuntar un teléfono/correo del destinatario para notificarle con un código de recogida una vez que el paquete se coloca en un casillero inteligente. Los campos del destinatario son opcionales: el endpoint sigue siendo retrocompatible.

```json
POST https://api.superlabel.ca/api/v1/inventories/carrier-staging-stockin
Authorization: Bearer <token>
{ "carrier_id": 1, "warehouse_id": 10, "data": [
  { "carrier_reference_number": "TRK1", "ref": "REF1",
    "recipient_phone": "+14165550123", "recipient_email": "r@example.com" }
] }
```

```graphql
mutation($carrierId: Int!, $warehouseId: Int, $packages: Json) {
  submitCarrierPackages(carrierId: $carrierId, warehouseId: $warehouseId, packages: $packages)
}
```

- Autenticación: token Bearer como siempre. Las cuentas de cliente deben tener una autorización de carga del transportista (transportista + almacén); las cuentas client, employee y partner usan su propio ámbito de almacén.
- Por paquete: member_number y/o carrier_reference_number según la configuración del transportista; opcionales carrier_order_id, batch, ref, grid_code (solo personal), recipient_phone, recipient_email.
- Cada fila de la respuesta devuelve un pickup_code; el mismo código se entrega al destinatario en la notificación de recogida.

El contacto del destinatario se almacena cifrado y nunca se devuelve. Cuando se indican teléfono y correo, se notifican ambos canales; el teléfono/correo tiene prioridad sobre la notificación en la app por vínculo de socio.

## Compromiso de compatibilidad

Consulte la política de gestión de cambios: respuestas solo aditivas, nuevos endpoints junto a los antiguos, cuerpos de webhook congelados de forma predeterminada, valores predeterminados nunca modificados, obsolescencias anunciadas con al menos 30 días de antelación mediante los encabezados `Deprecation` / `Sunset`. Estas garantías se aplican mediante pruebas automatizadas de compatibilidad a nivel de bytes en cada versión.