Skip to main content
Three common jobs, each small enough to read in one sitting. They use Node 18 or later and no Darwin library; swap in your own CRM, warehouse or hosting.

Send handoffs to Slack

When a visitor asks to talk to a person, post it to a Slack channel within seconds, with the page they were on and a link to the conversation. You need: a Slack incoming webhook URL for the channel, and somewhere to run a small HTTPS function (a serverless function, a container or an existing server).
server.mjs
1

Deploy the function

Deploy it so it is reachable at an HTTPS address, for example https://hooks.example.com/darwin. Set SLACK_WEBHOOK_URL now; you’ll get DARWIN_WEBHOOK_SECRET in the next step.
2

Add the endpoint in Darwin

In Settings → API → Webhooks, select Add endpoint, paste the address, choose only handoff.requested, and select Add endpoint. Copy the signing secret into DARWIN_WEBHOOK_SECRET and redeploy.
3

Test it

Select Send test event in the endpoint’s menu. Darwin should report a 200. The test event’s type is webhook.test, so nothing is posted to Slack.It worked if, after someone asks the chat on your live site to talk to a person, a message appears in the channel within a few seconds.
The same pattern sends meeting.booked to a sales channel or lead.captured to an SDR queue: subscribe to the type and read data.object. See Webhooks for every payload.

Sync leads to a CRM

Copy every contact Darwin captures into your CRM every 15 minutes, and record Darwin’s contact id back so later runs update the same record. You need: a key with contacts:read (and contacts:write if you write the CRM’s id back), and a place to keep one timestamp between runs.
sync-contacts.mjs
Run it on a schedule (cron, a scheduled function, or your integration platform). The first run, with no lastRun, copies every contact.
  • Writing external_id changes the contact, so it comes back once in the next run. The if (!contact.external_id) check makes that second pass a no-op.
  • Each contact can have one external_id, unique in the workspace. Two contacts with the same id return 409 conflict.
  • For the conversation behind a lead, list GET /v1/conversations?has_lead=true&updated_since=… and match on contact.
  • If you’d rather not poll, subscribe a webhook to lead.captured and upsert the contact in data.object. Keep this job as a nightly safety net for any webhook you miss.
It worked if a test lead from your live chat appears in the CRM after the next run, and GET /v1/contacts?email=… shows the CRM’s id as external_id.

Export conversations to your warehouse nightly

Load every conversation, with its transcript and Darwin’s grading, into BigQuery, Snowflake, Redshift or plain files each night. You need: a key with conversations:read. Leave out contacts:read if the warehouse should not hold names and emails: lead and booker fields then come back null (transcripts still hold whatever visitors typed).
export-conversations.mjs
Load the file into a table keyed on id, merging over yesterday’s rows. Useful columns: Add GET /v1/meetings?updated_since=… and GET /v1/analytics?range=7d to the same job for meetings and daily funnel numbers. It worked if the morning’s file has one line per conversation from the last three days and yesterday’s graded conversations have a non-null evaluation.