> For the complete documentation index, see [llms.txt](https://boundaryai.gitbook.io/boundaryai-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://boundaryai.gitbook.io/boundaryai-docs/boundaryai-docs-es/api-y-webhooks/webhooks.md).

# Webhooks

Suscríbase a eventos, verifique firmas y gestione reintentos.

Los webhooks envían eventos a tus sistemas en el momento en que ocurren, así que nunca haces sondeos. Las suscripciones se gestionan en el panel bajo **Integraciones → Herramientas de desarrollo → Webhooks** (solo administradores): configura una URL de destino, elige los eventos y obtienes un HMAC **secreto de firma**, se muestra una sola vez (gíralo en cualquier momento con *Regenerar secreto*). Una organización puede tener hasta 10 suscripciones, y cada una puede pausarse y reanudarse desde la misma pantalla.

Las URL de destino deben ser **HTTPS**, y las entregas se firman para que puedas demostrar que provienen de BAI Analytics. Usa *Probar webhook* en una suscripción para recibir una entrega firmada con `"event": "test"` antes de conectar eventos reales.

***

### Los eventos

| Evento               | Se activa cuando                                                                                                                                                                                                                                                                             |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `content.pushed`     | Una inserción mediante API dejó elementos en una fuente.                                                                                                                                                                                                                                     |
| `series.created`     | Se creó un grupo de feedback a través de la API.                                                                                                                                                                                                                                             |
| `survey.created`     | Se creó una fuente a través de la API.                                                                                                                                                                                                                                                       |
| `survey.published`   | Se publicó una fuente y puede recibir contenido.                                                                                                                                                                                                                                             |
| `analysis.completed` | Una pasada de análisis finalizó; los resultados se pueden leer a través del endpoint de análisis.                                                                                                                                                                                            |
| `flag.raised`        | Un monitor de Custom Monitoring superó su umbral de alerta. Se activa bajo la misma condición que las alertas de monitor por correo/SMS, por lo que necesita una configuración de notificaciones del monitor habilitada con la función de alertas; una suscripción por sí sola no lo activa. |
| `report.ready`       | Una suscripción de informe de cierre de período generó su informe.                                                                                                                                                                                                                           |
| `invites.completed`  | Una distribución de invitaciones activada por la API finalizó, con los conteos finales.                                                                                                                                                                                                      |
| `invite.bounced`     | Una invitación enviada por la API rebotó o generó una queja de spam.                                                                                                                                                                                                                         |

Los nombres de los eventos usan el vocabulario clásico de la API (`series` = grupo de feedback, `survey` = fuente, `flag` = monitor); son contratos de interfaz y se mantienen estables. `GET /me` enumera los eventos a los que la organización de tu clave puede suscribirse. Los esquemas completos de carga útil y un ejemplo de cada evento están en la sección **Webhooks** de la referencia de la API.

***

### Cómo se ve una entrega

```
POST <your URL>
Content-Type: application/json
X-Boundary-Event: analysis.completed
X-Boundary-Signature: sha256=8f2ab0...
User-Agent: BoundaryAI-Webhook/1.0

{"event": "analysis.completed",
 "timestamp": "2026-07-12T09:45:12Z",
 "data": {"survey_series_id": 1842, "survey_id": 9021,
          "analysis_id": 55710, "survey_name": "Tickets de soporte (sincronización CRM)"}}
```

Cada entrega tiene el mismo sobre: `evento`, `timestamp` (ISO-8601 UTC), y un objeto por evento de `datos` objeto.

***

### Verificando la firma

`X-Boundary-Signature` es `sha256=` seguido por el HMAC-SHA256 hexadecimal del **cuerpo bruto de la solicitud**, usando como clave el secreto de tu suscripción. Calcúlalo sobre los bytes exactos que recibiste, antes de cualquier análisis JSON, y compáralo en tiempo constante.

{% tabs %}
{% tab title="Python" %}

```python
import hashlib, hmac

def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), raw_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
const crypto = require("crypto");

function verify(rawBody, signatureHeader, secret) {
  const expected = "sha256=" +
    crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected), Buffer.from(signatureHeader));
}
```

{% endtab %}
{% endtabs %}

Rechaza cualquier cosa que no verifique. Si giras el secreto, las entregas se firman con el nuevo inmediatamente.

***

### Semántica de entrega

* **Responde con 2xx en 30 segundos.** Reconoce primero, procesa después; haz el trabajo pesado fuera del flujo de la solicitud.
* **No se siguen las redirecciones.** Una respuesta 3xx cuenta como una entrega fallida, así que apunta la suscripción a la URL final.
* **Reintentos**: una respuesta que no sea 2xx o un tiempo de espera agotado se reintenta después de aproximadamente 1 minuto y de nuevo después de aproximadamente 5 minutos, para un total de 3 intentos. Cada intento fallido incrementa el contador de fallos de la suscripción, que puedes ver en el panel; una entrega exitosa lo restablece.
* **Pausa automática**: después de 10 fallos consecutivos la suscripción se desactiva y deja de recibir eventos hasta que la vuelvas a habilitar en el panel. Primero arregla el endpoint, luego *Habilitar webhook*.
* **Diseña para al menos una vez.** Trata las entregas como idempotentes: la `datos` carga útil más tu propio estado debe hacer que la reentrega sea inofensiva.
* **No se garantiza el orden** entre eventos; usa el `timestamp` y tus propios IDs en lugar del orden de llegada.

{% hint style="success" %}
La combinación más útil: enviar con `POST /feedback/push`, luego actuar sobre `analysis.completed` en lugar de hacer sondeos al endpoint de análisis. Tu integración se mantiene dirigida por eventos de extremo a extremo.
{% endhint %}
