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

# Entregas y reintentos

> Cómo entrega Ciarem los eventos, qué pasa cuando tu servidor falla, cómo leer el registro de entregas y cómo enviar un evento de nuevo.

Una **entrega** es un evento dirigido a un endpoint. Si tres de tus endpoints están suscritos a `contact.created`, un contacto nuevo produce tres entregas, y cada una se sigue y se reintenta por separado.

## Qué cuenta como entregado

Ciarem envía el evento en el momento en que ocurre, normalmente en unos segundos, y espera hasta **10 segundos** a que tu servidor responda.

| Tu servidor | Resultado |
| - | - |
| Responde con cualquier estado `2xx` | **Entregado.** Ciarem no lee el cuerpo de la respuesta. |
| Responde con `3xx`, `4xx` o `5xx` | **Fallido.** Las redirecciones no se siguen. |
| Tarda más de 10 segundos | **Fallido.** |
| Rechaza la conexión, tiene un certificado TLS inválido o no se puede resolver | **Fallido.** |

Una entrega fallida se reintenta automáticamente.

## Reintentos

Después de un fallo, Ciarem espera y vuelve a intentar, con una espera más larga cada vez:

| Intento | Espera después del fallo anterior |
| - | - |
| 2.º | 1 minuto |
| 3.º | 5 minutos |
| 4.º | 30 minutos |
| 5.º | 2 horas |
| 6.º y siguientes | 8 horas cada uno |

Los reintentos continúan hasta que la entrega tiene **3 días**. Después de eso Ciarem la abandona y la marca como **Fallido**. En la práctica son unos 14 intentos. Los reintentos se ejecutan una vez por minuto, así que un intento puede empezar hasta un minuto después de su hora programada.

Cada intento envía el **mismo cuerpo** con el **mismo `id` de evento**. Solo cambia el encabezado `Ciarem-Signature`, porque cada intento se firma con una marca de tiempo nueva.

## Estados de entrega

| En el panel | En la API | Significado |
| - | - | - |
| **Pendiente** | `pending` | En cola, sin intentar todavía, o en cola para enviarse de nuevo. |
| **Entregado** | `succeeded` | Tu servidor respondió `2xx`. |
| **Reintentando** | `failed` | El último intento falló. Hay otro programado para `next_attempt_at`. |
| **Fallido** | `exhausted` | Ciarem dejó de intentar: la entrega pasó los 3 días, o su endpoint se desactivó. |

## Cuando un endpoint sigue fallando

Si **todas** las entregas a un endpoint fallan durante **3 días seguidos**, Ciarem apaga el endpoint. En el panel muestra **Desactivado por fallos repetidos**; en la API, `enabled` es `false` y `disabled_reason` es `auto_failures`.

Una sola entrega exitosa reinicia la cuenta, así que un endpoint con fallos ocasionales nunca se desactiva.

Mientras un endpoint está desactivado:

* No se le envía nada, y los eventos que ocurren mientras tanto **no** se guardan para después.
* Las entregas que esperaban un reintento se marcan como **Fallido**.

