Webhooks
Recibe eventos en tu servidor: registro de endpoints, verificación de firmas HMAC y política de reintentos.
Los webhooks avisan a tu servidor cuando cambia un recurso: por ejemplo, al comprar una guía, actualizar un rastreo o mover saldo. Registra un endpoint HTTPS y verifica la firma de cada entrega.
Registra un endpoint
Parámetros del cuerpo
urlstring
HTTPS y respuesta directa. Las redirecciones no se siguen, y un 3xx cuenta como fallo.
stringeventsstring[]
Los tipos de evento a los que se suscribe este endpoint (ver la tabla abajo).
string[]description?string
Nombre opcional para reconocer el destino.
stringcurl -X POST https://api.sendit.mx/v1/webhook-endpoints \
-H "X-API-Key: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://mitienda.mx/webhooks/sendit",
"description": "Receptor de producción",
"events": ["shipment.label.created", "shipment.tracking.updated"]
}'
{
"success": true,
"data": {
"id": "whe_a1b2c3d4e5f6",
"url": "https://mitienda.mx/webhooks/sendit",
"description": "Receptor de producción",
"events": ["shipment.label.created", "shipment.tracking.updated"],
"status": "ACTIVE",
"failureCount": 0,
"disabledAt": null,
"createdAt": "2026-07-18T10:00:00.000Z",
"signingSecret": "whsec_9f8e7d6c5b4a"
}
}
El campo se llama signingSecret. SendIt lo genera y lo devuelve solo al crear o rotar el endpoint. Guárdalo en un gestor de secretos: no puedes consultarlo de nuevo. El listado de endpoints nunca lo incluye.
Cada plan tiene un tope de endpoints activos. Registrar uno de más devuelve 403 PLAN_LIMIT_REACHED. Ver planes y cuotas.
Administra tus endpoints
| Método | Ruta | Descripción |
|---|---|---|
GET |
/v1/webhook-endpoints |
Listar tus endpoints |
GET/PATCH/DELETE |
/v1/webhook-endpoints/:id |
Consultar, actualizar o eliminar uno |
POST |
/v1/webhook-endpoints/:id/rotate-secret |
Generar un secreto nuevo (se devuelve una sola vez) |
POST |
/v1/webhook-endpoints/:id/test |
Enviar un evento webhook.test de inmediato |
GET |
/v1/webhook-endpoints/:id/events |
Historial de entregas de ese endpoint |
POST |
/v1/webhook-endpoints/:id/events/:eventId/redeliver |
Reintentar una entrega |
Las lecturas las puede hacer cualquier miembro autenticado. Las escrituras requieren rol ADMIN y el alcance webhooks:write.
Tipos de evento
Puedes suscribirte a estos eventos documentados:
| Evento | Cuándo se dispara |
|---|---|
shipment.created |
Se creó un envío |
shipment.updated |
Se actualizó un envío en DRAFT |
shipment.label.created |
Se compró una guía |
label.purchase.completed |
Una compra durable terminó: con éxito, con falla compensada o en action_required |
shipment.label.voided |
Se canceló una guía y se acreditó el reembolso |
shipment.tracking.updated |
El rastreo de la paquetería provocó un cambio de estado |
wallet.credited |
Se confirmó un crédito del monedero |
wallet.debited |
Se confirmó un débito por compra de guía |
wallet.low_balance |
Un débito LIVE cruzó el umbral configurado |
tracker.created |
Se registró un rastreador externo |
tracker.updated |
Un rastreador externo cambió de estado |
tracker.expired |
Un rastreador externo llegó a su TTL sin estado terminal |
Suscribe cada endpoint solo a los eventos que le interesan. Tu handler debe ignorar los tipos que no reconozca.
El payload
{
"id": "evt_1a2b3c4d5e",
"type": "shipment.tracking.updated",
"created": "2026-07-17T12:00:00.000Z",
"livemode": true,
"data": {
"object": {
"id": "clxq1w2e3r4t5y6u7i8o9p0a",
"status": "IN_TRANSIT",
"trackingNumber": "1234567890",
"carrierCode": "DHL",
"organizationId": "clxorg123"
}
}
}
createdes una marca de tiempo ISO-8601, no segundos epoch.data.objectes la proyección completa del recurso, no un subconjunto plano. Los eventos de envío traen dentro sus proyecciones defromAddress,toAddressylabel.- No hay
apiVersionniorganizationIden el nivel superior. Eldata.objectde un envío sí trae suorganizationId; el de un rastreador no. livemode: falsemarca los eventos de modo de prueba. Enrútalos a tu staging.ides único por evento. Úsalo para deduplicar si recibes una entrega repetida.
Verifica la firma
Cada entrega llega firmada con HMAC-SHA256 en el encabezado X-SendIt-Signature, con el formato t=<timestamp>,v1=<firma>:
POST /webhooks/sendit HTTP/1.1
X-SendIt-Signature: t=1752750000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
Content-Type: application/json
Verifica siempre antes de procesar. La firma es la única prueba de que el evento viene de SendIt:
import crypto from "node:crypto";
function verifySenditSignature(rawBody, signatureHeader, secret, toleranceSeconds = 300) {
const parts = Object.fromEntries(
signatureHeader.split(",").map((kv) => kv.split("="))
);
const { t, v1 } = parts;
// 1. Rechaza timestamps viejos (protección contra replay)
if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false;
// 2. Recalcula la firma sobre `${t}.${cuerpoCrudo}`
const expected = crypto
.createHmac("sha256", secret)
.update(`${t}.${rawBody}`)
.digest("hex");
// 3. Compara en tiempo constante
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}
Responde rápido, procesa después
Responde 2xx en cuanto persistas el evento, de preferencia en menos de un segundo. Procesa en segundo plano. Cualquier respuesta que no sea 2xx cuenta como fallo, incluidas las redirecciones.
Política de reintentos
| Intento | Espera |
|---|---|
| 1 | Inmediato |
| 2 | 2 min |
| 3 | 4 min |
| 4 | 8 min |
| 5 | 16 min |
Después del quinto intento el evento queda en EXHAUSTED y ya no se reintenta.
Un endpoint que falla continuamente durante 24 horas se deshabilita automáticamente. Cuando eso pasa, avisamos por correo a los administradores de la organización. Para reactivarlo, arregla tu servidor y manda una entrega de prueba con POST /v1/webhook-endpoints/:id/test: una prueba exitosa lo vuelve a habilitar.
Como las entregas pueden repetirse, haz tu procesamiento idempotente usando el id del evento.
Pruébalo sin riesgo
En modo de prueba, cada avance de estado dispara los webhooks reales con livemode: false. Compra una guía de prueba, avanza su estado y observa las entregas llegar a tu endpoint.
Errores
| Código | Cuándo ocurre | Cómo resolverlo |
|---|---|---|
400 INVALID_INPUT |
La URL o un tipo de evento no es válido | Usa HTTPS y un evento documentado |
403 INSUFFICIENT_SCOPE |
La llave no tiene webhooks:write para una escritura |
Emite una llave con el alcance requerido |
403 PLAN_LIMIT_REACHED |
La organización alcanzó su límite de endpoints | Elimina uno que no uses o cambia de plan |
404 RESOURCE_NOT_FOUND |
El endpoint o evento no existe | Verifica los identificadores |