Apartado 5 de 12 · Sincronizar
Webhooks: que Chatendo te avise
Da de alta un webhook en Chatendo, los ocho eventos que envía, cómo comprobar la firma X-Vertichat-Signature y qué pasa cuando tu servidor no contesta.
En esta página (4)
5.1 · Dar de alta el aviso
Necesita el permiso webhooks:manage.
curl -s -X POST "$API/webhook-endpoints" \
-H "Authorization: Bearer $TOKEN" \
-H 'Accept: application/json' -H 'Content-Type: application/json' \
-d '{"url":"https://tu-servidor.example/chatendo",
"events":["message.received","conversation.assigned"]}'Respuesta (la forma, probada el 22-09-2026; el secreto, recortado y de ejemplo):
{"id":1,
"url":"https://tu-servidor.example/chatendo",
"events":["message.received","conversation.assigned"],
"active":true,
"created_at":"2026-09-22T17:18:24Z",
"signing_secret":"a1b2c3d4…"}Ese signing_secret es lo único que verás una vez. Guárdalo: sin él no puedes comprobar la firma, y sin comprobar la firma cualquiera puede llamar a tu URL fingiendo ser Chatendo.
La URL tiene que ser pública. Hay guardia anti-SSRF: una dirección interna o de red privada se rechaza con 422 SSRF_BLOCKED. Para desarrollo, usa un túnel público.
5.2 · Los ocho eventos de hoy
conversation.created conversation.assigned conversation.closed
conversation.snoozed conversation.unsnoozed message.received
message.status_updated order.createdCuerpo de message.received. Los campos son los que manda Chatendo, uno por uno; los valores son de ejemplo:
{"id": 86934,
"wamid": "wamid.HBg…",
"direction": "in",
"type": "text",
"body": "¿Seguís teniendo plaza?",
"conversation_id": 2856,
"contact_id": 41,
"created_at": "2026-09-22T17:02:05Z"}Fíjate en lo que NO trae: ni el teléfono ni el nombre. Con contact_id tienes que dar otra vuelta a GET /contacts/{id} por cada mensaje. Si vas a procesar volumen, cachea la ficha del contacto por contact_id.
5.3 · Comprobar la firma
Cada entrega lleva:
X-Vertichat-Signature: sha256=<hmac-sha256 del cuerpo crudo, con tu signing_secret>La cabecera conserva el nombre viejo del producto. Es un identificador, no una errata.
import hmac, hashlib
def firma_valida(cuerpo_crudo: bytes, cabecera: str, secreto: str) -> bool:
esperada = 'sha256=' + hmac.new(
secreto.encode(), cuerpo_crudo, hashlib.sha256
).hexdigest()
return hmac.compare_digest(esperada, cabecera or '')Dos reglas que no son opcionales:
- Sobre el cuerpo SIN parsear. Si lo deserializas y lo vuelves a serializar, un espacio distinto rompe la firma y te pasarás la tarde buscando el fallo donde no está.
- Comparación en tiempo constante (
compare_digest), nunca==.
5.4 · Contestar rápido
Hasta 5 intentos con espera creciente. Tras el quinto, la entrega queda en failed.
Devuelve 2xx en cuanto recibas y haz el trabajo después, en una cola tuya. Si procesas antes de contestar y tardas, Chatendo reintenta y te llega el mismo evento otra vez.
Las entregas se consultan en GET /webhook-endpoints/{id}/deliveries, y esa ruta pide webhooks:manage como las demás — devuelve los payloads ya enviados, con teléfonos y textos de clientes dentro. Cambió el 22-09-2026: hasta ese día era la única de las cinco que no lo pedía, y cualquier token del inquilino la leía. Si tu token es anterior y no tiene ese permiso, ahora recibirás 403.