API webchat REST¶
Endpoint síncrono del inbound-router para enviar mensajes desde un cliente HTTP (no necesariamente el widget). Útil para tests, integraciones custom o backends server-to-server.
Decisión y justificación en ADR-0013 (Webchat sync handler).
Base URL¶
POST /v1/webchat/messages¶
Headers¶
| Header | Requerido | Descripción |
|---|---|---|
Content-Type |
sí | application/json |
x-tenant-id |
sí | ID del tenant. |
x-widget-id |
sí | ID del widget. |
x-session-id |
sí | UUID estable por sesión del usuario. |
x-idempotency-key |
recomendado | UUID por mensaje. Si se repite en 24h, se devuelve la respuesta original. |
x-correlation-id |
opcional | Propagado a logs/tracing. Si no se envía, se genera uno. |
Request body¶
{
"text": "Quiero saber sobre mis cursos",
"attachments": [],
"user": {
"id": "user-42",
"firstName": "Cristian",
"email": "cristian@example.com"
},
"metadata": {
"page": "/dashboard"
}
}
Response 200¶
{
"messageId": "01HZ8K0V5...",
"conversationId": "conv-7e29...",
"replies": [
{
"id": "01HZ8K0VG...",
"text": "¡Hola! Estos son tus cursos activos:",
"author": "bot",
"timestamp": "2026-05-18T14:23:01.234Z"
},
{
"id": "01HZ8K0VH...",
"text": "1) Cálculo I\n2) Algoritmos\n3) Bases de datos",
"author": "bot"
}
],
"flow": {
"id": "flow-bienvenida",
"version": 3,
"stepId": "list-cursos"
},
"handoff": null
}
Códigos de estado¶
| Código | Significado |
|---|---|
200 |
Mensaje procesado, respuesta del flow incluida. |
202 |
Aceptado pero la respuesta del flow tarda (>3s); usa long-poll en /v1/webchat/conversations/{id}/messages?after=.... |
400 |
Body inválido (faltan campos, JSON malformado). |
401 |
Falta header de tenant o firma inválida. |
403 |
Origen no en allowed_origins del widget. |
404 |
Tenant o widget no existe. |
409 |
Idempotency key duplicada con body distinto. |
429 |
Rate limit excedido (por sesión o por widget). |
5xx |
Error de plataforma. Reintentar con backoff exponencial. |
Idempotency¶
Repetir un POST con el mismo x-idempotency-key dentro de 24 horas
devuelve la respuesta original (200 cacheado en DDB zen-dev-dedup).
Cualquier diferencia en el body con la misma key produce 409.
Long polling¶
Para mensajes asincrónicos posteriores (ej. bot demora, agente humano escribiendo):
Devuelve hasta 50 mensajes nuevos, o queda colgado hasta 25s esperando.
Rate limits¶
- 30 req/min por
x-session-id(configurable por widget). - 600 req/min agregado por
x-tenant-id.
Excederlos devuelve 429 con header Retry-After.