Los webhooks te permiten recibir eventos en tiempo real en un endpoint HTTPS controlado por vos. Cada evento se envía como un POST JSON firmado con HMAC.
Eventos disponibles
| Evento | Cuándo se dispara |
|---|---|
DMARC_THRESHOLD_REACHED | Compliance cae debajo del umbral configurado |
NEW_LOOKALIKE_DETECTED | Se detecta un lookalike nuevo |
RBL_LISTED | Una IP tuya aparece en un RBL |
PHISHING_REPORTED | Un empleado reporta un phishing |
PHISHING_CLUSTERED | Un cluster de phishing supera N reportes |
SSPM_HIGH_RISK_APP_ADDED | Nueva app OAuth con scopes peligrosos |
SSPM_NEW_INBOX_RULE | Nueva inbox rule sospechosa |
TAKEDOWN_RESOLVED | Un takedown pasa a resolved |
AWARENESS_CAMPAIGN_COMPLETED | Campaña de simulación termina |
AUDIT_LOG_ANOMALY | Anomalía en el audit log (login desde geo raro, etc.) |
Registrar un webhook
curl -X POST https://platform.emate.cloud/v1/webhooks \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your.endpoint/emate-hook",
"events": ["PHISHING_REPORTED", "NEW_LOOKALIKE_DETECTED"],
"secret": "generated-server-side-if-omitted"
}'
Respuesta:
{
"id": "wh_abc123",
"url": "https://your.endpoint/emate-hook",
"events": ["PHISHING_REPORTED", "NEW_LOOKALIKE_DETECTED"],
"secret": "whsec_xyz789...",
"created_at": "2026-07-08T10:00:00Z"
}
Guardá el secret — lo vas a necesitar para verificar la firma.
Formato del payload
{
"id": "evt_abc123",
"type": "PHISHING_REPORTED",
"created_at": "2026-07-08T14:22:00Z",
"tenant_id": "d3d3...",
"data": {
"phishing_id": "...",
"from_domain": "phish.example",
"from_address": "[email protected]",
"subject": "...",
"ai_classification": "credential_phishing",
"cluster_key": "cluster-invoice-2026Q3",
"iocs": {
"domains": ["phish.example"],
"ips": ["203.0.113.42"],
"urls": ["https://phish.example/login"]
}
}
}
Verificar la firma
Cada request incluye headers:
X-eMate-Signature-Timestamp— Unix timestamp del envío.X-eMate-Signature— hex deHMAC-SHA256(secret, "{timestamp}.{body}").
Ejemplo Python:
import hmac
import hashlib
import time
def verify(request_body: bytes, timestamp: str, signature: str, secret: str) -> bool:
# Rechazar requests > 5 min viejas (protección contra replay).
if abs(time.time() - int(timestamp)) > 300:
return False
signed = f"{timestamp}.{request_body.decode()}".encode()
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Ejemplo Node.js:
import crypto from 'crypto';
function verify(rawBody, timestamp, signature, secret) {
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const signed = `${timestamp}.${rawBody}`;
const expected = crypto.createHmac('sha256', secret).update(signed).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
Retries
Si tu endpoint devuelve algo distinto de 2xx (o timeout > 10s), la plataforma reintenta con backoff exponencial:
- Intento 1: inmediato.
- Intento 2: +30s.
- Intento 3: +2min.
- Intento 4: +10min.
- Intento 5: +1h.
- Intento 6: +6h.
- Intento 7: +24h.
Después del intento 7, la delivery queda como failed y podés redisparar manualmente desde /v1/webhooks/{id}/deliveries o desde la UI en Settings → Webhooks → Deliveries.
Best practices
- Devuelve 200 rápido. Si necesitás procesar largo, aceptá el webhook, encolá el work y devolvé 200. Los timeouts frustran retries innecesariamente.
- Idempotencia. La plataforma puede reintentar la misma delivery. Usá
evt_idcomo key de idempotencia. - Ordenamiento. Los webhooks no garantizan orden. Si necesitás secuencia, ordená por
created_aten tu lado. - Retention. Guardamos deliveries por 90 días. Después del período, no se puede redisparar.