Webhooks
Inbound webhook URLs, authentication options, payload transforms, and secret rotation for triggering a Teammate.
What a webhook is
An inbound webhook lets an external system trigger a specific Teammate by sending it an HTTP request, rather than a message on a channel. It's the integration point for things that aren't people typing in Telegram or Slack: a CI pipeline notifying a Teammate a build failed, a form submission that should kick off a follow-up, a third-party service pushing an event your Teammate should react to.
Each webhook targets exactly one Teammate on one agent server, and you can create as many webhooks as you need — one per integration is the common pattern, so each has its own URL, its own auth, and its own transform logic.
Note: Connecting a GitHub App through the Connect GitHub flow (see Integrations) creates one of these for you automatically, named "GitHub App events" — that's how pull request events (and, for most roles, review and comment events) reach the Teammate without any manual webhook setup on your end. If you bring your own App instead, you configure its webhook yourself. Like any other configuration change, delivery starts after your next deploy, not the moment you finish connecting. For a QA Teammate, the webhook is created with the QA pull request review filter and payload instead of the generic one: it wakes the Teammate only when a non-draft pull request is opened, pushed to, reopened, or marked ready for review, skips pull requests marked
skip-qa, and does not wake on pull request comments or review submissions (the Teammate's own replies in a review thread are part of that review), and passes the pull request's branch and repository to the run. You don't need a separate "PR reviews" webhook, and adding one runs the review twice. A GitHub App connected before this change keeps its existing webhook until you reconnect it. You can edit its payload transform and event filter like any other webhook; disconnecting a Connect-created GitHub App removes it.
The generic webhook's event filter ignores pull requests opened from a fork, along with reviews on them, because anyone can open one against a public repository. To let the Teammate act on fork pull requests, edit the webhook's event filter, delete the line that starts
if (pr && pr.head && pr.base, and deploy. On the generic webhook, comments on a fork pull request still reach the Teammate. A QA Teammate's webhook also ignores fork pull requests; to allow them, delete the line that startsif (!head.repoin its event filter and deploy. A GitHub App connected before this default was added keeps its original filter. To add the fork check to it, put this line after the first line of its event filter, then deploy:var pr = payload.pull_request; if (pr && pr.head && pr.base && (!pr.head.repo || pr.head.repo.full_name !== pr.base.repo.full_name)) { return false; }
The URL
Every webhook gets its own URL, conceptually shaped as your organization, then the agent server, then a unique webhook ID appended to a base path the platform controls. You don't choose or see any internal hosting details — just the full URL to give the system that's calling it.
Authentication
A webhook is authenticated one of three ways:
| Auth type | How it works |
|---|---|
| Bearer token | The caller sends the webhook's secret as a bearer token in the Authorization header |
| Custom header | The caller sends a value in a header name you choose; validated either as a plain token match or as an HMAC-SHA256 signature |
| Query parameter | The caller sends the secret as a query-string parameter you name |
Payload transform and event filter
Every webhook requires a payload transform function, written in JavaScript, that turns the incoming request body into whatever the Teammate needs to act on. Optionally, you can also add an event filter function — JavaScript that decides whether a given incoming request should trigger the Teammate at all, letting you ignore payloads you don't care about without touching the sender's configuration.
Before your transform's output reaches the Teammate, the platform prepends a short instruction telling it to complete the task in that session rather than hand it off to another Teammate — a webhook run has no one waiting to see a "delegated, standing by" follow-up, so the Teammate always works the task through to a result itself.
Secret rotation
The webhook's secret is generated for you and shown exactly once, at creation — the platform doesn't retain it in a form you can look up later, so save it somewhere safe when you create the webhook. If it leaks or you simply want to rotate it, you can regenerate it at any time; the old secret stops working within a minute of regenerating, with no deploy needed.
Enable / disable
A webhook can be toggled on or off without deleting it, which is the quickest way to pause an integration temporarily while keeping its configuration, URL, and secret intact for when you turn it back on. Toggling doesn't invalidate the secret or change the URL — the sender can keep using the same values once you re-enable it.
Toggling or editing a webhook is a configuration change: it reaches the live webhook with your next deploy and takes effect within a minute of it. Deleting a webhook revokes its secret straight away, so its URL stops accepting requests within a minute, with no deploy needed.
Delivery destination
Each webhook can specify where the Teammate's reply should go: a channel (Telegram, Slack, or Discord) and a destination within it. Setting this is recommended — if you leave it blank, delivery falls back to whichever channel the Teammate was most recently active in, which isn't reliable for a webhook-triggered run that doesn't correspond to a live conversation.
You set a destination one of two ways:
- Teammate — search for and pick a team member who has that channel connected; the reply goes to their connected account.
- Custom ID — type the raw destination yourself (up to 255 characters): a Telegram chat ID or
@username, a Slack channel or group ID, or a Discord channel ID. Use this for a group chat, channel, or topic a teammate picker can't target.
A channel and a destination go together — set one and you must set the other. Leaving both blank is valid and means no explicit destination is configured.
Deliver result to channel
By default, when a webhook-triggered run finishes successfully, the Teammate announces the result in its message channel (Telegram, Slack, etc.) — the same way it would report back after a conversation. Turn this off when a webhook's real output lives somewhere else, like a comment the Teammate posts on a pull request, and the chat announcement would just be extra noise. Webhooks created before this setting existed keep today's behavior — the toggle defaults to on.
Duplicate deliveries
When the sender is GitHub, every delivery carries a unique delivery ID, and the platform uses it to skip repeat deliveries, so the Teammate normally runs once per ID. If GitHub sends the same delivery again within three days of it reaching the Teammate, including when you click Redeliver, the platform answers 200 with {"status": "duplicate"} and starts no second run. A delivery that never reached the Teammate, for example because the agent server was unavailable, doesn't count, so redelivering it does trigger a run. To run the Teammate on the same event again on purpose, trigger a new event instead of redelivering the old one. This is best-effort, not a hard guarantee: in rare cases, such as a slow response from the agent server or a brief platform error, the same delivery can run twice. If a Teammate's run has side effects like posting a comment or opening a ticket, don't rely on exactly-once delivery.
API and MCP
Webhooks have full dashboard/API/MCP parity: creating, editing, toggling, rotating secrets, and deleting are all available through the API and MCP tools as well as the dashboard. See API & MCP for the resource map.