Ir al contenido

Webhooks

Prealerto entrega eventos a los endpoints HTTPS que el courier registra. Garantiza entrega al menos una vez; usa el identificador del evento para descartar duplicados.

Eventos

TipoCuándoPayload
prealert.confirmed Una prealerta pasa a confirmed o confirmed_without_tracking. Exactamente una vez por prealerta. data = objeto Prealert con documents[].url prefirmada.
prealert.updated Una prealerta confirmada cambia: llega el tracking, un operador corrige un campo, se une un duplicado. Prealert completo más changes, la lista de campos modificados.

Los eventos de prueba usan prealert.confirmed con test: true y datos ficticios; se firman igual que los reales.

Sobre

{
  "id": "evt_01J9W3Z8P4Q6R7S8T9U0V1W2X3",
  "type": "prealert.confirmed",
  "created_at": "2026-11-03T15:04:05Z",
  "test": false,
  "organization_id": "7d4f1c2e-7f0a-4c3d-9c2b-1a2b3c4d5e6f",
  "data": { "...": "Prealert" },
  "changes": ["tracking", "status"]
}
  • id es único por evento y estable entre reintentos.
  • changes solo aparece en prealert.updated.

Solicitud HTTP

  • Método POST, Content-Type: application/json; charset=utf-8.
  • User-Agent: Prealerto-Webhooks/1.0.
  • Encabezados Prealerto-Signature, Prealerto-Event-Id y Prealerto-Event-Type.
  • Timeout de 10 segundos. Cualquier 2xx cuenta como entregada.

Verificación de firma

  1. Toma el cuerpo crudo, sin re-serializar.
  2. Construye signed_payload = "{t}.{raw_body}".
  3. Calcula HMAC-SHA256 con tu secreto, en hexadecimal.
  4. Compara con v1 en tiempo constante.
  5. Rechaza si |now − t| > 300 segundos.

El secreto (whsec_…) se muestra una sola vez al crear el endpoint y se puede rotar; durante 24 horas se firma con ambos secretos y v1= aparece dos veces.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyPrealertoSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Reintentos

IntentoEspera desde el anterior
1inmediato
21 minuto
35 minutos
430 minutos
52 horas
68 horas
724 horas

Tras el intento 7 la entrega queda agotada. El panel muestra cada intento y permite reenviar; POST /webhooks/deliveries/{id}/retry hace lo mismo por API. Cincuenta entregas agotadas consecutivas deshabilitan el endpoint y avisan por correo.

Orden y aislamiento

No se garantiza orden entre eventos: usa data.updated_at para quedarte con la versión más reciente. Un endpoint solo recibe eventos del courier que lo registró.