Saltar al contenido

Webhooks

Suscríbete a eventos de XID y recibe payloads HTTP firmados cuando cambien usuarios, sesiones y organizaciones.

Ver como Markdown

Nomenclatura de eventos

Los eventos siguen el patrón <object>.<action>. Cada evento lleva un nombre de tipo estable, un svix-id único y una marca de tiempo ISO 8601.

Objeto Acciones
user created, updated, deleted
session created, ended, removed, revoked
organization created, updated, deleted
organizationMembership created, updated, deleted
organizationInvitation created, accepted, revoked
organizationDomain created, updated, deleted, verified, verification_failed
authentication password_succeeded, password_failed, passkey_succeeded, passkey_failed, mfa_succeeded, mfa_failed, oauth_succeeded, oauth_failed, sso_succeeded, sso_failed, magic_auth_succeeded, magic_auth_failed, email_verification_succeeded, email_verification_failed, radar_risk_detected
connection activated, deactivated, deleted, saml_certificate_renewed, renewal_required
dsync activated, deleted, user.created, user.updated, user.deleted, group.created, group.updated, group.deleted, group.user_added, group.user_removed
role created, updated, deleted
permission created, updated, deleted
email created (se dispara cuando el desarrollador asume el envío)
sms created (se dispara cuando el desarrollador asume el envío)
billing subscription.created, subscription.updated, paymentAttempt.succeeded, paymentAttempt.failed

Estructura del payload

Cada entrega de webhook es un HTTP POST con Content-Type: application/json. El cuerpo contiene type, data y encabezados de metadatos de nivel superior.

{
  "type": "user.created",
  "data": {
    "id": "usr_01abc",
    "email_addresses": [{ "email_address": "alice@example.com" }],
    "created_at": 1700000000000
  }
}

Verificación de firma

XID firma cada entrega con HMAC-SHA256. Verifica la firma antes de procesar el payload. Rechaza entregas con más de 5 minutos de antigüedad para prevenir ataques de reproducción.

Encabezado Descripción
svix-id ID de mensaje único. Úsalo para deduplicar entregas reintentadas.
svix-timestamp Segundos Unix cuando se envió el mensaje.
svix-signature HMAC-SHA256 codificado en Base64 de ${svix-id}.${svix-timestamp}.${raw-body} usando el secreto de firma del endpoint.
// Node.js / Cloudflare Workers example
async function verifyWebhook(request, secret) {
  const svixId = request.headers.get('svix-id')
  const svixTimestamp = request.headers.get('svix-timestamp')
  const svixSignature = request.headers.get('svix-signature')
  const body = await request.text()

  // Reject messages older than 5 minutes
  const ts = Number(svixTimestamp)
  if (Math.abs(Date.now() / 1000 - ts) > 300) {
    throw new Error('webhook timestamp out of tolerance')
  }

  const signedContent = `${svixId}.${svixTimestamp}.${body}`
  const keyData = Uint8Array.from(atob(secret), c => c.charCodeAt(0))
  const key = await crypto.subtle.importKey(
    'raw', keyData, { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']
  )
  const msgData = new TextEncoder().encode(signedContent)

  // svix-signature may contain multiple comma-separated values
  for (const sig of svixSignature.split(' ')) {
    const prefix = 'v1,'
    if (!sig.startsWith(prefix)) continue
    const sigBytes = Uint8Array.from(atob(sig.slice(prefix.length)), c => c.charCodeAt(0))
    const valid = await crypto.subtle.verify('HMAC', key, sigBytes, msgData)
    if (valid) return JSON.parse(body)
  }
  throw new Error('invalid webhook signature')
}

Reintentos y mensajes fallidos

  • Las entregas fallidas se reintentan con retroceso exponencial. Tras el número máximo de reintentos, el mensaje se escribe en el almacén de mensajes fallidos en D1 para inspección manual.
  • La entrega está desacoplada de la ruta de autenticación mediante Cloudflare Queues. Un endpoint lento o no disponible no afecta la latencia de inicio de sesión.
  • Usa el encabezado svix-id para deduplicar entregas en tu lado. Los reintentos llevan el mismo svix-id que el intento original.
flowchart LR
  XID --> Queue
  Queue -->|HTTPS| Endpoint
  Endpoint -->|2xx| ACK
  Endpoint -->|non-2xx| Retry
  Retry --> Queue
  Retry -->|max_retries| dlq["D1 DLQ"]

Reproducción manual

Usa POST /v1/webhooks/:endpointId/replay para reproducir eventos por ID de mensaje o rango de tiempo. Los eventos reproducidos llevan nuevos valores svix-id pero conservan el type y data originales.

# Replay events from the last hour
curl -X POST https://xid.dev/v1/webhooks/whe_xxx/replay \
  -H 'Authorization: Bearer sk_live_xxx' \
  -H 'Content-Type: application/json' \
  -d '{ "since": "2024-01-01T00:00:00Z", "until": "2024-01-01T01:00:00Z" }'

API de eventos

Además de los webhooks push, XID expone un flujo de eventos ordenado e inmutable con paginación por cursor en GET /v1/events. Extrae el flujo para construir sincronización confiable sin perder eventos entre reintentos de webhook.

curl 'https://xid.dev/v1/events?limit=100&after=evt_xxx' \
  -H 'Authorization: Bearer sk_live_xxx'
Navegación

Escribe para buscar...

Usa las flechas para navegarPulsa Intro para seleccionarPulsa Escape para cerrar