Para volver a encenderlo, arregla tu servidor y luego elige **Activar** en el menú del endpoint, o envía `PATCH /v1/webhook-endpoints/{id}` con `{"enabled": true}`. Las entregas se reanudan con los eventos nuevos a partir de ese momento. Para recuperar lo que te perdiste, consulta [Recuperar eventos perdidos](#recuperar-eventos-perdidos).

## Pausar un endpoint por tu cuenta

Elige **Desactivar** en el menú del endpoint, o envía `{"enabled": false}`, para detener las entregas sin eliminar el endpoint. Se comporta igual que el caso automático: no se envía nada mientras está apagado, los reintentos en espera se descartan, y activarlo más tarde no reenvía los eventos antiguos. `disabled_reason` es `user`.

Eliminar un endpoint también elimina su registro de entregas.

## Si tu plan cambia

Los webhooks son parte del acceso a la API. Si tu organización pasa a un plan que no lo incluye, o una prueba termina sin una suscripción, Ciarem deja de enviar eventos de inmediato. Tus endpoints se conservan, y las entregas se reanudan solas cuando vuelves a Growth o Scale. Los eventos que ocurrieron en ese intervalo no se envían después.

## Duplicados y orden

Construye tu handler en torno a dos hechos:

**El mismo evento puede llegar más de una vez.** Ciarem garantiza que cada evento se entrega *al menos una vez*, no exactamente una vez. La causa habitual es un reintento después de que tu servidor procesó el evento pero respondió demasiado lento. Haz que procesar un evento sea seguro de repetir:

* Guarda el `id` de cada evento que procesas y sáltate cualquier `id` que ya hayas visto. Conservar los ids unos días es suficiente, porque los reintentos terminan a los 3 días.
* O haz que la acción misma sea repetible, por ejemplo "pon la etapa del contacto en X" en vez de "avanza el contacto una etapa".

**Los eventos pueden llegar fuera de orden.** Un evento reintentado llega después de otros más nuevos, y dos eventos con segundos de diferencia pueden intercambiar su lugar. No asumas que el último evento que recibiste es el estado más reciente:

* Compara `created_at` del sobre, o `updated_at` del contacto, con lo que ya tienes guardado, e ignora los datos más antiguos.
* En las conversaciones, espera que `messages.inbound` pueda llegar antes que el `conversation.created` de la misma conversación.
* Cuando el orden importa, trata el evento como una señal y lee el estado actual desde la [API](https://help.ciarem.ai/es/api-reference/overview).

## El registro de entregas

Cada entrega de los últimos **30 días** queda registrada, con el cuerpo exacto que se envió.

**En el panel:** abre **Configuración → Webhooks** y haz clic en un endpoint. La tabla **Entregas** muestra cada evento, su estado, el código de respuesta de tu servidor y el número de intentos. Haz clic en una fila para ver el cuerpo que se envió, el id del evento, la respuesta de tu servidor o el error, y el último y el próximo intento.

**Con la API:**

```bash theme={null}
curl "https://api.ciarem.ai/v1/webhook-endpoints/whe_…/deliveries?status=failed&limit=50" \
  -H "Authorization: Bearer oak_TU_SECRETO"
```

```json theme={null}
{
  "items": [
    {
      "id": "whd_…",
      "endpoint_id": "whe_…",
      "event_id": "evt_…",
      "event_type": "contact.updated",
      "status": "failed",
      "attempt_count": 3,
      "next_attempt_at": "2026-10-09T15:40:05.123456Z",
      "last_attempt_at": "2026-10-09T15:10:05.123456Z",
      "response_status": 500,
      "error": "endpoint answered 500",
      "created_at": "2026-10-09T15:04:05.123456Z",
      "payload": { "id": "evt_…", "type": "contact.updated", "…": "…" }
    }
  ],
  "next_cursor": null
}
```

| Parámetro | |
| - | - |
| `status` | Opcional. Uno de `pending`, `succeeded`, `failed`, `exhausted`. |
| `limit` | Opcional. De 1 a 100, por defecto 20. |
| `cursor` | Opcional. El `next_cursor` de la página anterior. Los resultados van del más nuevo al más antiguo. |

`response_status` es `null` cuando tu servidor nunca respondió (un timeout o un error de conexión); en ese caso `error` dice qué salió mal.

Dos cosas **no** están en el registro: los eventos de prueba, y las entregas sobre un contacto que después se borró de forma permanente, que se eliminan junto con los datos del contacto.

## Enviar una entrega de nuevo

Puedes reenviar cualquier entrega del registro, sea cual sea su estado, por ejemplo después de corregir un error en tu handler.

* **En el panel:** haz clic en la entrega para abrirla y luego haz clic en **Enviar de nuevo**.
* **Con la API:** `POST /v1/webhook-deliveries/{delivery_id}/redeliver`.

La entrega vuelve a **Pendiente** y se envía **en menos de un minuto**, con el mismo cuerpo y el mismo `id` de evento. Como el `id` no cambia, un handler que deduplica la va a saltar: borra primero ese `id` de tu lado si quieres que se procese otra vez.

Enviar de nuevo se rechaza con `409 endpoint_disabled` mientras el endpoint está apagado. Actívalo primero.

## Recuperar eventos perdidos

Los reintentos cubren caídas de hasta 3 días. Para algo más largo, o para el tiempo en que un endpoint estuvo desactivado, reconcilia desde la API:

* **Contactos:** lístalos con `GET /v1/contacts` y compara `updated_at` con lo que tienes.
* **Conversaciones:** lístalas con `GET /v1/conversations` y lee los mensajes de las que cambiaron.

Una reconciliación periódica como esta es una buena práctica incluso cuando todo funciona. Te protege de errores de tu lado que los webhooks por sí solos no pueden revelar.

## Gestionar endpoints con la API

Todo lo que hay en el panel también está disponible para una clave de API. Los detalles completos de solicitudes y respuestas están en la [referencia de la API](https://help.ciarem.ai/es/api-reference/overview), en **Webhooks**.

| Solicitud | Qué hace |
| - | - |
| `GET /v1/webhook-endpoints` | Lista tus endpoints. |
| `POST /v1/webhook-endpoints` | Crea un endpoint y devuelve su secreto de firma. |
| `GET /v1/webhook-endpoints/{id}` | Lee un endpoint. |
| `PATCH /v1/webhook-endpoints/{id}` | Cambia `url`, `description`, `events` o `enabled`. Envía solo los campos que quieres cambiar. |
| `DELETE /v1/webhook-endpoints/{id}` | Elimina el endpoint y su registro de entregas. |
| `POST /v1/webhook-endpoints/{id}/test` | Envía un evento de prueba ahora y devuelve la respuesta de tu servidor. |
| `GET /v1/webhook-event-samples` | Devuelve el cuerpo de ejemplo de cada tipo de evento. |
| `GET /v1/webhook-endpoints/{id}/deliveries` | Lista las entregas de un endpoint. |
| `POST /v1/webhook-deliveries/{id}/redeliver` | Envía una entrega de nuevo. |

Errores específicos de los webhooks, además de los [generales](https://help.ciarem.ai/es/api-reference/errors-limits-pagination.md):

| Estado | `detail` | Significado |
| - | - | - |
| 422 | `{"code": "invalid_url", "message": "…"}` | La URL no es HTTPS, no tiene host, no resuelve o apunta a una dirección privada. `message` dice cuál. |
| 422 | `"endpoint_limit_reached"` | La organización ya tiene 10 endpoints. Elimina uno primero. |
| 422 | mensajes por campo | Por ejemplo un tipo de evento desconocido, o `*` mezclado con otros tipos. |
| 404 | `"not_found"` | No hay ningún endpoint ni entrega con ese id en tu organización. |
| 409 | `"endpoint_disabled"` | Intentaste enviar una entrega de nuevo mientras su endpoint está apagado. |

Estas llamadas cuentan para tu [límite de uso](https://help.ciarem.ai/es/api-reference/errors-limits-pagination.md#límites-de-uso) como cualquier otra solicitud a la API. Los eventos que Ciarem **te envía** no cuentan.

## Solución de problemas

| Problema | Qué revisar |
| - | - |
| **No llega ningún evento** | ¿El endpoint está activado? ¿Está suscrito al evento que esperas? Envía un evento de prueba: su resultado muestra exactamente qué respondió tu servidor. Revisa que tu plan incluya webhooks. |
| **La prueba funciona pero los eventos reales no** | Probablemente el endpoint no está suscrito a ese tipo de evento. Ábrelo y revisa **Eventos a enviar**. |
| **"Esta URL no se puede usar"** | La URL debe ser `https://` y resolver a una dirección pública. Los nombres de host internos y `localhost` se rechazan. Usa un túnel para el desarrollo local. |
| **Las entregas fallan con un `301` o `302`** | Tu servidor redirige, a menudo de una URL sin barra final a una con ella, o de un dominio sin `www` a `www`. Registra la URL final. |
| **Las entregas fallan con `401` o `403`** | Algo delante de tu servidor (un firewall, una protección contra bots o una pantalla de inicio de sesión) bloquea la solicitud. Permite las solicitudes `POST` a esa ruta. Puedes reconocer a Ciarem por el user agent `Ciarem-Webhooks/1.0`, pero para la seguridad confía en la [firma](https://help.ciarem.ai/es/webhooks/signatures.md), no en el user agent. |
| **Las entregas fallan con un timeout** | Tu handler tarda más de 10 segundos. Responde `200` primero y haz el trabajo en segundo plano. |
| **Las entregas fallan con un error de TLS o de certificado** | Tu certificado está vencido, es autofirmado o fue emitido para otro nombre de host. |
| **La firma no coincide** | Consulta [Si la firma no coincide](https://help.ciarem.ai/es/webhooks/signatures.md#si-la-firma-no-coincide). |
| **El mismo evento llega dos veces** | Es de esperar de vez en cuando. Deduplica por el `id` del evento. Si pasa con todos los eventos, revisa si dos endpoints apuntan a la misma URL. |
| **`contact.updated` llega varias veces por una sola edición** | Cada propiedad personalizada que cambia envía su propio evento, y los cambios de etapa y de propietario envían los suyos. Consulta el [catálogo de eventos](https://help.ciarem.ai/es/webhooks/events.md). |
| **Un endpoint muestra "Desactivado por fallos repetidos"** | Falló todas las entregas durante 3 días. Corrige la causa y luego elige **Activar**. |
| **Falta una entrega en el registro** | El registro conserva 30 días. Los eventos de prueba nunca se registran. |


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