Webhooks
Los webhooks te permiten enterarte de eventos importantes en tu workspace sin pollear. Cuando un usuario se registra en tu instancia, te mandamos un POST a tu endpoint con la info. Vos respondés 2xx y seguís.
Crear un webhook
Sección titulada «Crear un webhook»curl -X POST https://api.prysmid.com/v1/workspaces/$WS/webhooks \ -H "Authorization: Bearer $TOKEN" \ -d '{ "url": "https://yourapp.com/hooks/prysmid", "events": ["user.created", "user.deleted", "session.started"] }'Respuesta:
{ "id": "wh_abc123", "url": "https://yourapp.com/hooks/prysmid", "secret": "whsec_29uifd89...", // mostrado UNA vez; guardalo "events": ["user.created", "user.deleted", "session.started"], "created_at": "2026-04-28T10:00:00Z"}Verificar la firma
Sección titulada «Verificar la firma»Cada delivery viene con header Prysmid-Signature: t=<unix_ts>,v1=<hmac_sha256>. La firma se computa sobre <unix_ts>.<raw_body> con tu webhook secret como key HMAC.
import hmac, hashlib, time
def verify(secret, signature_header, raw_body, max_age_seconds=300): parts = dict(p.split("=", 1) for p in signature_header.split(",")) ts, sig = int(parts["t"]), parts["v1"] if abs(time.time() - ts) > max_age_seconds: raise ValueError("timestamp too old (replay protection)") expected = hmac.new(secret.encode(), f"{ts}.{raw_body}".encode(), hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, sig): raise ValueError("invalid signature")Eventos disponibles
Sección titulada «Eventos disponibles»| Evento | Cuándo dispara |
|---|---|
user.created | Nuevo usuario completó signup en tu instance. |
user.updated | Cambio de email, nombre, attributes. |
user.deleted | Usuario borrado por admin o por self-service. |
session.started | Login exitoso. |
session.ended | Logout o expiración. |
tenant.created | Nuevo tenant creado en tu workspace. |
tenant.deleted | Tenant borrado. |
plan.changed | Tu workspace cambió de plan (Free→Pro etc). |
subscription.past_due | Pago falló; estás en grace period. |
mau.threshold_warning | Cruzaste 80% / 95% / 100% del MAU incluido. |
signups_blocked | Spending cap alcanzado; nuevos signups bloqueados. |
Shape del payload
Sección titulada «Shape del payload»{ "id": "evt_abc123", "type": "user.created", "workspace_id": "ws_xyz", "tenant_id": "tn_acme", "created_at": "2026-04-28T10:00:00Z", "data": { "user_id": "294857...", "email": "alice@acme.com", "name": "Alice", "via_idp": "google" }}Política de retry
Sección titulada «Política de retry»Si tu endpoint responde no-2xx (o no responde en 10s), reintentamos con backoff exponencial:
- 1m, 5m, 30m, 2h, 6h, 12h, 24h, 48h.
- Después de 48h sin éxito, marcamos el evento como
failed_permanenty lo podés ver enSettings → Webhooks → Failed.
Idempotencia: usá el id del evento como deduplication key. Un mismo evento puede entregarse varias veces (al-menos-una-vez, no exactly-once).
Health del endpoint
Sección titulada «Health del endpoint»Si tu endpoint falla más del 5% del tráfico durante 30 minutos, te mandamos un email de aviso a los owners del workspace. Si sigue caído por 24h, pausamos las entregas (no las eventos — quedan encolados) hasta que lo reactives manualmente desde el dashboard.
Lo que NO está en webhooks (y por qué)
Sección titulada «Lo que NO está en webhooks (y por qué)»- Tokens emitidos (
access_token/id_token): no los exponemos por webhook. Riesgo de filtrar credenciales activas. - Passwords: nunca hashed, nunca plain. Ni siquiera el hash sale de la instance.
- Eventos del plano de control en realtime: cosas como “miembro del workspace cambió rol” — disponibles en audit log, no por webhook (frecuencia muy baja, no justifica push).