Webhook
Escucha eventos de tu cuenta de n1co buiness en tu punto de conexión de webhook para que tu integración pueda activar reacciones automáticas a medida que ocurren eventos en tu cuenta.
Por qué usar webhooks
Al crear integraciones con n1co Business, es posible que desees que tus aplicaciones reciban eventos a medida que ocurren en tu cuenta, para que tus sistemas de back-end puedan ejecutar las acciones necesarias.
Para habilitar los eventos de webhook, debes registrar los puntos de conexión de webhook. Después de registrarlos, n1co Business puede enviar datos de eventos en tiempo real al punto de conexión de tu aplicación cuando se produzcan eventos en tu cuenta. n1co Business utiliza HTTPS para enviar eventos de webhook a tu aplicación como una carga JSON que incluye un objeto event.
Recibir eventos de webhook es particularmente útil para escuchar eventos asincrónicos, por ejemplo, cuando se crea, paga o anula un pedido, cuando se actualiza el estado de envío de un pedido, etc.
Configuración de webhook
Para configurar un punto de conexión de webhook, debes proporcionar una URL de punto de conexión y generar una llave secreta. La URL de punto de conexión es la URL a la que n1co Business enviará eventos de webhook. La llave secreta es una cadena utilizada para firmar los eventos de webhook que se envían a tu aplicación. Puedes utilizar la llave secreta para verificar que los eventos que recibes provienen de n1co Business.
Crear un punto de conexión de webhook
Para crear un punto de conexión de webhook, sigue estos pasos:
- Inicia sesión en tu cuenta de n1co business
- En el menú de la parte superior derecha, haz clic en Configuración
- En la sección Opciones para desarrolladores, haz clic en Webhook
- Agrega la URL de tu punto de conexión de webhook y genera una llave secreta, luego haz clic en Guardar Cambios
- ¡Listo! Tu punto de conexión de webhook está listo para recibir eventos de n1co business
Eventos de webhook
n1co Business envía eventos de webhook a tu punto de conexión en tiempo real. Cada evento de webhook incluye un objeto event que contiene información sobre el evento que se ha producido en tu cuenta de n1co Business. Los eventos de webhook se envían como cargas JSON en una solicitud HTTPS POST a tu punto de conexión.
Headers del request
Cada entrega llega a tu endpoint con estos headers:
| Header | Descripción |
|---|---|
X-H4B-Hmac-Sha256 | HMAC-SHA256 en Base64 del raw body del request, firmado con tu secret key. Ver Verificación de eventos de webhook |
X-H4B-Event-Id | Identificador numérico del evento. No cambia entre reenvíos del mismo evento: deduplica por este valor |
X-H4B-Event-Created | Fecha y hora UTC (ISO 8601) en que se originó el evento. Tampoco cambia entre reenvíos |
El body y la firma no cambian respecto a versiones anteriores; X-H4B-Event-Id y X-H4B-Event-Created
son headers adicionales.
- Si tu comercio tiene varias URLs configuradas (separadas por
;), cada URL recibe su propioX-H4B-Event-Idpara el mismo evento. X-H4B-Event-Idtambién sirve para consultar el evento en la API:GET /api/v3/WebhookEvents/{eventId}devuelve la primera entrega del evento. Ver Recuperar eventos que no pudiste procesar.- Si una entrega nueva no se pudo registrar de nuestro lado (por ejemplo, durante una caída), el evento
se envía igual, pero sin
X-H4B-Event-IdniX-H4B-Event-Created, y no aparecerá en el historial de entregas ni se podrá reenviar. Deduplica esas entregas por su payload.
Entrega y reintentos
- At-least-once, en la medida de lo posible. Una entrega se reintenta 3 veces en cuestión de
segundos ante errores de conexión, respuestas
5xxy408. Después de eso no se reintenta automáticamente. Un mismo evento puede llegar más de una vez y los eventos pueden llegar desordenados. - Deduplica por
X-H4B-Event-Id. Guarda los identificadores que ya procesaste y descarta los repetidos; es la única forma confiable de no procesar dos veces el mismo evento. - Responde rápido. Devuelve un
2xxapenas hayas guardado el payload de tu lado y procésala de forma asíncrona. Cualquier otro status code marca la entrega como no entregada. - La API es la source of truth. Usa el webhook como señal y confirma el estado con
GET /api/v3/Orders/{id}cuando sea crítico, por ejemplo antes de liberar un producto. - Verifica la firma sobre el raw body, antes de parsearlo, con una comparación constant-time.
- Lo que se escape de los reintentos automáticos lo recuperas con la API de eventos de webhook.
Objeto Event
El contract para los eventos de webhook es el siguiente:
{
"orderId": "String!",
"orderReference": "String",
"orderType": "String!",
"description": "String!",
"level": "String!",
"type": "String!",
"metadata": "Object"
}
La definición de los campos del objeto event es la siguiente:
orderId: String! -> identificador interno de la orden generado por el sistema de n1co
orderReference: String -> referencia de la orden proporcionada por el integrador
orderType: String! -> tipo de orden que originó el evento
description: String! -> mensaje descriptivo de evento
level: String! -> nivel de severidad del evento
type: String! -> tipo de evento
metadata: Object -> key-value object que contiene información adicional sobre el evento
Niveles de severidad level
- Info: Indica información general o eventos que no requieren atención inmediata.
- Warning: Indica situaciones que podrían requerir atención o investigación, pero que no representan un error crítico o una falla del sistema.
- Error: Indica un error del sistema que requiere atención.
Tipos de orden orderType
Indica qué clase de orden originó el evento. Viene en todos los eventos y te permite, por ejemplo, separar la compra de un cupón o una giftcard de una venta normal sin consultar la API.
| Valor | Orden |
|---|---|
COUPON_APP | Compra de un cupón |
GIFTCARDS | Compra de una giftcard |
FASTLINK_CHARGE | Enlace de pago |
FULL | Orden completa |
STOREFRONT | Tienda en línea |
SUBSCRIPTION | Suscripción |
MENU_APP | App de menú |
EPAY | EPay |
SUPER_APP | SuperApp |
COURIER | Envío por courier |
MARKETPLACE | n1co plaza |
type y orderType no son lo mismotype es el tipo de evento (Created, SuccessPayment, …). orderType es el
tipo de orden que lo originó. Una misma orden emite varios eventos con distinto
type, pero todos con el mismo orderType.
Ten en cuenta además que las órdenes creadas desde un enlace de pago llegan como
FASTLINK_CHARGE, no como FULL.
Tipos de evento type
Created
Este evento indica que se ha creado un nuevo pedido en n1co business.
Ejemplo:
{
"orderId": "1057",
"orderReference": "test-3",
"orderType": "FASTLINK_CHARGE",
"description": "La orden fue creada",
"metadata": null,
"level": "Info",
"type": "Created"
}
SuccessPayment
Este evento indica que el pago de un pedido ha sido exitoso.
Ejemplo:
{
"orderId": "52544",
"orderReference": null,
"orderType": "COUPON_APP",
"description": "La orden fue pagada exitosamente autorización: 831000",
"metadata": {
"PaymentId": "3aaf6eaf-f32f-4857-8312-e63f4e497822",
"ChargeId": "af543e17-18d9-4512-b1ba-2991b6c31613",
"Status": "SUCCEEDED",
"AuthorizationCode": "831000",
"SequentialNumber": "7744791861156741504807",
"AccountId": "hugoapp.h4b",
"PaymentProcessor": "cybersource",
"PaymentProcessorReference": "7744791861156741504807",
"TransactionDate": "2026-03-25T22:53:06.6475595Z",
"PaidAmount": "8.00",
"BuyerName": "Juan Pérez",
"BuyerPhone": "+50370000000",
"BuyerEmail": "[email protected]",
"BuyerExternalId": "6x1ekkKH1a",
"CheckoutNote": "N/A",
"OrderReference": "",
"OrderTotalDetails": {
"subtotal": "8.0000",
"shippingAmount": "0",
"discountAmount": "0",
"surchargeAmount": "0",
"total": "8.00"
},
"IsManagedPaymentMethod": false,
"InvoiceName": "",
"InvoiceAddress": "",
"InvoiceTaxCode": "",
"orderDetail": [
{
"orderItemId": "13188",
"itemId": "30666",
"name": "Coconut Shrimp",
"price": "8.0000",
"promoId": null,
"promoPrice": null,
"promoName": null,
"quantity": "1",
"modifiersTotal": "0.0000",
"sku": "DL100",
"productImageUrl": "https://cdn.h4b.dev/images/.../Image1.webp",
"modifiers": [],
"note": null,
"description": "8 Camarones empanizados con coco rallado...",
"quantityAvailable": "75",
"requiresShipping": false,
"productMetadata": null,
"coupon": {
"code": "U6FWUW",
"qrCodeUrl": "https://qr.n1co.shop/?chl=U6FWUW",
"startDate": "2026-01-06T18:00:00",
"endDate": "2026-03-31T18:00:00",
"redemptionLimit": "1",
"redemptionCount": "0",
"status": "Unredeemed"
}
}
]
},
"level": "Info",
"type": "SuccessPayment"
}
Detalle de campos de metadata en SuccessPayment
| Campo | Tipo | Descripción |
|---|---|---|
PaymentId | String | Identificador único del pago |
ChargeId | String | Identificador único del cobro |
Status | String | Estado del pago (SUCCEEDED) |
AuthorizationCode | String | Código de autorización de la transacción |
SequentialNumber | String | Número secuencial de la transacción |
AccountId | String | Identificador de la cuenta del comercio |
PaymentProcessor | String | Procesador de pago utilizado |
PaymentProcessorReference | String | Referencia del procesador de pago |
TransactionDate | String | Fecha y hora de la transacción (ISO 8601) |
PaidAmount | String | Monto pagado |
BuyerName | String | Nombre del comprador |
BuyerPhone | String | Teléfono del comprador |
BuyerEmail | String | Email del comprador |
BuyerExternalId | String | Identificador externo del comprador |
CheckoutNote | String | Nota del checkout |
OrderReference | String | Referencia de la orden proporcionada por el integrador |
OrderTotalDetails | Object | Desglose de totales de la orden (subtotal, shippingAmount, discountAmount, surchargeAmount, total) |
IsManagedPaymentMethod | Boolean | Indica si el método de pago es gestionado por n1co |
InvoiceName | String | Nombre para facturación |
InvoiceAddress | String | Dirección para facturación |
InvoiceTaxCode | String | Código fiscal para facturación |
orderDetail | Array | Detalle de los productos de la orden (ver tabla siguiente) |
Detalle de productos orderDetail
| Campo | Tipo | Descripción |
|---|---|---|
orderItemId | String | Identificador del ítem en la orden |
itemId | String | Identificador del producto |
name | String | Nombre del producto |
price | String | Precio unitario del producto |
promoId | String | null | Identificador de la promoción aplicada |
promoPrice | String | null | Precio promocional |
promoName | String | null | Nombre de la promoción |
quantity | String | Cantidad del producto |
modifiersTotal | String | Total de modificadores aplicados |
sku | String | SKU del producto |
productImageUrl | String | URL de la imagen del producto |
modifiers | Array | Lista de modificadores aplicados al producto |
note | String | null | Nota del producto |
description | String | Descripción del producto |
quantityAvailable | String | Cantidad disponible en inventario |
requiresShipping | Boolean | Indica si el producto requiere envío |
productMetadata | Object | null | Metadatos adicionales del producto |
coupon | Object | null | Cupón asociado al producto (ver tabla siguiente). Es null si el producto no tiene cupón |
Objeto coupon
Cuando un producto tiene un cupón asociado, el campo coupon contiene la información del cupón generado para esa compra.
| Campo | Tipo | Descripción |
|---|---|---|
code | String | Código del cupón |
qrCodeUrl | String | URL del código QR para el cupón |
startDate | String | Fecha de inicio de validez del cupón (ISO 8601) |
endDate | String | Fecha de expiración del cupón (ISO 8601) |
redemptionLimit | String | Número máximo de veces que el cupón puede ser redimido |
redemptionCount | String | Número de veces que el cupón ha sido redimido |
status | String | Estado actual del cupón |
Estados posibles del cupón (status):
Unredeemed: El cupón está activo y disponible para ser redimidoRedeemed: El cupón ya alcanzó su límite de redencionesExpired: El cupón ha expirado (la fecha actual es posterior aendDate)Scheduled: El cupón aún no está activo (la fecha actual es anterior astartDate)
Cancelled
Este evento indica que un pedido ha sido anulado.
Ejemplo:
{
"orderId": "32395",
"orderReference": null,
"description": "La orden fue cancelada, motivo: some reason",
"metadata": null,
"level": "Info",
"type": "Cancelled"
}
Finalized
Este evento indica que el estado de un pedido ha sido finalizado.
Ejemplo:
{
"orderId": "32395",
"orderReference": null,
"description": "Se finalizó la orden.",
"metadata": null,
"level": "Info",
"type": "Finalized"
}
Updated
Este evento indica que se ha actualizado el estado de envío de un pedido en n1co business.
Listado de estados de envío:
PENDING: Orden pendienteACCEPTED: Orden aceptadaREADY: Orden listaDISPATCHED: Orden despachadaON_ITS_WAY: Orden en caminoDELIVERED: Orden entregadaSCHEDULED: Orden programadaREJECTED: Orden rechazada
Ejemplos:
Para el cambio de estado de PENDING a ACCEPTED:
{
"orderId": "13766",
"orderReference": null,
"description": "Se cambió el estado del envío de Pendiente a Aceptado",
"metadata": {
"PreparationEtaMinutes": "15",
"PreviousStatus": "PENDING",
"NewStatus": "ACCEPTED"
},
"level": "Info",
"type": "Updated"
}
Para el cambio de estado de ACCEPTED a READY:
{
"orderId": "13766",
"orderReference": null,
"description": "Se cambió el estado del envío de Aceptado a Preparado",
"metadata": {
"PreviousStatus": "ACCEPTED",
"NewStatus": "READY"
},
"level": "Info",
"type": "Updated"
}
Para el cambio de estado de READY a DISPATCHED:
{
"orderId": "13766",
"orderReference": null,
"description": "Se cambió el estado del envío de Preparado a Despachado",
"metadata": {
"PreviousStatus": "READY",
"NewStatus": "DISPATCHED"
},
"level": "Info",
"type": "Updated"
}
Para el cambio de estado de DISPATCHED a ON_ITS_WAY:
{
"orderId": "13766",
"orderReference": null,
"description": "Se cambió el estado del envío de Despachado a En Camino",
"metadata": {
"PreviousStatus": "DISPATCHED",
"NewStatus": "ON_ITS_WAY"
},
"level": "Info",
"type": "Updated"
}
Para el cambio de estado de ON_ITS_WAY a DELIVERED:
{
"orderId": "13766",
"orderReference": null,
"description": "Se cambió el estado del envío de En Camino a Entregado",
"metadata": {
"PreviousStatus": "ON_ITS_WAY",
"NewStatus": "DELIVERED"
},
"level": "Info",
"type": "Updated"
}
Deleted
Este evento indica que un pedido ha sido eliminado.
Ejemplo:
{
"orderId": "32395",
"orderReference": null,
"description": "Se eliminó la orden",
"metadata": null,
"level": "Info",
"type": "Deleted"
}
SuccessReverse
Este evento indica que se ha realizado una reversión exitosa de un pago.
Ejemplo:
{
"orderId": "1056",
"orderReference": null,
"description": "El pago de la orden fue revertido",
"metadata": null,
"level": "Info",
"type": "SuccessReverse"
}
ReverseError
Este evento indica que se ha producido un error al intentar revertir un pago.
Ejemplo:
{
"orderId": "1056",
"orderReference": null,
"description": "La orden no pudo ser cancelada, no se pudo revertir el pago",
"metadata": null,
"level": "Error",
"type": "ReverseError"
}
PaymentError
Este evento indica que se ha producido un error al intentar realizar un pago.
Ejemplo:
{
"orderId": "1056",
"orderReference": null,
"description": "El pago no fue realizado: some error",
"metadata": null,
"level": "Error",
"type": "PaymentError"
}
ThreeDSecureAuthSucceeded
Este evento indica que la autenticación 3DS se completó correctamente para un cobro específico y por ende se puede proceder con la confirmación de la transacción utilizando el authenticationId provisto en la metadata del evento.
Ejemplo:
{
"orderId": "31833",
"orderReference": "order-integration-id",
"description": "La autenticación 3DS ha sido completada con éxito",
"metadata": {
"authenticationId": "fdedee2f-5942-47ff-83a5-cb473d0e8764"
},
"level": "Info",
"type": "ThreeDSecureAuthSucceeded"
}
ThreeDSecureAuthError
Este evento indica que se produjo un error durante la autenticación 3DS para un cobro específico. El error puede deberse a varios motivos, como información incorrecta del titular de la tarjeta, problemas técnicos con el proveedor de autenticación 3DS o problemas de conectividad. Para más detalle se pueden consultar los atributos reason y description incluídos en la metadata del evento.
Ejemplo:
{
"orderId": "31833",
"orderReference": "order-integration-id",
"description": "Ocurrió un error en la autenticación 3DS",
"metadata": {
"authenticationId": "fdedee2f-5942-47ff-83a5-cb473d0e8764",
"reason" : "Some reason",
"description" : "Some description",
},
"level": "Error",
"type": "ThreeDSecureAuthError"
}
ThreeDSecureAuthExpired
Este evento es un indicador de que la autenticación 3DS no se completó a tiempo y que la transacción no se puede completar en este momento. Se puede volver a intentar la transacción más tarde una vez que el titular de la tarjeta inicie una nueva solicitud de autenticación.
Ejemplo:
{
"orderId": "31833",
"orderReference": "order-integration-id",
"description": "La autenticación 3DS ha expirado",
"metadata": {
"authenticationId": "fdedee2f-5942-47ff-83a5-cb473d0e8764"
},
"level": "Info",
"type": "ThreeDSecureAuthExpired"
}
ThreeDSecureAuthFailed
Este evento indica que hubo un fallo técnico que impidió que la autenticación 3DS se completara correctamente para un pedido específico. El fallo puede deberse a problemas con el proveedor de autenticación 3DS, problemas de integración o problemas del lado del servidor. Para más detalle se pueden consultar los atributos reason y description incluídos en la metadata del evento.
Ejemplo:
{
"orderId": "31833",
"orderReference": "order-integration-id",
"description": "Ocurrió un fallo en la autenticación 3DS",
"metadata": {
"authenticationId": "fdedee2f-5942-47ff-83a5-cb473d0e8764",
"reason" : "Some reason",
"description" : "Some description",
},
"level": "Error",
"type": "ThreeDSecureAuthFailed"
}
Verificación de eventos de webhook
Para verificar que los eventos de webhook que recibes provienen de n1co buiness, puedes utilizar la llave secreta que generaste al configurar tu punto de conexión de webhook. Para verificar un evento de webhook, sigue estos pasos:
- Extrae el valor de la cabecera
X-H4B-Hmac-Sha256de la solicitud HTTP POST que contiene el evento de webhook. - Calcula el HMAC SHA-256 del raw body del request HTTP POST, antes de parsearlo, utilizando el secret key generado al configurar tu endpoint de webhook.
- Compara el resultado en Base64 con el valor del header usando una comparación constant-time.
Ejemplo de verificación de eventos de webhook
Node.js
const crypto = require("crypto");
const express = require("express");
const app = express();
// Usa el raw body tal como llegó; no lo vuelvas a serializar
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
// Llave secreta configurada en el portal de n1co Business (Configuración → Webhook)
const API_SECRET = process.env.API_SECRET;
// Firma enviada por n1co (Base64)
const hmacHeader = req.get("X-H4B-Hmac-Sha256") || "";
// Calcular el HMAC SHA-256 del raw body y codificarlo en Base64
const hash = crypto.createHmac("sha256", API_SECRET).update(req.body).digest("base64");
// Comparación en tiempo constante
const expected = Buffer.from(hash);
const received = Buffer.from(hmacHeader);
if (expected.length !== received.length || !crypto.timingSafeEqual(expected, received)) {
console.log("Firma inválida");
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
console.log("Firma válida", event.type);
res.sendStatus(200);
});
Python
import base64
import hashlib
import hmac
import os
from flask import Flask, request, abort
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def webhook():
# Llave secreta configurada en el portal de n1co Business (Configuración → Webhook)
api_secret = os.environ["API_SECRET"]
# Firma enviada por n1co (Base64)
hmac_header = request.headers.get("X-H4B-Hmac-Sha256", "")
# Usa el raw body tal como llegó; no lo vuelvas a serializar
raw_body = request.get_data()
# Calcular el HMAC SHA-256 del raw body y codificarlo en Base64
digest = hmac.new(api_secret.encode("utf-8"), raw_body, hashlib.sha256).digest()
expected = base64.b64encode(digest).decode("ascii")
# Comparación en tiempo constante
if not hmac.compare_digest(expected, hmac_header):
print("Firma inválida")
abort(401)
event = request.get_json()
print("Firma válida", event.get("type"))
return "", 200
if __name__ == "__main__":
app.run()
PHP
<?php
// Llave secreta configurada en el portal de n1co Business (Configuración → Webhook)
$apiSecret = getenv("API_SECRET");
// Firma enviada por n1co (Base64)
$hmacHeader = $_SERVER["HTTP_X_H4B_HMAC_SHA256"] ?? "";
// Usa el raw body tal como llegó; no lo vuelvas a serializar
$rawBody = file_get_contents("php://input");
// Calcular el HMAC SHA-256 del raw body y codificarlo en Base64
$expected = base64_encode(hash_hmac("sha256", $rawBody, $apiSecret, true));
// Comparación en tiempo constante
if (!hash_equals($expected, $hmacHeader)) {
echo "Firma inválida";
http_response_code(401);
exit;
}
$event = json_decode($rawBody, true);
echo "Firma válida";
http_response_code(200);
Recuperar eventos que no pudiste procesar
Si tu endpoint estuvo caído o respondió con un error, no necesitas pedirle nada al comercio: la API de integración expone el historial de entregas de tu webhook y te permite reenviarlas.
| URL base | https://api.n1co.com/api/v3 |
| Autenticación | El mismo token Bearer que el resto de la API, obtenido con tus credenciales de cliente (clientId / clientSecret) |
| Alcance | Cada llamada solo ve las entregas del comercio asociado a tus credenciales |
| Método | Ruta | Para qué |
|---|---|---|
GET | /WebhookEvents | Listar entregas, de la más reciente a la más antigua, paginadas |
GET | /WebhookEvents/{id} | Consultar una entrega |
POST | /WebhookEvents/{id}/Resend | Volver a enviar el payload de una entrega, de forma síncrona |
Entregas y eventos
- Entrega: un
POSTHTTP de un webhook a una URL. Cada entrega queda registrada y tiene unid. Losidsolo crecen con el tiempo. - Evento: lo que ocurrió, por ejemplo un pago. Un evento tiene una o más entregas: la primera, más una
por cada reenvío. Su
eventIdes elidde su primera entrega, así queGET /api/v3/WebhookEvents/{eventId}devuelve esa primera entrega.
El objeto entrega
{
"id": 1201,
"eventId": 1201,
"eventType": "SuccessPayment",
"eventCreated": "2026-09-02T15:04:05Z",
"url": "https://example.com/n1co/webhook",
"payload": "{\"orderId\":\"123\",\"type\":\"SuccessPayment\"}",
"responseStatusCode": 503,
"delivered": false,
"created": "2026-09-02T15:04:05"
}
| Campo | Tipo | Descripción | Filtrar / ordenar |
|---|---|---|---|
id | Integer | Identificador de esta entrega | Sí |
eventId | Integer | Identificador del evento, compartido por la entrega original y sus reenvíos. Es igual a id en una primera entrega y es el valor que viaja en X-H4B-Event-Id | No |
eventType | String | Tipo de evento, el mismo type del objeto event | Sí |
eventCreated | String | Fecha y hora UTC del evento original. No cambia entre reenvíos | No |
url | String | URL a la que se hizo esta entrega | No |
payload | String | Body exacto que se envió, como string JSON | No |
responseStatusCode | Integer | Status code HTTP con que respondió tu endpoint. 0 es una entrega que no ha terminado. 500 también cubre fallos de conexión y timeouts | Sí |
delivered | Boolean | true cuando tu endpoint respondió 2xx | Sí |
created | String | Fecha y hora UTC en que se registró esta entrega | Sí |
Todas las fechas están en UTC. El signing key y los headers del request y del response nunca se devuelven.
Listar entregas
GET /api/v3/WebhookEvents lista las entregas de tu comercio.
| Valor por defecto | |
|---|---|
| Filtro | Ninguno: todas las entregas del comercio, entregadas, fallidas, in-flight y reenvíos |
| Orden | De la más reciente a la más antigua, por id descendente |
page | 1 si se omite. Un valor menor que 1 se rechaza con 400 |
pageSize | 50 si se omite. Un valor mayor que 100 se reduce a 100. Un valor de 0 o menor se rechaza con 400 |
Query params, los mismos de filtrado, orden y paginación del resto de la API v3:
| Parámetro | Ejemplo | Notas |
|---|---|---|
filters | delivered==false,id%3E1150 | La coma equivale a AND. Operadores: ==, !=, >, <, >=, <=, @= (contiene) y _= (empieza con). Aplica URL-encode al valor: un < o > sin encodear en el query string se rechaza con 404, así que id>1150 se envía como id%3E1150 |
sorts | id o -id | Reemplaza el orden por defecto. El prefijo - ordena de forma descendente |
page | 1 | Empieza en 1 |
pageSize | 100 | Máximo 100 |
Respuesta:
{
"webhookEvents": [ { "...": "objeto entrega" } ],
"totalCount": 1
}
totalCount cuenta todas las entregas que cumplen filters, sumando todas las páginas.
Uso recomendado: consultar con un cursor de id
Usa el id de la entrega como cursor en lugar de números de página: los números de página se desplazan a
medida que llegan entregas nuevas y el cursor no.
- Guarda el último
idde entrega que procesaste. - Pide lo que viene después, de la más antigua a la más reciente:
Envía siempre
GET /api/v3/WebhookEvents?filters=id%3E1150&sorts=id&pageSize=100sorts=idal consultar con cursor. Sin él la lista viene de la más reciente a la más antigua, y una página después de tu cursor se salta las entregas intermedias más antiguas. - Procesa la página, mueve el cursor al último
idde esa página y repite pidiendo la página 1 hasta que una página venga vacía. - Para recuperar un evento, pasa su
payloadal mismo handler que atiende tu endpoint de webhook. Solo necesitas reenviar cuando quieres una nueva entrega HTTP.
Para ver solo las fallidas, agrega delivered==false:
GET /api/v3/WebhookEvents?filters=delivered==false,id%3E1150&sorts=id&pageSize=100
payload es exactamente el body que se envió a tu URL, así que lo más simple suele ser pasárselo al
mismo handler que atiende tu endpoint de webhook.
Errores comunes
- Una entrega fallida sigue fallida después de un reenvío exitoso. El reenvío es una entrega nueva con
el mismo
eventId, y la original conservadelivered: false. Por esodelivered==falsepuede listar eventos que ya se entregaron después. Agrupa poreventId: un evento sigue pendiente solo mientras ninguna de sus entregas tengadelivered: true. - Deduplica por
eventId. Es igual al headerX-H4B-Event-Id, así que puedes descartar los eventos que ya procesaste desde el webhook en vivo. - Un
responseStatusCodede0es una entrega que seguía in-flight o que se interrumpió. Vuelve a consultarla antes de tratarla como fallida. - Filtra por
id>siempre que puedas. Los filtros pordelivered,createdoeventTypesin un cursorid>son más lentos en comercios con mucho historial, y lo mismo pasa con eltotalCountque acompaña cada página. - Las entregas que no se pudieron registrar no aparecen. Llegaron sin
X-H4B-Event-IdniX-H4B-Event-Created(ver Headers del request); deduplícalas por su payload.
Consultar una entrega
GET /api/v3/WebhookEvents/{id} devuelve un objeto entrega.
| Status | Cuándo |
|---|---|
200 | La entrega existe para tu comercio |
404 | El id no existe o pertenece a otro comercio |
Reenviar una entrega
POST /api/v3/WebhookEvents/{id}/Resend vuelve a enviar el payload almacenado de la entrega {id}, de forma
síncrona, y devuelve la nueva entrega.
- Se firma con el signing key vigente del webhook del comercio y va a su configuración actual.
- Lleva el
X-H4B-Event-Idy elX-H4B-Event-Createdoriginales, así que un consumidor que deduplica lo reconoce. - Se registra como una entrega nueva, con un
idnuevo y el mismoeventId. - Reenviar un reenvío conserva el identificador del evento original.
¿Qué URL lo recibe?
| Configuración del comercio | Destino |
|---|---|
| La URL de la entrega sigue configurada | Solo esa URL. La comparación ignora espacios alrededor y mayúsculas/minúsculas |
| La URL de la entrega ya no está configurada | Todas las URLs configuradas. La respuesta es una entrega fallida si alguna falló; si no, la última |
La respuesta es el objeto de la nueva entrega: su campo delivered te dice de inmediato si tu endpoint
la aceptó.
| Status | Cuándo |
|---|---|
200 | Se envió. Revisa delivered en el body del response: un 200 aquí no significa que tu endpoint lo aceptó |
400 | El comercio no tiene webhook configurado, o su configuración de URL no contiene ninguna URL |
404 | El id no existe o pertenece a otro comercio |
500 | El reenvío no se pudo registrar. Es seguro reintentar, porque cada entrega lleva el mismo X-H4B-Event-Id |
Un reenvío llega con el X-H4B-Event-Id del evento original. Si ya habías procesado ese evento,
tu handler debe descartarlo.
Limitaciones conocidas
eventIdyeventCreatedno se pueden usar enfiltersni ensorts.- Los reintentos automáticos siguen deteniéndose a los pocos segundos. Esta API es el camino de recuperación para todo lo que se escape.