---
title: "Endpoints de webhook"
description: "Gestiona varias URL de webhook con secretos por endpoint y filtros de eventos."
---

El sistema de webhooks basado en endpoints te permite registrar **múltiples**
destinos por organización, cada uno con su propio secreto, su propio
estado y su propia suscripción a un subconjunto de tipos de eventos. Este es
el modelo recomendado para todas las integraciones nuevas.

Compáralo con el [webhook heredado de URL única](/api-reference/organizations#legacy-single-url-webhook),
que se mantiene por compatibilidad con versiones anteriores, pero solo admite una URL por
organización.

## Endpoints

| Método | Ruta | Rol obligatorio | Descripción |
|--------|------|---------------|-------------|
| `GET` | `/v1/developer/webhook-endpoints` | `admin+` | Listar endpoints |
| `POST` | `/v1/developer/webhook-endpoints` | `admin+` | Crear un endpoint |
| `PATCH` | `/v1/developer/webhook-endpoints/{endpoint_id}` | `admin+` | Actualizar etiqueta / URL / eventos / estado |
| `DELETE` | `/v1/developer/webhook-endpoints/{endpoint_id}` | `admin+` | Eliminar un endpoint |
| `POST` | `/v1/developer/webhook-endpoints/{endpoint_id}/rotate-secret` | `admin+` | Reemplazar el secreto de firma |
| `POST` | `/v1/developer/webhook-endpoints/{endpoint_id}/test` | `admin+` | Enviar una entrega de prueba firmada |
| `GET` | `/v1/developer/webhook-deliveries` | `admin+` | Inspeccionar resultados recientes de entregas de endpoints y heredadas |

## Objeto de endpoint

```json
{
  "id": "c4d5e6f7-...",
  "label": "Production — Call events",
  "url": "https://example.com/thunderphone/hook",
  "events": ["telephony.incoming", "telephony.complete"],
  "status": "active",
  "agent_id": 42,
  "agent_name": "Support Agent",
  "secret_hint": "a1b2…9f0e",
  "paused_at": null,
  "pause_last_error": "",
  "pause_undelivered_count": null,
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z"
}
```

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `id` | UUID | ID del punto de conexión |
| `label` | cadena | Nombre visible, de 1 a 120 caracteres |
| `url` | cadena | URL HTTPS; se permite `http://localhost` para desarrollo |
| `events` | matriz de cadenas | Tipos de eventos suscritos (consulta los [valores válidos](#valid-event-types)). Una matriz vacía se suscribe a todos los eventos, excepto a los eventos explícitos por turno (`telephony.turn` / `web.turn`) |
| `status` | cadena | `active`, `disabled` (pausado manualmente) o `failing` (se establece automáticamente cuando una entrega agota su programación de reintentos de 24 h sin un solo 2xx) |
| `agent_id` | entero \| null | Agente al que se limita este punto de conexión; `null` significa para toda la organización |
| `agent_name` | cadena \| null | Nombre del agente limitado, o `null` para un punto de conexión de toda la organización |
| `secret_hint` | cadena | Los primeros 4 y últimos 4 caracteres del secreto de firma con puntos suspensivos (`a1b2…9f0e`); es suficiente para comparar el secreto que guardaste localmente sin exponer el valor completo |
| `paused_at` | marca de tiempo \| null | Cuándo ThunderPhone estableció el punto de conexión en `failing`. `null` mientras está `active` o `disabled` |
| `pause_last_error` | cadena | El último error de entrega cuando se pausó el punto de conexión, por ejemplo `HTTP 503: Service Unavailable`. Vacío salvo que esté en `failing` |
| `pause_undelivered_count` | entero \| null | Eventos no entregados desde la última entrega exitosa del punto de conexión, contados cuando se pausó |
| `created_at`, `updated_at` | marca de tiempo | |

<Note>
  El `secret` completo del endpoint se devuelve **una sola vez** al crearlo y
  nunca más. Guárdalo de forma segura; si lo pierdes,
  [rótalo](#rotate-the-signing-secret) para obtener uno nuevo.
</Note>

### Tipos de eventos válidos

`events` se valida con respecto a este conjunto exacto: los valores fuera de la lista
devuelven `400`. Consulta el [catálogo de eventos](/es/webhooks/events) para ver la
estructura de la carga útil de cada tipo.

- `telephony.incoming`, `telephony.complete`, `telephony.tool`, `telephony.turn`
- `web.incoming`, `web.complete`, `web.tool`, `web.turn`
- `sms.sent`, `sms.failed`
- `sms.received` (reservado; aún no se emite)
- `call.graded`, `call.data_extracted`, `call.transfer_completed`
- `campaign.completed`
- `issue.reported`, `issue.escalated`
- `test-call.completed`
- `alert.triggered`

`issue.escalated` no tiene contexto de agente y se entrega únicamente a
endpoints de toda la organización.

`voice.ready` y `voice.failed` no se pueden seleccionar explícitamente. Para recibirlos,
crea un endpoint de toda la organización con `events: []`. Una lista de eventos vacía
recibe todos los eventos compatibles excepto `telephony.turn` y `web.turn`,
que se deben seleccionar explícitamente.

### Estados de los endpoints

- `active` — las entregas fluyen normalmente.
- `disabled` — pausado manualmente mediante `PATCH`. No se envían solicitudes. Nunca
  cambiamos el estado de un endpoint `disabled`; volver a cambiarlo a
  `active` siempre depende de ti.
- `failing` — se establece automáticamente cuando una entrega al endpoint agota
  todo su programa de reintentos (8 intentos durante 24 horas) sin
  recibir nunca un 2xx. Un endpoint con errores no recibe más tráfico.
  Enviamos un correo electrónico a los propietarios y administradores de tu organización cuando esto sucede, y
  el panel muestra el endpoint pausado con un botón **Reactivar**.
  Una vez que el endpoint se corrija, cambia su estado mediante `PATCH` de nuevo a `active`;
  las entregas cuyo programa de reintentos aún no haya terminado se reanudarán donde
  se quedaron.

---

## Listar endpoints

<CodeGroup>
```bash cURL
curl https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Devuelve un arreglo de [objetos de endpoint](#endpoint-object).
Pasa `?agent_id=42` para devolver solo los endpoints asociados a ese agente.

### Endpoints asociados a un agente

Los endpoints de toda la organización reciben todos los eventos coincidentes. Un endpoint con
`agent_id` recibe solo los eventos coincidentes de las llamadas atendidas por ese agente;
los eventos sin contexto de agente, como `alert.triggered`, nunca llegan a él. También
puedes crear y administrar estos endpoints desde la sección
**Webhooks** del creador de agentes.

---

## Crea un endpoint

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Production — Call events",
    "url":    "https://example.com/thunderphone/hook",
    "events": ["telephony.incoming", "telephony.complete"]
  }'
```

```python Python
result = requests.post(
    "https://api.thunderphone.com/v1/developer/webhook-endpoints",
    headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
    json={
        "label":  "Production — Call events",
        "url":    "https://example.com/thunderphone/hook",
        "events": ["telephony.incoming", "telephony.complete"],
    },
).json()
secret = result["secret"]
endpoint_id = result["id"]
```
</CodeGroup>

### Campos de la solicitud

| Campo | Tipo | Obligatorio | Descripción |
|-------|------|----------|-------------|
| `label` | cadena | sí | 1–120 caracteres |
| `url` | cadena | sí | URL HTTPS (`http` permitido solo para `localhost` / `127.0.0.1`) |
| `events` | arreglo | no | Si está vacío o se omite, se suscribe a todos los eventos excepto `telephony.turn` / `web.turn`, que requieren una suscripción explícita. Debe usar los valores indicados en [Tipos de eventos válidos](#valid-event-types); se eliminan los duplicados |
| `agent_id` | entero \| nulo | no | Limita la entrega a un agente de esta organización; omite o usa `null` para un endpoint de toda la organización |

Devuelve `201 Created` con el [objeto Endpoint](#endpoint-object) más
un campo `secret` adicional de nivel superior que contiene la clave de firma sin procesar: una
cadena hexadecimal de 48 caracteres:

```json
{
  "id": "c4d5e6f7-…",
  "label": "Production — Call events",
  "url": "https://example.com/thunderphone/hook",
  "events": ["telephony.incoming", "telephony.complete"],
  "status": "active",
  "secret_hint": "a1b2…9f0e",
  "created_at": "2026-04-20T18:24:10.113Z",
  "updated_at": "2026-04-20T18:24:10.113Z",
  "secret": "a1b2c37e08d94f5b16a2c8d90e7f3a4b5c6d7e8f90a19f0e"
}
```

<Warning>
  `secret` se devuelve **solo al crear**. Las respuestas posteriores de `GET`
  incluyen únicamente `secret_hint`. Copia el valor completo en tu gestor de secretos
  antes de descartar la respuesta.
</Warning>

---

## Actualiza un endpoint

<CodeGroup>
```bash cURL
curl -X PATCH https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-... \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label":  "Production — Call + Grade events",
    "events": ["telephony.incoming", "telephony.complete", "call.graded"]
  }'
```
</CodeGroup>

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `label` | cadena | |
| `url` | cadena | |
| `events` | arreglo | |
| `status` | cadena | `active` o `disabled`. Establece `active` para volver a habilitar un endpoint que el servidor marcó como `failing` |
| `agent_id` | entero \| nulo | Establece un ID de agente para limitar el endpoint o `null` para que sea de toda la organización |

Devuelve `200 OK` con el [objeto Endpoint](#endpoint-object) actualizado.

---

## Rota el secreto de firma

Reemplaza el secreto de firma de un endpoint, por ejemplo, si se perdió o
podría haberse filtrado. Para un endpoint con alcance de agente, también puedes usar el
panel: abre la sección **Webhooks** del agente y selecciona
**Regenerar secreto** en el endpoint. Los endpoints de toda la
organización se rotan mediante la API.

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../rotate-secret \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```
</CodeGroup>

| Campo | Tipo | Obligatorio | Descripción |
|-------|------|----------|-------------|
| `include_copies` | booleano | no | El valor predeterminado es `true`. También proporciona el nuevo secreto a los demás endpoints de tu organización que tienen la misma URL y el mismo secreto actual, como las copias de este endpoint en otros agentes, para que un receptor siga verificando con un solo secreto |

Devuelve `200 OK`:

```json
{
  "endpoint": { "id": "c4d5e6f7-...", "secret_hint": "7f3a…c21d", "...": "..." },
  "secret": "7f3a90b2c4d5e6f708192a3b4c5d6e7f8091a2b3c4d5c21d",
  "rotated_endpoint_ids": ["c4d5e6f7-..."]
}
```

| Campo | Tipo | Descripción |
|-------|------|-------------|
| `endpoint` | objeto | El [objeto Endpoint](#endpoint-object) con su nuevo `secret_hint` |
| `secret` | cadena | El nuevo secreto de firma. Se devuelve solo en esta respuesta |
| `rotated_endpoint_ids` | arreglo de UUID | Cada endpoint que ahora usa el nuevo secreto |

<Warning>
  El secreto anterior deja de usarse de inmediato: la siguiente entrega,
  incluidos los reintentos, se firma con el nuevo. Hasta que tu receptor tenga
  el nuevo secreto, las entregas no superan su verificación de firma; si responde
  a esas entregas con un estado distinto de 2xx, se reintentan según el programa
  normal de 24 h, así que actualiza el receptor de inmediato. Si tu receptor se implementa
  por etapas, haz que acepte ambos secretos durante la implementación; las funciones auxiliares de
  verificación del SDK aceptan una lista de secretos (consulta
  [Verificar firmas de webhooks](/es/guides/verify-webhook-signatures)).
</Warning>

---

## Enviar una entrega de prueba

Envía un evento sintético `webhook.test` a un endpoint mediante el flujo de
entrega normal, incluida la serialización canónica de JSON, ambos
encabezados de firma, el registro de entregas y el seguimiento de reintentos.
La prueba se dirige al endpoint seleccionado independientemente de su filtro `events`.

<CodeGroup>
```bash cURL
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

El endpoint recibe un sobre como este:

```json
{
  "data": {
    "message": "ThunderPhone webhook test",
    "sent_at": "2026-07-17T20:12:34.567890+00:00"
  },
  "event_id": "2ad6507c-7d19-4498-9b2d-7e8f944ab5a1",
  "type": "webhook.test"
}
```

La API devuelve `200 OK` después del primer intento, incluso si el destino
devuelve un error. Revisa `success`, `status`, `response_code` y `error`
para conocer el resultado de la entrega:

```json
{
  "success": true,
  "event_id": "2ad6507c-7d19-4498-9b2d-7e8f944ab5a1",
  "event_type": "webhook.test",
  "status": "delivered",
  "response_code": 204,
  "error": ""
}
```

`webhook.test` es sintético y no se puede agregar a la suscripción de `events`
de un endpoint. Si el primer intento falla, ThunderPhone lo reintenta una vez aproximadamente
un minuto después y luego se detiene; la entrega muestra entonces `status: "failed"`
en [Depurar entregas](#debug-deliveries). Una entrega de prueba nunca marca
el endpoint como `failing`.

Para configurar un desencadenador con una estructura de evento real, pasa un
`event_type` opcional. La entrega sigue siendo sintética y contiene `"sample": true`;
las muestras relacionadas con llamadas usan `call_id: 0` y `agent_id: 0`.

```bash
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-.../test \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event_type":"call.graded"}'
```

`event_type` acepta cualquier valor de [Tipos de evento válidos](#valid-event-types).
Omitirlo conserva el comportamiento genérico de `webhook.test`.

---

## Eliminar un endpoint

<CodeGroup>
```bash cURL
curl -X DELETE https://api.thunderphone.com/v1/developer/webhook-endpoints/c4d5e6f7-... \
  -H "Authorization: Bearer sk_live_YOUR_API_KEY"
```
</CodeGroup>

Devuelve `204 No Content`. La entrega a la URL se detiene de inmediato;
se abandonan los reintentos en curso.

---

## Depurar entregas

Antes de concluir que no se envió un webhook, revisa
[`GET /v1/developer/webhook-deliveries`](/api-reference/webhook-deliveries).
Muestra intentos recientes de ambos sistemas de webhooks, incluido el id de llamada,
el origen de la URL, el estado HTTP, el número de intentos, la categoría de error permitida y la hora del próximo
reintento. Nunca devuelve la carga útil del evento, la transcripción, el texto de error almacenado,
el cuerpo de la respuesta ni la ruta de la URL.

También puedes ver el mismo historial reciente en **Agentes → selecciona un agente → Webhooks →
Entregas recientes**. Las filas muestran la etiqueta del endpoint y el origen de la URL usado por el último
intento. Este es un estado operativo, no un registro de auditoría inmutable: eliminar un endpoint
también elimina sus filas de entrega.

Para un `404` de n8n, primero confirma que el flujo de trabajo esté activo, acepte `POST` y use
la URL de webhook de producción en lugar de la URL de prueba. Un `401` o `403` indica un problema de
autenticación o validación de firma; los tiempos de espera indican latencia
o disponibilidad del destino; los errores de TLS indican un problema con la cadena de certificados, el nombre de host o el vencimiento.

---

## Relacionado

<CardGroup cols={2}>
  <Card title="Catálogo de eventos" icon="list" href="/es/webhooks/events">
    La lista completa de valores de `events` a los que puedes suscribirte.
  </Card>
  <Card title="Descripción general de webhooks" icon="bolt" href="/es/webhooks/overview">
    Verificación de firmas y semántica de entrega.
  </Card>
</CardGroup>
