Find it in Darwin Profile menu → Workspace settings → API → Webhooks Open this screen ↗
Webhooks tell your systems the moment something happens in the chat: a visitor leaves their email, asks for a person, or books a meeting. Darwin sends each event as a signed POST to your HTTPS address and retries for about three days if your server doesn’t answer.
Every event is something Darwin’s server recorded, never something a browser claimed. Your own preview chats send no events; use Send test event to try an endpoint.
Add an endpoint
- In Darwin
- With the API
1
Open Webhooks
Open Settings → API. Owners and admins see Add endpoint beside Webhooks.
2
Enter your URL
Select Add endpoint and enter an HTTPS URL on a public hostname, for example
https://example.com/webhooks/darwin. It must answer 2xx within 10 seconds.3
Choose events
Under Events, keep Choose events and tick what you need.
lead.captured, handoff.requested and meeting.booked are ticked for you. All events subscribes to every type, including ones Darwin adds later.4
Copy the signing secret
Select Add endpoint. Darwin shows the endpoint’s Signing secret (
whsec_…). Store it with your receiver’s other secrets. Owners and admins can see it again later with Show signing secret.5
Send a test event
Open the endpoint’s ⋯ menu and select Send test event. It worked if Darwin says The endpoint answered 200 (or another
2xx). Otherwise it shows why, for example HTTP 401 or No answer within 10 seconds.GET /events.
Events
data.object has the same shape as the REST API’s answer for that object, so code that reads GET /conversations/{id} also reads the webhook. Webhooks always include names and emails: an endpoint exists to get the lead into your CRM.
What Darwin sends
Darwin builds the payload a few seconds after the event and keeps it: a retry or redelivery sends the same body. For the latest state, read the object from the API by its id.
Example payloads
lead.captured
lead.captured
handoff.requested and conversation.completed
handoff.requested and conversation.completed
conversation.completed has the same shape. Its evaluation is filled in: intent, buying_stage, qualification_score and meeting_intent (0 to 10), understood, failure_category, abandonment_reason and recommended_improvement. conversation.started carries the conversation without messages.meeting.booked, meeting.rescheduled and meeting.canceled
meeting.booked, meeting.rescheduled and meeting.canceled
verified is true when the calendar provider confirmed the booking. On meeting.rescheduled, start_at, end_at and reschedules change; on meeting.canceled, status is canceled.experiment.started and experiment.winner_found
experiment.started and experiment.winner_found
GET /experiments/{id}.knowledge.source_failed
knowledge.source_failed
webhook.test
webhook.test
GET /events.data.object is null. If the person was erased, data is { "erased": true }.
Verify the signature
Darwin signs every request the Standard Webhooks way, so you can use an existing library or a few lines of your own. Always verify before you trust a payload: anyone can send aPOST to your URL.
- Take the raw request body exactly as received. Parsing and re-serialising the JSON changes the bytes and breaks the signature.
- Reject the request if
webhook-timestampis more than five minutes from your clock. - Build the signed content:
`${webhook-id}.${webhook-timestamp}.${body}`. - Compute HMAC-SHA256 over it. The key is your signing secret without the
whsec_prefix, base64-decoded. - Base64-encode the result and compare it, in constant time, with each
v1,entry inwebhook-signature. The header can hold several entries separated by spaces (during a secret rotation); accept if any matches.
Use a Standard Webhooks library
Any Standard Webhooks library verifies Darwin’s signatures, including Svix’s. Pass the raw body, the headers and the secret as Darwin shows it:Answer quickly
- Answer with any
2xxstatus within 10 seconds. Anything else counts as a failure: a3xx(Darwin does not follow redirects), a4xx, a5xx, a timeout or a refused connection. - Answer first and do slow work (CRM calls, Slack posts) afterwards in a queue. A receiver that waits on another service is the most common cause of timeouts.
- Darwin reads at most the first 64 KB of your answer and keeps the first 500 characters in the delivery log. Don’t return anything secret.
Handle duplicates and order
- At least once. Darwin may deliver the same event more than once, for example when your server handled it but the answer was lost.
webhook-id(the eventid) is the same on every retry and redelivery. Record the ids you’ve processed and skip repeats. - No ordering. Events can arrive out of order, especially after retries. A
meeting.rescheduledcan arrive before itsmeeting.booked. Usecreated_at, or the object’supdated_at, to decide which is newer, or read the current object from the API.
Retries
If a delivery fails, Darwin tries again after:
That is nine attempts over about three days. After the last one the delivery is marked Failed. You can still send it again by hand for 30 days.
Endpoints that keep failing are switched off
If an endpoint has failures and not one successful delivery for three days, and is still failing, Darwin switches it off and shows why under its address in Settings → API: Deliveries have failed for three days without one success. Fix the receiver, then switch the endpoint back on. An endpoint that answers410 Gone is switched off at once: that is how a receiver (Zapier, for one) says the subscription is over. Its badge turns from Failing to Off, and GET /webhook_endpoints/{id} shows "status": "disabled" with a disabled_reason.
While an endpoint is off, Darwin does not queue new events for it. To recover:
- Fix your receiver and check it with Send test event.
- Open the endpoint’s ⋯ menu and select Switch on (or
PATCHit with{"status": "enabled"}). Deliveries that were still retrying continue. - Send the events you missed: use Send again in Deliveries, or read
GET /eventsfor the gap and redeliver them.
Check deliveries and send again
Open the endpoint’s ⋯ menu and select Deliveries. Each row shows the event type, whether it was Delivered, is Retrying or Failed, the number of attempts, your server’s last HTTP status or error, and the next try. Send again puts that delivery back in the queue; it goes out within a few seconds. The endpoint row also summarises this week: how many were delivered, failed and are retrying. With the API:queued. Only enabled endpoints subscribed to the event’s type receive it.
Catch up with the event log
Every event from the last 30 days is inGET /events (scope events:read), newest first. It is the pull twin of webhooks: use it after downtime, or instead of webhooks if you would rather poll.
Rotate the signing secret
Open the endpoint’s ⋯ menu, select Rotate signing secret and confirm. Darwin shows the new secret once. For the next 24 hours every delivery carries two signatures, one per secret, so your receiver keeps working while you switch it to the new secret. After 24 hours only the new secret signs. With the API:POST /v1/webhook_endpoints/{id}/rotate_secret returns the endpoint with its new secret.
Requirements for your URL
- HTTPS on a public hostname. Plain HTTP, IP addresses,
localhostand.localor.internalnames are refused, and so is a hostname that resolves to a private network address. - No username or password before the host. To authenticate requests, verify the signature, or put a token in the path or query string.
- Darwin does not publish a fixed list of sending IP addresses. Verify signatures rather than allowlisting IPs.
Change or remove an endpoint
- Change its URL, events or description with
PATCH /v1/webhook_endpoints/{id}. - Delete in the ⋯ menu (or
DELETE /v1/webhook_endpoints/{id}) stops all deliveries and removes the endpoint’s delivery log.
Troubleshooting
Every delivery fails with a signature error on my side
Every delivery fails with a signature error on my side
Check that you verify the raw body, not parsed and re-serialised JSON, and that you base64-decode the secret after removing
whsec_. Frameworks that parse JSON automatically need a raw-body route, like express.raw above.Redirects are not followed
Redirects are not followed
Your URL answered with a
3xx. Use the final address, including https:// and the exact path, often with or without a trailing slash.No answer within 10 seconds
No answer within 10 seconds
Answer
200 before doing the work. Check that your server is reachable from the public internet and not behind a login or firewall.I don't get events for my test chats
I don't get events for my test chats
Preview chats in Darwin never send events. Use Send test event, or have someone use the chat on your live website.