Blog · Guide · 29 October 2026
Trigger an AEGIS workflow from a signed webhook
Disclosure: 100monkeys.ai builds AEGIS, so read this guide as a maker's account. It was drafted by one of our AI agents from the public AEGIS documentation, Configuring Webhooks, and reviewed by the company. Every command and code block below is copied from that page; none was run for this guide. Where the docs leave a question open, the last section says so.
AEGIS by 100monkeys.ai, in beta, can start a workflow when another system sends it an event: a push on GitHub, a CI job finishing, any service that can make an HTTP request. The sender needs no account on your node. In the docs' words, "Authentication is handled by HMAC-SHA256 signature verification, not OAuth." This guide sets up one source end to end, from the shared secret to a tested request, and covers the errors you will meet on the way.
Step 1. Name the source
Every webhook arrives at POST /v1/webhooks/{source}. The source is "a lowercase slug that identifies the system sending the event", such as github, stripe or my-ci. Pick one per sending system: the secret, the route and the duplicate check all key on it.
Step 2. Set the shared secret on the orchestrator
Secrets are scoped per tenant and source, so two tenants that both call their source github hold "completely independent secrets". Each pair is one environment variable on the orchestrator, named by this pattern:
# 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"
So tenant u-abc123 with source my-ci reads AEGIS_WEBHOOK_SECRET_U_ABC123_MY_CI. If the variable is missing for the resolved pair, the request is rejected with 401 secret_not_found. Give the same secret to the sender and to nobody else.
Step 3. Route the source to a workflow
A direct route maps the source to one workflow, so routing is "instant and deterministic". In the current release, direct routes are "configured via orchestrator workflow routing configuration", and the page notes "there is no aegis stimulus routes CLI command yet". Without a direct route, the pipeline falls back to a configured RouterAgent, which classifies the event with a language model. With neither, the request fails with 422 no_router_configured. For a single, known sender, a direct route is the one to want: the same event always starts the same workflow.
Step 4. Sign the raw body on the sender
The sender computes an HMAC-SHA256 of the raw request body with the shared secret and sends it in X-Aegis-Signature with the prefix sha256=. The docs' Python example:
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,
},
)
The page also gives the same in Node.js. The one rule it puts in bold: compute the HMAC over the raw request body bytes before any parsing, because "Computing over a re-serialized object will produce a different signature." Sign the exact bytes you send.
Step 5. Test the endpoint with 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"
A success answers with two ids:
{
"stimulus_id": "stim-uuid",
"workflow_execution_id": "wfex-uuid"
}
The second is the workflow run the event started; follow it as you would any other run.
Step 6. Stop duplicate deliveries
Senders retry. Forward the provider's delivery id as X-Idempotency-Key: for GitHub that is X-GitHub-Delivery, and for your own sender "Any stable per-event UUID". The orchestrator deduplicates on source and key for 24 hours, and a repeat answers 409:
{
"error": "idempotent_duplicate",
"original_stimulus_id": "stim-original-uuid"
}
Step 7. Read the error you get
The page's error table, in the order you are likely to meet it:
401 missing_signature: noX-Aegis-Signatureheader.400 malformed_signature: the header is not insha256=<hex>form;400 invalid_hex: the hex part has other characters.401 secret_not_found: no variable for the resolved tenant and source.401 invalid_signature: the digest does not match; a body re-serialized before signing is the case the page warns about.409 idempotent_duplicate: already processed within 24 hours.422 classification_failed: the RouterAgent's confidence was below its threshold;422 no_router_configured: no direct route and no RouterAgent.
Step 8. Use the authenticated endpoint for internal callers
A service that already holds a Keycloak account can skip the shared secret and post to POST /v1/stimuli with a bearer token instead, giving source, content and an idempotency_key in the body. Keep the webhook route for systems you do not run.
What the docs leave open
- How to write a direct route. The page says routes live in the orchestrator's workflow routing configuration and gives no key, file or example, and the Configuration Reference is not linked from that step.
- How a webhook is registered. The tenant "is resolved from the (tenant, source_name) registration written when the webhook was registered"; the page does not show that registration.
- What the workflow receives. The page does not say how the payload and headers appear in the started workflow's input or blackboard.
- Rotating a secret. No overlap window is described, and the page does not say whether a changed variable takes effect without restarting the orchestrator.
Next
The workflow a webhook starts is a state machine you write. Our guide AEGIS workflow states and transitions, step by step builds one. AEGIS installs with the command printed on 100monkeys.ai:
curl -fsSL https://get.100monkeys.ai | bash