> ## Documentation Index
> Fetch the complete documentation index at: https://help.asistian.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Enviar datos a otro sistema (webhook saliente)

> Avisa a tu CRM, ERP, Zapier, Make o n8n cuando algo pasa en Asistian: una automatización con la acción Enviar Webhook manda un POST con JSON a tu URL.

Un **webhook saliente** es un aviso que Asistian le manda a otro sistema en el
momento en que algo pasa: se creó una conversación, un contacto se calificó, se
agendó una reserva, se cerró una venta. Tu sistema recibe un `POST` con los
datos en JSON y hace con ellos lo que necesites.

En Asistian se arma con una **automatización**: el evento decide **cuándo** se
envía y la acción **Enviar Webhook** decide **a dónde** y **qué** se envía.

<Note>
  ¿Quieres lo contrario, que tu sistema le avise a Asistian? Eso es un
  [webhook entrante](/mintlify/automatizaciones/webhook-entrante).
</Note>

## Antes de empezar

* Una **URL pública** (`https://…`) que acepte un `POST` con JSON. Si usas
  Zapier, Make o n8n, es la URL que te da su disparador de tipo *Webhook*.
* Si todavía no tienes servidor, usa [webhook.site](https://webhook.site): te
  da una URL de prueba y te muestra todo lo que le llega.

## Crear el webhook

<Steps>
  <Step title="Crea la automatización">
    Ve a **Configuración → Automatizaciones → Crear Automatización**.
  </Step>

  <Step title="Elige cuándo se envía">
    En el nodo del evento, abre **Tipo de Evento** y elige qué tiene que pasar.
    Sirve cualquiera de los eventos de la
    [lista completa](/mintlify/automatizaciones/eventos). Los más usados para
    avisar a otro sistema:

    | Si quieres avisar cuando… | Elige |
    | - | - |
    | Llega una conversación nueva | **Conversación creada** |
    | Un contacto llega a una etapa | **Contacto cambia de etapa** |
    | Un contacto se califica o se gana | **Contacto calificado** / **Contacto ganado** |
    | Se agenda o se cancela una cita | **Reserva creada** / **Reserva cancelada** |
    | Se registra una venta | **Venta creada** |
    | Se crea un ítem en un tablero | **Nuevo ítem de tablero** |

    Si solo te interesan algunos casos (por ejemplo, un buzón o una etapa en
    particular), agrega condiciones.
  </Step>

  <Step title="Agrega la acción Enviar Webhook">
    Haz clic en el **+** de la línea que une el evento con **Fin**, escribe
    `webhook` en el buscador y elige **Enviar Webhook**.
  </Step>

  <Step title="Llena los datos del envío">
    | Campo | Para qué sirve |
    | - | - |
    | **URL del Webhook** (obligatorio) | La dirección que recibe el `POST` |
    | **Nombre del Evento** | Un nombre para que tu sistema sepa qué pasó, por ejemplo `contacto_calificado`. Viaja en el encabezado `X-Webhook-Event`. Si lo dejas vacío, se usa `automation_triggered` |
    | **Secreto** | Una clave que inventas tú. Con ella Asistian **firma** cada envío para que tu sistema compruebe que viene de Asistian. Ver [Verificar la firma](#verificar-la-firma) |
    | **Payload Personalizado (opcional)** | El JSON exacto que quieres mandar. Si lo dejas vacío, se manda el [cuerpo por defecto](#el-cuerpo-por-defecto) |
  </Step>

  <Step title="Prueba la conexión">
    En **Probar Webhook**, haz clic en **Test**. Asistian manda un envío de
    prueba a tu URL, con la misma firma y el mismo cuerpo que un envío real, y
    te muestra el código HTTP que respondió tu sistema y su respuesta.

    Tres diferencias con un envío real: las variables (`{{…}}`) viajan **sin
    reemplazar**, porque todavía no hay un evento del que sacar los datos; sin
    payload personalizado, `data` trae datos de ejemplo en lugar del evento; y
    la prueba espera la respuesta **10 segundos** (el envío real, 30).
  </Step>

  <Step title="Guarda y activa">
    Guarda la automatización y revisa que esté **activa**. Desde ese momento,
    cada vez que ocurra el evento se manda el webhook.
  </Step>
</Steps>

## Qué recibe tu sistema

### Encabezados

| Encabezado | Valor |
| - | - |
| `Content-Type` | `application/json` |
| `User-Agent` | `Asistian-Webhook/1.0` |
| `X-Webhook-Event` | El **Nombre del Evento** que pusiste, o `automation_triggered` |
| `X-Webhook-Signature` | `sha256=<firma>`. Solo si configuraste un **Secreto** |

### El cuerpo por defecto

Si no escribes un payload personalizado, Asistian manda el evento completo:

```json theme={null}
{
  "event": "contacto_calificado",
  "timestamp": "2026-10-14T18:22:05.000000Z",
  "data": {
    "event_type": "lead_stage_changed",
    "conversation": { "id": 7788, "…": "…" },
    "contact": { "id": 300, "name": "Ana López", "email": "ana@ejemplo.com", "phone": "+525512345678", "…": "…" },
    "agent": { "id": 8, "name": "Luis", "email": "luis@ejemplo.com", "…": "…" },
    "stage": { "id": 12, "name": "Calificado", "…": "…" },
    "channel_type": { "…": "…" },
    "trigger": { "id": 55, "name": "Avisar al ERP", "…": "…" }
  }
}
```

* `event` es el **Nombre del Evento** y `timestamp`, la hora del envío.
* `data` trae la conversación, el contacto, el agente, la etapa y el canal, más
  el objeto propio del evento cuando aplica: `booking` en reservas, `sale` en
  ventas, `deal` en oportunidades, `ticket` en tableros. Lo que trae cada
  evento está en la columna **Datos que trae** de la
  [lista de eventos](/mintlify/automatizaciones/eventos).
* Los mismos datos también llegan con su nombre anterior (`lead`, `client`,
  `source`, `sender`) para no romper integraciones viejas. Usa los nuevos.

<Tip>
  El cuerpo por defecto es grande y trae datos que tu sistema probablemente no
  necesita. Para una integración en producción, usa un **payload
  personalizado** con solo los campos que vas a leer: es más fácil de
  mantener y no comparte datos de más.
</Tip>

### Payload personalizado

Escribe el JSON que quieres recibir y usa `{{variable}}` donde va un dato:

```json theme={null}
{
  "tipo": "contacto_calificado",
  "conversacion_id": "{{lead.id}}",
  "nombre": "{{client.full_name}}",
  "correo": "{{client.email}}",
  "telefono": "{{client.phone}}",
  "etapa": "{{stage.name}}",
  "agente": "{{agent.name}}"
}
```

El JSON que escribes **es** el cuerpo que se envía, tal cual: no se envuelve en
`event`, `timestamp` y `data`. Si los necesitas, agrégalos tú
(`"evento": "{{event_type}}"`, `"fecha": "{{timestamp}}"`).

Variables más usadas:

| Variable | Qué trae |
| - | - |
| `{{lead.id}}` | ID de la conversación |
| `{{client.name}}`, `{{client.full_name}}` | Nombre del contacto |
| `{{client.email}}`, `{{client.phone}}` | Correo y teléfono del contacto |
| `{{client.cf_<clave>}}` | Un [campo personalizado](/mintlify/bandeja/contactos#campos-personalizados) del contacto, por su **Clave del Campo** (por ejemplo `{{client.cf_presupuesto}}`) |
| `{{lead.cf_<clave>}}` | Un campo personalizado de la conversación |
| `{{agent.name}}`, `{{agent.email}}` | Agente asignado |
| `{{stage.name}}` | Etapa actual |
| `{{event_type}}`, `{{timestamp}}` | Qué evento disparó la automatización y cuándo |
| `{{trigger.name}}` | Nombre de la automatización |
| `{{booking.…}}`, `{{sale.…}}`, `{{deal.…}}`, `{{ticket.…}}` | Datos de la reserva, venta, oportunidad o ítem, en los eventos de esos módulos |

Cada evento trae además sus propios datos (la etapa anterior en un cambio de
etapa, el formulario en **Formulario contestado**, el horario anterior en una
reserva reprogramada…). Están en la
[lista de eventos](/mintlify/automatizaciones/eventos).

Cómo se reemplazan:

* Las variables funcionan **en los valores**, no en los nombres de los campos.
* El resultado siempre es **texto**: `"{{lead.id}}"` llega como `"7788"`, no
  como número.
* Si la variable no existe para ese evento (por ejemplo, `{{booking.id}}` en
  un evento de conversación), llega **tal cual**, con las llaves. Si ves
  `{{…}}` en lo que recibes, esa es la causa.

<Note>
  Si el JSON tiene un error (una coma de más, una comilla o una llave
  faltante), el editor lo marca en rojo y no te deja probar ni guardar hasta
  que lo corrijas.
</Note>

## Verificar la firma

Si configuraste un **Secreto**, cada envío trae el encabezado
`X-Webhook-Signature` con el formato `sha256=<firma>`. La firma es un
HMAC-SHA256 del **cuerpo crudo** de la petición, usando tu secreto como llave,
en hexadecimal. Tu sistema la calcula igual y compara:

<CodeGroup>
  ```js Node.js theme={null}
  import { createHmac, timingSafeEqual } from 'node:crypto';

  // rawBody: el cuerpo tal como llegó (Buffer o string), ANTES de JSON.parse
  function firmaValida(rawBody, header, secreto) {
    const esperada = 'sha256=' + createHmac('sha256', secreto).update(rawBody).digest('hex');
    const recibida = header ?? '';
    return recibida.length === esperada.length
      && timingSafeEqual(Buffer.from(recibida), Buffer.from(esperada));
  }
  ```

  ```php PHP theme={null}
  $cuerpo = file_get_contents('php://input'); // cuerpo crudo
  $recibida = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
  $esperada = 'sha256=' . hash_hmac('sha256', $cuerpo, $secreto);

  if (! hash_equals($esperada, $recibida)) {
      http_response_code(401);
      exit;
  }
  ```
</CodeGroup>

<Warning>
  Calcula la firma sobre el cuerpo **tal como llegó**. Si primero lo conviertes
  a objeto y luego otra vez a texto, el orden o los espacios cambian y la firma
  ya no coincide.
</Warning>

## Si tu sistema falla

* Asistian espera la respuesta hasta **30 segundos**.
* Cualquier respuesta `2xx` cuenta como entregado. Cualquier otro código, un
  error de red o pasarse del tiempo cuenta como **fallo**.
* **Un envío fallido no se reintenta.** Si tu servidor estaba caído en ese
  momento, ese aviso se pierde: diseña tu integración para poder ponerse al
  día (por ejemplo, con una revisión periódica).
* Responde `200` en cuanto recibas el envío y procesa después, en segundo
  plano. Un sistema que tarda más de 30 segundos se ve como caído aunque al
  final termine bien.

Cuando un envío falla, la ejecución queda marcada con error en el
**Historial** de la automatización y te avisamos en la campanita (como máximo
un aviso por automatización cada 24 horas). En **Configuración →
Automatizaciones → Avisos de fallo** puedes activar **Enviarme también un
correo**.

<Note>
  La URL tiene que ser pública. Asistian no envía a `localhost`, a direcciones
  de red privada ni a URLs con usuario y contraseña escritos dentro
  (`https://usuario:clave@…`).
</Note>

## Ver lo que se envió

* **Historial** de la automatización (en su tarjeta, en **Configuración →
  Automatizaciones**): cada ejecución, si salió bien y, si falló, el motivo
  (por ejemplo, `HTTP 404`).
* **Configuración → Integraciones → Webhooks → Gestionar**, pestaña
  **Registros de Ejecución**: los últimos envíos y recepciones de webhooks de
  tu cuenta, con su estado y tiempo de respuesta.

## Que tu asistente de IA lo dispare

Además de un evento, tu asistente de IA puede ejecutar la automatización en
medio de una conversación, por ejemplo para mandar los datos del cliente a tu
sistema cuando confirma un pedido.

<Steps>
  <Step title="Crea la automatización con la acción Enviar Webhook">
    Igual que arriba. Déjala **activa**.
  </Step>

  <Step title="Dale la habilidad al asistente">
    En la configuración del asistente, activa la habilidad avanzada
    **Ejecutar Automatización** y elige esa automatización.
  </Step>

  <Step title="Dile cuándo usarla">
    En sus instrucciones, describe el momento: *"Cuando el cliente confirme su
    pedido, ejecuta la automatización para enviarlo al sistema de pedidos"*.
  </Step>
</Steps>

Cuando el asistente la ejecuta, la automatización corre sobre **la
conversación en la que está**: las variables (`{{client.email}}`,
`{{lead.id}}`…) toman los datos de esa conversación. Las condiciones del
evento no se revisan en ese caso: el asistente decide cuándo, según sus
instrucciones. Cada ejecución queda en el **Historial** de la automatización.

## Preguntas frecuentes

<AccordionGroup>
  <Accordion title="¿Funciona con Zapier, Make o n8n?">
    Sí. En tu herramienta, crea un flujo cuyo disparador sea un **webhook**
    (en Zapier, *Webhooks by Zapier → Catch Hook*), copia la URL que te da y
    pégala en **URL del Webhook**.
  </Accordion>

  <Accordion title="Mi sistema pide un token en un encabezado (Authorization)">
    La acción no tiene campo para encabezados propios. Usa el **Secreto** y
    valida la firma, o pide a tu sistema una URL que ya incluya su token (por
    ejemplo, `https://api.tusistema.com/hooks/asistian?token=…`).
  </Accordion>

  <Accordion title="¿Puedo mandar el mismo evento a dos sistemas?">
    Sí: agrega dos acciones **Enviar Webhook** en la misma automatización, una
    por URL. Cada una se envía y se registra por separado.
  </Accordion>

  <Accordion title="Recibo el texto {{client.email}} en lugar del correo">
    La variable no existe para ese evento, o está mal escrita. Revisa la tabla
    de variables y el evento que elegiste.
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.