Webhooks
Los dos webhooks del agente en Atendy: el de entrada (antes de la llamada) y el de fin de llamada, con la estructura del payload y buenas prácticas.
Webhooks (API)
Un webhook es una URL tuya (o de una herramienta como n8n, Make o tu propio servidor) a la que Atendy envía datos de forma automática en un momento concreto de la llamada. Cada agente puede tener dos webhooks, y sirven para cosas distintas: uno se dispara antes de que empiece la conversación y el otro cuando la llamada termina.
Ambos se configuran dentro del agente, en su asistente de herramientas o ajustes del agente, pegando la URL correspondiente. Funcionan tanto en llamadas de teléfono como en las pruebas desde el navegador.
Webhook de entrada (antes de la llamada)
En cuanto entra una llamada (o empiezas una prueba), Atendy hace una petición a tu URL de entrada con los datos que ya conoce, sobre todo el número de teléfono de quien llama. Tu servidor puede usar ese número para buscar a la persona en tu sistema y responder con datos suyos. Todo lo que devuelvas queda disponible como variables dentro del prompt y del saludo.
- Prepara una URL en tu servidor o herramienta que reciba una petición POST con JSON.
- En el agente, pega esa URL en el campo del webhook de entrada.
- Cuando llegue una llamada, Atendy enviará a esa URL el número de origen y el identificador del agente.
- Tu servidor responde con un JSON que contenga las variables que quieras usar (por ejemplo el nombre del cliente).
- El agente arranca la conversación ya con esos datos cargados.
Esto es un ejemplo de lo que Atendy envía a tu webhook de entrada:
{
"agent_id": "a1b2c3d4-0000-0000-0000-000000000000",
"caller_number": "+34600123456",
"room_name": "call-_+34600123456_a1B2c3"
}Y esto es lo que tu servidor debe responder: un JSON con las variables que quieras poner a disposición del agente. Los nombres de las claves son los que luego usarás entre dobles llaves.
{
"nombre": "Ana García",
"plan": "Premium",
"ultima_cita": "2026-07-02"
}Usar las variables en el prompt y el saludo
Cada variable que devuelva el webhook de entrada se escribe entre dobles llaves y Atendy la sustituye por su valor real justo antes de hablar. Puedes usarlas tanto en el prompt del sistema como en el saludo inicial.
Saludo inicial:
Hola {{nombre}}, gracias por llamar. Veo que tienes el plan {{plan}}.
Prompt del sistema:
Atiendes a {{nombre}}, cliente con plan {{plan}}.
Su última cita fue el {{ultima_cita}}. Ayúdale con lo que necesite
sobre su cuenta y confirma sus datos si hace falta.Webhook de fin de llamada
Cuando la llamada termina y Atendy ha analizado la conversación, envía a tu URL de fin de llamada un único mensaje con lo ocurrido: la transcripción completa, un resumen, los KPIs que hayas definido y los datos de la llamada. Es el momento ideal para volcar el resultado en tu CRM, avisar a tu equipo o lanzar un flujo en n8n.
El payload usa la misma estructura que el evento call_analyzed de Retell, para que los flujos ya construidos para ese formato funcionen sin cambios. Todo cuelga de un objeto call:
{
"event": "call_analyzed",
"call": {
"call_id": "call-out-4f3a9c2b1d7e",
"agent_id": "a1b2c3d4-0000-0000-0000-000000000000",
"agent_name": "Recepción",
"call_status": "ended",
"start_timestamp": 1786303502000,
"end_timestamp": 1786303645000,
"duration_ms": 143000,
"from_number": "+34911234567",
"to_number": "+34600123456",
"direction": "outbound",
"disconnection_reason": "agent_hangup",
"transcript": "Agent: Hola Ana, le llamo por su cita.\nUser: Sí, quería cambiarla.",
"transcript_object": [
{ "role": "agent", "content": "Hola Ana, le llamo por su cita." },
{ "role": "user", "content": "Sí, quería cambiarla." }
],
"call_analysis": {
"call_summary": "La clienta pidió cambiar su cita del jueves al viernes por la tarde. Se reprogramó y se le confirmó.",
"custom_analysis_data": {
"cita_reprogramada": true,
"motivo": "cambio de fecha"
}
}
}
}Campos que recibes, todos dentro de call:
| Campo | Qué contiene |
|---|---|
| event | Siempre call_analyzed. Va en la raíz, no dentro de call. |
| call_id | Identificador de la llamada. En una llamada lanzada por API es exactamente el call_id que te devolvió el POST, así que es la forma de casar tu petición con su resultado. |
| agent_id / agent_name | El agente que atendió la llamada. |
| call_status | Siempre ended: este aviso solo se envía con la llamada terminada. |
| direction | inbound en llamadas entrantes, outbound en salientes y web en las pruebas desde el navegador. |
| from_number / to_number | Números de la llamada según su dirección. En una saliente, from_number es tu número y to_number el de la persona a la que llamaste. |
| start_timestamp / end_timestamp | Momentos de inicio y fin en milisegundos desde el 1 de enero de 1970 (epoch), no en texto con fecha. Valen 0 si el inicio no se pudo determinar. |
| duration_ms | Duración en MILISEGUNDOS. Ojo si vienes de una integración que esperaba segundos. |
| disconnection_reason | Cómo terminó: agent_hangup, user_hangup, call_transfer o max_duration_reached. |
| transcript | La conversación como texto plano, con cada turno en una línea con el prefijo Agent: o User:. |
| transcript_object | La misma conversación turno a turno, con role (agent o user) y content. Fíjate en que el texto va en content, no en text. |
| call_analysis.call_summary | El resumen de la llamada. |
| call_analysis.custom_analysis_data | Los datos clave que le pediste extraer al agente (por ejemplo, si se cerró una cita). |