API de socios: enviar pedidos y recibir callbacks
Envío de pedidos (HMAC inbound en hex), callbacks order.created y order.status_changed (HMAC outbound sha256=), endpoints de reconciliación, deduplicación por X-N1-Delivery-Id, reintentos y circuit breaker con auto-recuperación.
En esta guía vas a…
- Construir la URL base y el endpoint
POST /api/webhooks/partner/orders - Firmar peticiones inbound (socio → N1) en hex, sin prefijo
- Validar callbacks outbound (N1 → socio) con
sha256=en la cabecera - Interpretar los códigos de respuesta y el ID
PARTNER-{identificador}-{external_order_id}
URLs base
Todas las rutas usan el mismo host de tu instancia N1 (donde está alojado el panel). Por ejemplo:
https://TU-DOMINIO-N1.com/api/webhooks/partner/ordershttps://TU-DOMINIO-N1.com/api/webhooks/partner/docshttps://TU-DOMINIO-N1.com/api/webhooks/partner/health
Sustituye TU-DOMINIO-N1.com por el dominio real.
Inbound — enviar pedidos (POST /api/webhooks/partner/orders)
Cabeceras obligatorias
Content-Type: application/jsonX-API-Key: clave con formatopk_live_opk_test_(la misma que se muestra al crear la API Key)X-Webhook-Timestamp: Unix en segundos (entero)X-Webhook-Signature: firma HMAC-SHA256 en hex ( sin el prefijosha256=)
Cómo calcular la firma (inbound)
- Cadena firmada:
timestamp + "." + cuerpo JSON en bruto— el punto es literal; el cuerpo debe ser exactamente los bytes enviados (mismo orden de claves, espacios y saltos de línea) HMAC-SHA256(cadena_firmada, webhook_secret)→ salida en hexadecimal- Envía ese hex en
X-Webhook-Signature
firma = HMAC_SHA256_hex( timestamp + "." + rawBody, webhook_secret )Ventana de tiempo
X-Webhook-Timestamp debe estar a como máximo unos 5 minutos del reloj del servidor (anti-replay). Las marcas de tiempo fuera de la ventana generan un error de firma o de timestamp.
Respuestas y errores
- 201: pedido creado con éxito (el cuerpo incluye
order_id) - 400: contenido inválido (esquema Zod) — corrige los campos indicados en
details - 401: API Key inválida/inactiva o firma HMAC inválida o timestamp ausente/inválido — revisa el secreto, la cadena firmada y
X-Webhook-Timestamp - 403: IP no permitida — cuando hay una lista blanca de IP configurada para esa clave (se ajusta vía administrador/API/soporte; no hay pantalla para esto en el panel de API Keys)
- 409: pedido duplicado — mismo
external_order_idpara el mismo identificador de socio - 429: límite de peticiones — espera y reinténtalo (la respuesta incluye la cabecera
retry_afteren segundos)
El ID del pedido en N1
El ID interno generado es:
PARTNER-{partnerIdentifier}-{external_order_id}
Usa el mismo external_order_id que enviaste en el JSON para correlacionarlo con el sistema de origen.
Outbound — callbacks (N1 → tu endpoint)
Cuando se crea un pedido o cambia de estado, N1 puede hacer POST a tu callbackUrl (si está configurado). La documentación completa con ejemplos de validación está en GET /api/webhooks/partner/docs y en el prompt de integración (botón del panel de API Keys).
Eventos
order.created: se dispara inmediatamente tras una creación correcta (útil como registro auditable más allá de la respuesta HTTP 201). Requiere"created"encallback_eventsde la API key.order.status_changed: se dispara ante cualquier cambio de estado del pedido, venga de donde venga (operaciones internas, transportista, 17TRACK, sincronizaciones).
La cabecera X-N1-Event indica qué evento se entregó.
Cabeceras + firma
X-N1-Signature:sha256=+ hex (distinto del inbound, que es solo hex)X-N1-Timestamp: Unix en segundos. Tu validación debe rechazar todo lo que quede fuera de la ventana de 5 minutos.X-N1-Event:order.createduorder.status_changedX-N1-Delivery-Id: UUID único — tu código DEBE deduplicar por este valor (TTL ≥ 30 días). La misma entrega puede llegar más de una vez (reintentos, reenvío manual).- Contenido firmado:
timestamp + "." + rawBody.
Reintentos, dead-letter y circuit breaker
- Tu endpoint debe responder 2xx. Cualquier otro estado (o un error de red) dispara un reintento: 3 intentos con espera
1min → 5min→ dead-letter. - Circuit breaker (auto-recuperación): tras 10 fallos consecutivos, N1 deja de enviar durante 30 minutos. Si vuelve a fallar al reabrir, la espera se duplica: 60 min → 120 min → … con un tope de 24 h. Cualquier respuesta 2xx lo reinicia. No requiere acción manual (el botón de reactivación del panel es solo un atajo).
Reconciliación (auto-recuperación del socio)
Si tu endpoint estuvo caído o perdiste callbacks, tres endpoints GET/POST te permiten recuperarte sin pedir ayuda manual. Exigen las mismas 6 capas de seguridad que el POST de creación; para GET, la cadena firmada es timestamp + "." + ruta-de-la-URL-con-query-string.
GET /api/webhooks/partner/orders/:external_order_id— estado actual de un pedido.GET /api/webhooks/partner/orders?updated_since=ISO&limit=100&offset=0— lista los pedidos modificados después de la marca de tiempo (paginado).POST /api/webhooks/partner/orders/:external_order_id/replay-callbacks— vuelve a encolar los últimos N callbacks de ese pedido (cuerpo:{ "limit": 5 }, por defecto 5, máximo 20).
Ejemplos completos en /api/webhooks/partner/docs y en el prompt LLM del panel.
Salud del servicio
GET /api/webhooks/partner/health — respuesta pública { "status": "ok", ... } para monitorización. No requiere autenticación.
Limitaciones y panel
El límite de peticiones y la lista blanca de IP existen en la API; si no aparecen en tu panel, considéralos ajustables vía administrador o soporte. No des por hecho botones que no están en la interfaz.
Artículo relacionado
Configuración en el panel (crear clave, secreto, callback): Claves API de socios — panel.