Overview
Every zombie with a webhook trigger gets a unique, stable URL:Inbound event webhooks
A zombie declares its webhook trigger inTRIGGER.md:
trigger.source is a human-readable label (email, github, slack, linear, …) that appears in the activity stream; the platform routes strictly by the zombie ID in the URL path. The signature block declares how the platform will authenticate incoming requests.
Authentication modes
A single middleware authenticates every inbound webhook before the agent is notified. Seven first-class providers ship today, each matching the signature scheme the upstream service uses:| Provider / mode | How it authenticates | Field in TRIGGER.md |
|---|---|---|
| Generic Bearer | Authorization: Bearer <token> header | signature.bearer_ref |
| AgentMail | AgentMail HMAC signature | source: agentmail + signature.secret_ref |
| Grafana | Bearer token | source: grafana + signature.bearer_ref |
| Slack | Slack signing secret HMAC | source: slack + signature.secret_ref |
| GitHub | GitHub webhook HMAC | source: github + signature.secret_ref |
| Linear | Linear HMAC | source: linear + signature.secret_ref |
| Jira | Jira HMAC | source: jira + signature.secret_ref |
| Clerk (Svix) | Svix multi-signature rotation | URL prefix /v1/webhooks/svix/{zombie_id} + signature.secret_ref |
secret_ref and bearer_ref fields name entries in the workspace vault. See Credentials.
Sending an event
For generic Bearer-authenticated zombies:202 Accepted with a request ID:
event_id in the body so the agent can de-duplicate if your upstream retries.
Failure modes
| Status | Cause |
|---|---|
401 | Missing, malformed, or mis-signed authentication header. |
404 | Zombie ID does not exist in any workspace. |
410 | Zombie was killed; re-deploy with zombiectl up. |
429 | Workspace rate limit hit; back off per Retry-After. |
503 | Budget breached, or backpressure applied; safe to retry after the period resets. |
Approval gate webhooks
Some zombie actions — sending money, merging a PR, posting to a public channel — should not happen without a human in the loop. The approval gate lets a zombie pause mid-event, emit an approval request, and wait for a human to click approve or deny in Mission Control or via a webhook callback.zombiectl up.
/grant-approval endpoint covers the grant-flow case where a zombie asks for permission to attach a new integration (for example, a new Slack workspace) — see Integration grants for the CLI-side view.
URL-embedded secret form
For upstream systems that cannot attach a header (some form postbacks, some SaaS providers), the platform supports a path-embedded secret:url_secret segment is matched against the zombie’s configured secret in constant time. Reserved segments (approval, grant-approval, svix) are not allowed as URL secret values.
Observing webhook traffic
Every accepted and rejected webhook appears in the activity stream. Stream it with:webhook_rejected, reason code in detail) so you can distinguish a noisy upstream from a real authentication mismatch.