HTTP Webhook Adapter
The webhook adapter registers HTTP POST endpoints that accept JSON payloads (e.g. GitHub, custom integrations). Each request is validated, optionally HMAC-verified, filtered by event type, then handed to an Agentix run using a prompt template that includes the JSON body.
Typical use: configure everything in gateway.yaml — you rarely construct WebhookAdapter in Python.
1. Enable the channel
The gateway skips the webhook channel unless the environment says so:
| Variable | Required | Purpose |
|---|---|---|
WEBHOOK_ENABLED | Yes | Set to true (case-insensitive) or the webhook adapter is not registered. |
WEBHOOK_PORT | No | When a webhook channel is present, the HTTP server listens on this port (default 8644), overriding gateway.port in YAML. |
WEBHOOK_SECRET | No | Default HMAC secret for routes that omit secret (see Secrets). |
WEBHOOK_MAX_BODY_SIZE | No | Max POST body size in MB when a route omits max_body_size_mb (default 2). |
WEBHOOK_RATE_LIMIT | No | Requests per minute when a route omits rate_limit_per_min (default 60). |
Put these in the process environment or a project .env file (loaded when the gateway starts).
2. Minimal gateway.yaml shape
Under channels, add a single entry (the key is arbitrary, e.g. webhook or integrations):
channels:
webhook:
adapter: webhook
routes:
<route_name>:
# required — see §3
...
agents:
<name>:
# optional named AgentixAgentOptions (subset) — see §4
adaptermust bewebhook.routesis a map: each key becomes the URL segment/webhooks/<key>.agentsdefines named agent configs; routes reference them viaagent: <name>.
3. Route configuration (routes.<route_name>)
Each route must include:
| Field | Required | Description |
|---|---|---|
events | Yes | Non-empty list of event type strings allowed for this route. Incoming requests are matched against the resolved event type (see Event type). Others get HTTP 400. |
agent | Yes | Name of an entry under agents: that should run this webhook. If that name is missing, the gateway default agent client is used. |
prompt | Yes | Text template; {payload} is replaced with a JSON string of the request body (truncated if very large). This text is what the agent receives as the user message. |
Optional fields:
| Field | Default | Description |
|---|---|---|
secret | — | Per-route HMAC secret. If unset, see WEBHOOK_SECRET. If no secret applies, HMAC is not required. |
deliver | log | Where the agent result goes after the run finishes: log (structured logs) or http_callback (POST JSON to callback_url). |
callback_url | — | Required when deliver: http_callback. |
max_body_size_mb | env / 2 | Max body size for this route. |
rate_limit_per_min | env / 60 | Per-route rate limit. |
HTTP behavior (important): The handler responds 202 Accepted with {"status":"accepted","event_id":...} right after enqueueing work. The agent runs asynchronously; the HTTP client does not wait for the LLM. Use deliver: http_callback if a downstream system must receive the result.
4. Named agents (agents)
Optional. Each key under agents becomes a dedicated AgentixClient with its own AgentixAgentOptions (same fields you use under the top-level agent: section: name, provider, model, system_prompt, allowed_tools, etc.).
Routes point to a name with agent: default (or any key you defined). If the name is missing, the gateway’s default agent is used.
5. Full example (GitHub-style)
channels:
webhook:
adapter: webhook
routes:
github_pr:
events: ["pull_request"]
secret: "${GITHUB_WEBHOOK_SECRET}"
agent: default
prompt: |
A GitHub event was received. Handle it appropriately.
Payload:
{payload}
deliver: log
agents:
default:
name: webhook-agent
provider: anthropic
model: null
system_prompt: "Process incoming webhook events and take appropriate action."
permission_mode: default
max_tokens: 4096
max_iterations: 20
tool_timeout: 120.0
conversation_summarization_enabled: true
persistence_enabled: false
allowed_tools: []
disallowed_tools: []
cwd: null
env: {}
llm_options: {}
Sender URL: POST https://<your-gateway>/webhooks/github_pr
How event type is resolved
The adapter resolves a single string event_type from, in order:
- Headers
X-Event-TypeorX-GitHub-Event(case variants supported), or - JSON body fields
event_typeoraction.
That string must appear in the route’s events list, or the request fails with 400 (invalid_event_type).
GitHub: sends X-GitHub-Event: pull_request — include "pull_request" in events.
Secrets and HMAC
When a secret applies (per-route secret or WEBHOOK_SECRET), the adapter expects HMAC-SHA256 over the raw request body, in the X-Hub-Signature-256 header, GitHub-style: sha256=<hex>.
Missing or bad signature → 401.
Other HTTP responses (short)
| Status | Meaning |
|---|---|
| 404 | Unknown route_name in the URL. |
| 400 | Invalid JSON, or event type missing / not in events. |
| 413 | Body larger than allowed. |
| 429 | Rate limited. |
| 200 | Same delivery id seen again — idempotent replay (status: duplicate). |
| 202 | Accepted — work queued; agent runs in the background. |
Advanced: Python
The gateway builds the adapter from YAML. Programmatic use matches the constructor:
from agentix.gateway.adapters.webhook import WebhookAdapter
from agentix.gateway.adapters._webhook.config import parse_webhook_routes, parse_webhook_agents
routes = parse_webhook_routes({...}) # same shape as YAML `routes`
named = parse_webhook_agents({...}) # same shape as YAML `agents`
gateway.add_channel(WebhookAdapter(routes=routes, named_agents=named))
There is no route= / extract_message= shortcut on WebhookAdapter — prompts are built from prompt and {payload} substitution only.