Blog · Guía · 29 de octubre de 2026
Inicia un workflow de AEGIS desde un webhook firmado
Aviso: en 100monkeys.ai construimos AEGIS, así que lee esta guía como el relato de quien lo fabrica. La redactó uno de nuestros agentes de IA a partir de la documentación pública de AEGIS, Configuring Webhooks, y la revisó la empresa; esta versión en español es una traducción de la guía original en inglés. Cada comando y bloque de código de abajo está copiado de esa página, y ninguno se ejecutó para esta guía. Las citas van en inglés con la traducción al lado. Donde la documentación deja una pregunta abierta, la última sección lo dice.
AEGIS by 100monkeys.ai, in beta, puede iniciar un workflow cuando otro sistema le envía un evento: un push en GitHub, un job de CI que termina, cualquier servicio capaz de hacer una petición HTTP. El emisor no necesita cuenta en tu nodo. En palabras de la documentación, "Authentication is handled by HMAC-SHA256 signature verification, not OAuth." (la autenticación se hace verificando una firma HMAC-SHA256, no con OAuth). Esta guía configura un origen de punta a punta, del secreto compartido a una petición probada, y repasa los errores que encontrarás por el camino.
Paso 1. Nombra el origen
Todo webhook llega a POST /v1/webhooks/{source}. El origen es "a lowercase slug that identifies the system sending the event" (un slug en minúsculas que identifica al sistema que envía el evento), como github, stripe o my-ci. Elige uno por sistema emisor: el secreto, la ruta y el control de duplicados dependen de él.
Paso 2. Define el secreto compartido en el orquestador
Los secretos van por tenant y origen, así que dos tenants que llaman github a su origen tienen "completely independent secrets" (secretos completamente independientes). Cada par es una variable de entorno del orquestador, con un nombre que sigue este patrón:
# Pattern: AEGIS_WEBHOOK_SECRET_<UPPER_TENANT>_<UPPER_SOURCE>
# Hyphens and dots in tenant id and source name are replaced with underscores
export AEGIS_WEBHOOK_SECRET_U_ABC123_GITHUB="your-shared-secret-here"
export AEGIS_WEBHOOK_SECRET_U_ABC123_STRIPE="another-secret"
export AEGIS_WEBHOOK_SECRET_U_DEF456_MY_CI="third-secret"
Así, el tenant u-abc123 con el origen my-ci lee AEGIS_WEBHOOK_SECRET_U_ABC123_MY_CI. Si falta la variable del par resuelto, la petición se rechaza con 401 secret_not_found. Da el mismo secreto al emisor y a nadie más.
Paso 3. Enruta el origen a un workflow
Una ruta directa asocia el origen a un workflow, de modo que el enrutado es "instant and deterministic" (instantáneo y determinista). En la versión actual, las rutas directas se "configured via orchestrator workflow routing configuration" (configuran mediante la configuración de enrutado de workflows del orquestador), y la página aclara que "there is no aegis stimulus routes CLI command yet" (aún no existe el comando de CLI aegis stimulus routes). Sin ruta directa, el proceso recurre a un RouterAgent configurado, que clasifica el evento con un modelo de lenguaje. Sin ninguno de los dos, la petición falla con 422 no_router_configured. Para un único emisor conocido, la ruta directa es la que conviene: el mismo evento inicia siempre el mismo workflow.
Paso 4. Firma el cuerpo en bruto en el emisor
El emisor calcula un HMAC-SHA256 del cuerpo en bruto de la petición con el secreto compartido y lo envía en X-Aegis-Signature con el prefijo sha256=. El ejemplo en Python de la documentación:
import hashlib
import hmac
import json
import requests
def sign_payload(body: bytes, secret: str) -> str:
sig = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return f"sha256={sig}"
payload = json.dumps({"event": "push", "ref": "refs/heads/main"}).encode()
signature = sign_payload(payload, WEBHOOK_SECRET)
requests.post(
"https://your-aegis-node/v1/webhooks/github",
data=payload,
headers={
"Content-Type": "application/json",
"X-Aegis-Signature": signature,
},
)
La página da lo mismo en Node.js. La regla que pone en negrita: calcula el HMAC sobre los bytes en bruto del cuerpo antes de cualquier análisis, porque "Computing over a re-serialized object will produce a different signature." (calcularlo sobre un objeto vuelto a serializar produce otra firma). Firma exactamente los bytes que envías.
Paso 5. Prueba el endpoint con curl
# Generate a test signature
SECRET="your-shared-secret-here"
BODY='{"event":"push","ref":"refs/heads/main"}'
SIG="sha256=$(echo -n "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')"
# Send the test webhook
curl -X POST https://your-aegis-node/v1/webhooks/github \
-H "Content-Type: application/json" \
-H "X-Aegis-Signature: $SIG" \
-d "$BODY"
Si todo va bien, la respuesta trae dos ids:
{
"stimulus_id": "stim-uuid",
"workflow_execution_id": "wfex-uuid"
}
El segundo es la ejecución de workflow que inició el evento; síguela como cualquier otra ejecución.
Paso 6. Frena las entregas repetidas
Los emisores reintentan. Reenvía el id de entrega del proveedor como X-Idempotency-Key: en GitHub es X-GitHub-Delivery, y en tu propio emisor "Any stable per-event UUID" (cualquier UUID estable por evento). El orquestador elimina duplicados por origen y clave durante 24 horas, y una repetición responde 409:
{
"error": "idempotent_duplicate",
"original_stimulus_id": "stim-original-uuid"
}
Paso 7. Lee el error que recibes
La tabla de errores de la página, en el orden en que es probable que los encuentres:
401 missing_signature: falta la cabeceraX-Aegis-Signature.400 malformed_signature: la cabecera no tiene la formasha256=<hex>;400 invalid_hex: la parte hexadecimal tiene otros caracteres.401 secret_not_found: no hay variable para el tenant y el origen resueltos.401 invalid_signature: el resumen no coincide; un cuerpo vuelto a serializar antes de firmar es el caso del que avisa la página.409 idempotent_duplicate: ya procesado en las últimas 24 horas.422 classification_failed: la confianza del RouterAgent quedó por debajo de su umbral;422 no_router_configured: no hay ruta directa ni RouterAgent.
Paso 8. Usa el endpoint autenticado para llamadas internas
Un servicio que ya tiene una cuenta de Keycloak puede prescindir del secreto compartido y enviar a POST /v1/stimuli con un token bearer, indicando source, content y una idempotency_key en el cuerpo. Deja la ruta de webhook para los sistemas que no gestionas tú.
Lo que la documentación deja abierto
- Cómo escribir una ruta directa. La página dice que las rutas viven en la configuración de enrutado de workflows del orquestador y no da clave, archivo ni ejemplo, y ese paso no enlaza la Configuration Reference.
- Cómo se registra un webhook. El tenant "is resolved from the (tenant, source_name) registration written when the webhook was registered" (se resuelve a partir del registro (tenant, source_name) escrito al registrar el webhook); la página no muestra ese registro.
- Qué recibe el workflow. La página no dice cómo aparecen la carga y las cabeceras en la entrada o el blackboard del workflow iniciado.
- Rotar un secreto. No se describe ningún periodo de solapamiento, y la página no dice si una variable cambiada surte efecto sin reiniciar el orquestador.
Siguiente
El workflow que inicia un webhook es una máquina de estados que escribes tú. Nuestra guía Estados y transiciones de un workflow de AEGIS, paso a paso construye una. AEGIS se instala con el comando que aparece en 100monkeys.ai:
curl -fsSL https://get.100monkeys.ai | bash