Saltar al contenido principal

Webhook

El canal webhook convierte a Korvun en un endpoint HTTP: cualquier cosa que sepa hacer POST de JSON — el backend de un formulario, un CRM, un hub IoT, otro servicio tuyo — envía un mensaje, Korvun lo enruta por un cerebro y publica la respuesta en la URL que elijas. Sin cuenta de proveedor, sin SDK — solo HTTP.

A diferencia de Telegram (polling) o Discord (Gateway), este canal escucha en un socket tuyo: solo-loopback por defecto, y autenticado en cada petición con un secreto compartido que generas tú.

Paso 1 — Configura el canal

El canal webhook no lleva mode. token_env nombra la variable con el secreto de entrada; outbound_url es adonde se envían las respuestas:

{
"channels": [
{
"type": "webhook",
"token_env": "KORVUN_WEBHOOK_SECRET",
"webhook": {
"bind": "127.0.0.1:8090",
"path": "/webhook",
"outbound_url": "http://127.0.0.1:9099/replies"
}
}
],
"routes": [
{ "channel": "webhook", "brain": "assistant" }
]
}

bind tiene por defecto 127.0.0.1:8090 y path /webhook — arriba se muestran explícitos.

Paso 2 — Genera el secreto y expórtalo

export KORVUN_WEBHOOK_SECRET=$(openssl rand -hex 32)
korvun config check --preflight korvun.local.json # confirms it resolves

El secreto es un secreto. Vive en el entorno, nunca en el fichero de configuración, un commit o un chat — la configuración solo guarda el nombre de la variable. Si se filtra, genera uno nuevo y reexporta.

Paso 3 — Arranca y envía un mensaje

korvun serve --config korvun.local.json
curl -s http://127.0.0.1:8090/healthz # liveness, no auth needed -> 200

Cada petición de entrada necesita el secreto Bearer y el content type JSON:

curl -i http://127.0.0.1:8090/webhook \
-H "Authorization: Bearer $KORVUN_WEBHOOK_SECRET" \
-H "Content-Type: application/json" \
-d '{"sender_id": "alice", "text": "hello korvun"}'

Un 200 significa que Korvun aceptó el mensaje y lo está enrutando. La respuesta del cerebro va a tu outbound_url — no en esta respuesta HTTP.

Paso 4 — Mira las respuestas

Un receptor desechable que imprime lo que recibe (solo la librería estándar de Python):

python3 -c 'import http.server as h; \
c=type("C",(h.BaseHTTPRequestHandler,),{"do_POST":lambda s:(print(s.rfile.read(int(s.headers["Content-Length"])).decode()),s.send_response(200),s.end_headers())}); \
h.HTTPServer(("127.0.0.1",9099),c).serve_forever()'

Apunta outbound_url a http://127.0.0.1:9099/replies (como en el paso 1), envía un mensaje, y el JSON de la respuesta se imprime en la terminal del receptor.

conversation_id y el mapeo de campos

Korvun mapea tus campos JSON a su forma de mensaje; sobrescribe solo lo que difiera, en webhook.mapping:

Campo de KorvunClave JSON por defectoSignificado
sender idsender_idobligatorio — quién lo envió
sender namesender_namenombre visible, opcional
texttextel cuerpo del mensaje
media urlmedia_urlURL de adjunto, opcional
media typemedia_typetipo MIME, opcional
conversation idconversation_idagrupa mensajes en un hilo

conversation_id es lo que da memoria al cerebro entre mensajes — reutiliza el mismo valor y Korvun los trata como una sola conversación. Si falta, el respaldo es el sender id, así que cada remitente conserva un hilo estable. La respuesta lleva el mismo conversation_id de vuelta.

"webhook": {
"outbound_url": "http://127.0.0.1:9099/replies",
"mapping": { "conversation_id": "thread", "text": "message" }
}

Qué significa cada rechazo

EstadoSignificadoArreglo
401Authorization: Bearer ausente o incorrecto.Envía el secreto exacto del paso 2.
415El Content-Type no es application/json.Añade la cabecera (; charset=utf-8 vale).
413Cuerpo de más de 1 MiB.Envía un payload menor.
400JSON inválido, o sin remitente / sin contenido.Corrige el JSON; incluye sender_id y texto o media.
503Buffer de entrada momentáneamente lleno.Reintenta luego — tu petición estaba bien.

Exponerlo al exterior (proxy inverso + TLS)

El bind por defecto es loopback, así que nada es alcanzable desde fuera de la máquina. Si escuchas en una dirección no-loopback, Korvun avisa al arrancar: el secreto Bearer cruzaría la red en claro. Korvun no termina TLS por sí mismo — pon delante un proxy inverso que termine TLS y deja a Korvun en loopback:

server {
listen 443 ssl;
server_name korvun.example.com;

ssl_certificate /etc/letsencrypt/live/korvun.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/korvun.example.com/privkey.pem;

location /webhook {
proxy_pass http://127.0.0.1:8090/webhook;
}
}

Siguiente