Set up outbound webhooks
Register an HTTPS endpoint, pick the events you want, and receive signed JSON from Adduce when themes change or a brief is published.
An outbound webhook is a URL of yours that Adduce POSTs signed JSON to when something happens in a project — no polling, no schedule.
Before you begin
- Role: project Editor or Lead. A workspace Admin is a lead on every project.
- To hand: an HTTPS URL that accepts a POST body and answers with a 2xx status.
- Somewhere to keep a secret: the signing secret is shown once and never again.
- Time: ten minutes, most of it verifying the signature.
What Adduce sends
Three events, each subscribed to independently:
| Event | When it fires |
|---|---|
theme.created | A new theme appeared in synthesis |
theme.updated | An existing theme changed — once per synthesis run, so expect it often |
brief.published | A brief moved from draft to ready |
Every delivery is one POST with the same envelope. data holds the theme or the brief; a theme carries its name, description, evidence and source counts, strength, sentiment and rank, and a brief carries its title, summary and change types. Both carry a url that opens the thing in Adduce.
{
"version": 1,
"eventId": "0c7a5f1e-8b3d-4a2c-9e10-6f2b7d4c1a55",
"type": "theme.updated",
"createdAt": "2026-09-08T09:14:02.117Z",
"project": { "id": "…", "slug": "quillbrook-app" },
"data": { "name": "Onboarding friction on the workspace step", "…": "…" }
}Headers name the event and the delivery: X-Adduce-Event, X-Adduce-Event-Id, X-Adduce-Delivery-Id and X-Adduce-Signature.
How to check a delivery is really from Adduce
The signature header holds a timestamp and a hex HMAC:
X-Adduce-Signature: t=1757323442,v1=5c1f…Recompute HMAC-SHA256(secret, "<t>.<raw body>") over the raw bytes you received, before any JSON parsing, and compare it to v1 in constant time. Reject anything where t is more than five minutes old. Deduplicate on eventId, and ignore fields you do not recognise — version only changes if a field is removed or reshaped, never when one is added.
Steps
In Adduce, open the project, choose Sources, and scroll past the sources list to Outbound webhooks.
Choose Add endpoint. Enter the Endpoint URL — HTTPS only, and it must be a public address; a private or internal one is refused. Add a Description so the card is recognisable later.
Untick any event you do not want, then choose Add endpoint.
The dialog turns into Save your signing secret. Copy it and store it somewhere your service can read, then choose Done. This is the only time it is shown; to replace it you delete the endpoint and add it again.
Choose Send test event on the new card. Adduce POSTs a ping event immediately and prints the status your endpoint returned beside the button.
Verify the signature on that ping against the secret you stored. Once it checks out, the endpoint is live.
When Adduce sends, and what happens when it fails
A delivery is attempted as soon as the event happens, and each attempt is given ten seconds. Anything outside 2xx is a failure, and so is a redirect: Adduce does not follow them.
A failed delivery is retried four more times — after one minute, five minutes, one hour and six hours — and then given up on. Ten given-up deliveries in a row disable the endpoint: the badge reads Auto-disabled, everything still queued for it is dropped, and nothing more is sent. Any single success resets that count to zero.
Send test event still works on a disabled endpoint, so you can confirm a fix — but the app has no control that turns one back on today. The way back is to delete the endpoint and add it again, which means a new signing secret.
Delivery is at-least-once, so the same eventId can arrive twice after a crash. Delivery log on the card lists each attempt with its status and what your endpoint returned, and keeps thirty days.
Disconnect or replace credentials
Delete on the card removes the endpoint, its signing secret and its delivery history. Rotating the secret is the same action: delete the endpoint and add it again, then store the new secret. Nothing already delivered is affected.
If it did not work
Why was the URL refused?
It is not a public HTTPS address. Adduce refuses http, and refuses addresses that resolve inside a private network, which rules out localhost and internal hostnames. Use a public tunnel while you are developing.
Why do my signature checks fail when the payload looks right?
Almost always because the body was parsed and re-serialised before hashing. Sign the exact bytes you received, and include the timestamp and the dot: the message is <t>.<raw body>, not the body alone.
Why did my endpoint go to Auto-disabled?
Ten deliveries in a row were given up on. That is usually an expired certificate, a route that started answering 404, or a handler that takes longer than ten seconds. Fix the destination and choose Send test event to confirm it. Then delete the endpoint and add it again: the card's own notice mentions re-enabling, but no control for that is built yet.
What's next
Connect GitHub Issues
Connect GitHub to a project with a fine-grained token so a theme can be pushed into a repository as an issue, with its evidence and quotes.
Publish briefs to Notion
Connect a Notion integration to a project, choose the parent page briefs land under, and publish a brief as a Notion page you can republish.