Webhook triggers
Receive inbound webhooks and dispatch agent runs.
Webhook triggers
Oxagen accepts signed inbound webhooks at
POST https://api.oxagen.ai/v1/triggers/webhook/{slug}. Each
webhook trigger has a slug (chosen at creation time), an HMAC
secret stored in Google Cloud Secret Manager, and an optional
JMESPath filter.
Request shape
| Header | Required | Value |
|---|---|---|
X-Oxagen-Signature | yes | t=<unix-seconds>,v1=<hex-hmac-sha256> |
X-Oxagen-Idempotency-Key | no | opaque ASCII, ≤200 chars |
Content-Type | no | application/json or application/x-www-form-urlencoded |
Body: raw bytes, max 2 MiB.
Signature
Compute HMAC-SHA256(secret, f"{t}.{body}") where t is the Unix
timestamp in seconds and body is the raw request body bytes.
Send the result as the v1= segment.
Oxagen rejects signatures when t is more than 300 seconds ahead
of or behind server time. Regenerate t and the HMAC on each
retry; resending a stale header returns 401 with
reason: signature_invalid.
Responses
| Status | Meaning |
|---|---|
| 202 | Delivery accepted; body includes delivery_id and optional execution_id |
| 401 | Signature invalid; body includes delivery_id and reason: signature_invalid |
| 404 | Unknown or disabled slug |
| 413 | Body exceeds 2 MiB |
Every request — including 401 responses — persists a row in
run.webhook_delivery with the raw headers and body. A daily GC
task deletes rows older than 30 days.
Idempotency
When X-Oxagen-Idempotency-Key is present, duplicate deliveries
with the same key return the prior delivery_id and
execution_id without re-dispatching.
JMESPath filter
When event_filter.expression is set on the trigger, the webhook
payload is evaluated as {headers, body, trigger}. A false result
skips dispatch but still records the delivery.