Connect Heilo to your CRM
Four steps to connect Heilo to any CRM — using Zapier, Make, or any other tool that supports webhooks.
After every call, Heilo sends a notification with the call details to an address you choose. This guide shows how to connect Heilo to any CRM using Zapier or Make — no code, in 15–20 minutes.
It’s a universal path that works with any CRM supported by Zapier or Make. Dedicated step-by-step recipes for Pipedrive, HubSpot, and Zoho CRM are included below. One-click Zapier/Make templates are still on the roadmap — until then, each recipe walks you through the last step (saving to your CRM) manually.
1Create a new Zap in Zapier
The “Webhooks by Zapier (Catch Hook)” trigger generates an address that Heilo will send events to.
- Sign in to your Zapier dashboard
- Create Zap → Choose Trigger → “Webhooks by Zapier”
- Event = “Catch Hook” → Continue
- Zapier shows an address like https://hooks.zapier.com/hooks/catch/… — copy it
2Paste the address into Heilo as a webhook subscription
Heilo verifies the address — your Zapier endpoint responds automatically. After activation, every call is sent to this address.
- Go back to Settings → Integrations in Heilo
- Click “Add subscription”
- Paste the Zapier address into the “Endpoint URL” field, choose the event types (completed call + outbound call attempt) and click “Create + handshake”
- The status should change to “Active”. Copy the signing_secret (shown once)
3Send a test event
Heilo sends a test event with the full set of data from a completed call (sample data: Jan Kowalski / plastering / Warsaw) — in Zapier you’ll see every field you’ll get in real events. Map once, and it works for both the test and real calls.
- In Heilo, click the “Test” icon next to your subscription
- Back in Zapier, go to the trigger step → “Test trigger” → you should see the full data
- Check that you can see the call data — the caller’s number, name, summary and recording link
- Continue → move on to the action step (your CRM)
4Set up the save in your CRM
In your tool (Zapier or Make) add actions for your CRM — for example Pipedrive, Zoho CRM, Notion or Airtable. For sales workflows this is usually three steps: (1) find or create a contact by phone number, (2) create or update a lead/deal, (3) attach an activity, task or note.
| Heilo field | Map to CRM |
|---|---|
| data.call_id | ID / reference field |
| data.customer_phone_e164 | Contact phone (“Phone” / “Primary Phone”) |
| data.transcript_processed.caller_name | Contact name (if Heilo detected it) |
| data.transcript_processed.summary | Note body or activity description |
| data.transcript_processed.service_needed | Activity subject or deal title |
| data.transcript_processed.subject | Lead/deal title (best fallback for service_needed) |
| data.transcript_processed.lead_score | Priority, label or qualification filter |
| data.transcript_processed.preferred_date | Follow-up due date or expected close date |
| data.transcript_processed.client_city | Contact city / address field |
| data.transcript_processed.client_address | Contact street address |
| data.transcript_processed.services_match | Whether the request matches your offer (true/false) — for qualification |
| data.transcript_processed.additional_details | Extra details from the call → note / description |
| data.recording_url | A URL field (e.g. “Recording link”) |
| data.duration | Activity duration (in seconds) |
The data.outbound_lifecycle field appears only in call.outbound.attempted and call.failed events — it is not present in call.completed.
Recipes for specific CRMs
Below are CRM-specific configurations. The generic webhook gives you the call data; this section shows how to turn it into a contact, lead/deal and activity in a specific CRM.
Pipedrive: contact + lead/deal + activity
Target outcome: after a completed call, Pipedrive finds or creates a person, creates a sales lead/deal and attaches an activity with the summary and recording link.
Use Lead if calls should first land in Leads Inbox for qualification. Use Deal if every qualified call should enter the pipeline immediately.
Zapier
- Trigger: Webhooks by Zapier → Catch Hook. Keep the Heilo subscription in permissive mode.
- Filter by Zapier: allow event_type = call.completed; during setup also allow webhook.test (or filter by data._test = true).
- Pipedrive → Find or Create Person. Search by Phone Numbers = data.customer_phone_e164, and set Person Name from caller_name or the phone number.
- Pipedrive → Create Lead or Find or Create Deal. Set the title from subject, with service_needed as fallback.
- Pipedrive → Create Activity. Attach it to Lead ID or Deal ID, then put summary, recording_url, transcript_original and call_id in Note/Public Description.
Make
- Trigger: Webhooks → Custom webhook. The scenario must be active and run when data arrives.
- Add a filter after the webhook: event_type = call.completed; while mapping test data, also allow webhook.test (or filter by data._test = true).
- Pipedrive CRM → Search Persons by data.customer_phone_e164. If there is no result, create a Person with that phone and caller_name or the phone number as the name.
- Pipedrive CRM → Search Leads or Search Deals for that person. If there is no open opportunity, create a Lead or Deal.
- Pipedrive CRM → Create Activity or Create Note. Attach it to the lead/deal/person and store summary, recording_url and call_id.
| Heilo field | Pipedrive field / action | Use |
|---|---|---|
| event_type | Filter / Router | Process call.completed; use webhook.test only for field mapping. |
| data.customer_phone_e164 | Person → Phone Numbers | Primary field for contact lookup and deduplication. |
| data.transcript_processed.caller_name | Person → Person Name | If empty, use the phone number as a safe fallback name. |
| data.transcript_processed.subject | Lead/Deal → Title | Best opportunity title; fall back to service_needed. |
| data.transcript_processed.service_needed | Lead/Deal → Title or custom field | Inquiry category; useful for pipeline routing or labels. |
| data.transcript_processed.summary | Activity/Note → Note or Public Description | Short call description visible on the opportunity. |
| data.transcript_processed.lead_score | Lead label / priority / filter | For example, create a lead/deal only from 7/10 or send lower scores to review. |
| data.transcript_processed.preferred_date | Expected close date or activity due date | Use when the customer mentioned a deadline or preferred follow-up date. |
| data.transcript_processed.client_city | Person → Address (city) or custom field | Customer city; handy for segmentation or a regional pipeline. |
| data.transcript_processed.client_address | Person/Organization → Address | Fill the person/organization address when the caller provided it. |
| data.transcript_processed.services_match | Filter / Lead label | false = request outside your offer; skip the deal or flag it for rejection. |
| data.transcript_processed.additional_details | Activity/Note → Note | Extra details from the call; append them to the activity body. |
| data.recording_url | Activity/Note → Recording link | Playback link; may stop working after the call is deleted for GDPR retention. |
| data.call_id | Custom field → Heilo Call ID | Idempotency key. Prevents a second CRM record for the same call. |
| data.duration | Activity duration | Heilo sends seconds; convert if your Pipedrive field expects a time format. |
Conditions for correct pairing
- Do not enable strict mode for Zapier/Make — their webhook endpoints return standard 2xx responses but do not echo the challenge.
- Do not mix event types without a filter: call.outbound.attempted does not include the full transcript or recording.
- Add a Pipedrive custom field named Heilo Call ID and store data.call_id there to avoid duplicates.
- When updating an existing lead/deal, first search for an open opportunity for the person, and create a new one only if none exists.
HubSpot: contact + deal + note
Target outcome: after a completed call, HubSpot finds or creates a contact by phone number, creates a deal and logs a note with the summary and recording link.
Deduplication trap: Zapier's Create or Update Contact matches existing contacts by e-mail only. Heilo events carry a phone number and often no e-mail, so that action creates a duplicate contact on every call. Always search by the phone property first and create a contact only when the search finds nothing.
Zapier
- Trigger: Webhooks by Zapier → Catch Hook. Keep the Heilo subscription in permissive mode.
- Filter by Zapier: allow event_type = call.completed; during setup also allow webhook.test (or filter by data._test = true).
- HubSpot → Find Contact. Set the search property to Phone Number and map data.customer_phone_e164; enable the option to create the contact when nothing is found, with caller_name or the phone number as the name. Do not use Create or Update Contact here — it matches by e-mail.
- HubSpot → Create Deal. Set Deal Name from subject (service_needed as fallback), pick Pipeline and Deal Stage, and associate the deal with the contact.
- HubSpot → Create Engagement (type Note). Associate it with the contact and deal, and put summary, recording_url, transcript_original and call_id in the note body.
Make
- Trigger: Webhooks → Custom webhook. The scenario must be active and run when data arrives.
- Add a filter after the webhook: event_type = call.completed; while mapping test data, also allow webhook.test (or filter by data._test = true).
- HubSpot CRM → Search for Contacts by the phone property = data.customer_phone_e164. If there is no result, create the contact with Create a Contact (that phone plus caller_name or the phone number as the name).
- HubSpot CRM → Create a Deal. Set Deal Name from subject, pick Pipeline and Deal Stage, and associate the deal with the contact.
- HubSpot CRM → Create an Engagement (type Note). Link it to the contact and deal and store summary, recording_url and call_id.
| Heilo field | HubSpot field / action | Use |
|---|---|---|
| event_type | Filter / Router | Process call.completed; use webhook.test only for field mapping. |
| data.customer_phone_e164 | Contact → Phone Number | Primary lookup key. Store phones in HubSpot in E.164 format — the phone search matches exact values, not formatting variants. |
| data.transcript_processed.caller_name | Contact → First Name / Last Name | If empty, use the phone number as a safe fallback name. |
| data.transcript_processed.subject | Deal → Deal Name | Best opportunity title; fall back to service_needed. |
| data.transcript_processed.service_needed | Deal → Deal Name or custom property | Inquiry category; useful for pipeline routing or labels. |
| data.transcript_processed.summary | Note → Note body | Short call description visible on the opportunity. |
| data.transcript_processed.lead_score | Custom property / filter | For example, create a lead/deal only from 7/10 or send lower scores to review. |
| data.transcript_processed.preferred_date | Deal → Close Date or task due date | Use when the customer mentioned a deadline or preferred follow-up date. |
| data.transcript_processed.client_city | Contact → City | Customer city; handy for segmentation or a regional pipeline. |
| data.transcript_processed.client_address | Contact → Street Address | Fill the person/organization address when the caller provided it. |
| data.transcript_processed.services_match | Filter / deal tag | false = request outside your offer; skip the deal or flag it for rejection. |
| data.transcript_processed.additional_details | Note → Note body | Extra details from the call; append them to the activity body. |
| data.recording_url | Note → Recording link | Playback link; may stop working after the call is deleted for GDPR retention. |
| data.call_id | Custom property → Heilo Call ID | Idempotency key. Prevents a second CRM record for the same call. |
| data.duration | Custom property or note | Heilo sends seconds; convert if your HubSpot property expects a different format. |
Conditions for correct pairing
- Do not enable strict mode for Zapier/Make — their webhook endpoints return standard 2xx responses but do not echo the challenge.
- Do not mix event types without a filter: call.outbound.attempted does not include the full transcript or recording.
- Do not rely on Create or Update Contact for matching — it deduplicates by e-mail only; always run the phone search first.
- Add a HubSpot custom property named Heilo Call ID (single-line text) and store data.call_id there to avoid duplicates.
- When updating an existing lead/deal, first search for an open opportunity for the person, and create a new one only if none exists.
Zoho CRM: contact + deal + note
Target outcome: after a completed call, Zoho CRM finds or creates a contact by phone number, creates a deal and attaches a note with the summary and recording link.
Search contacts by the Phone field (or Mobile, if that is where you store numbers). Heilo sends data.customer_phone_e164 in E.164 format — keep Zoho numbers in the same format, otherwise the search will not match.
Zapier
- Trigger: Webhooks by Zapier → Catch Hook. Keep the Heilo subscription in permissive mode.
- Filter by Zapier: allow event_type = call.completed; during setup also allow webhook.test (or filter by data._test = true).
- Zoho CRM → Find Module Entry in the Contacts module, searching the Phone field by data.customer_phone_e164; enable the option to create the entry when nothing is found. Zoho requires Last Name — use caller_name or the phone number.
- Zoho CRM → Create Module Entry in the Deals module. Set Deal Name from subject (service_needed as fallback), pick Stage and link the deal to the contact.
- Zoho CRM → Create Module Entry in the Notes module. Put summary, recording_url, transcript_original and call_id in Note Content and relate the note to the deal or contact.
Make
- Trigger: Webhooks → Custom webhook. The scenario must be active and run when data arrives.
- Add a filter after the webhook: event_type = call.completed; while mapping test data, also allow webhook.test (or filter by data._test = true).
- Zoho CRM → Search Objects in the Contacts module with the criterion Phone = data.customer_phone_e164. If there is no result, create the contact with Create an Object (Last Name from caller_name or the phone number).
- Zoho CRM → Create an Object in the Deals module. Set Deal Name from subject, pick Stage and link the deal to the contact.
- Zoho CRM → Create an Object in the Notes module. Store summary, recording_url and call_id in Note Content and attach the note to the deal or contact.
| Heilo field | Zoho CRM field / action | Use |
|---|---|---|
| event_type | Filter / Router | Process call.completed; use webhook.test only for field mapping. |
| data.customer_phone_e164 | Contact → Phone | Primary lookup key. Search the Phone field (or Mobile) and keep one number format on both sides — the search matches exact values. |
| data.transcript_processed.caller_name | Contact → Last Name | Zoho requires Last Name; if caller_name is empty, use the phone number as a safe fallback name. |
| data.transcript_processed.subject | Deal → Deal Name | Best opportunity title; fall back to service_needed. |
| data.transcript_processed.service_needed | Deal → Deal Name or custom field | Inquiry category; useful for pipeline routing or labels. |
| data.transcript_processed.summary | Note → Note Content | Short call description visible on the opportunity. |
| data.transcript_processed.lead_score | Custom field / filter | For example, create a lead/deal only from 7/10 or send lower scores to review. |
| data.transcript_processed.preferred_date | Deal → Closing Date or task due date | Use when the customer mentioned a deadline or preferred follow-up date. |
| data.transcript_processed.client_city | Contact → Mailing City | Customer city; handy for segmentation or a regional pipeline. |
| data.transcript_processed.client_address | Contact → Mailing Street | Fill the person/organization address when the caller provided it. |
| data.transcript_processed.services_match | Filter / tag | false = request outside your offer; skip the deal or flag it for rejection. |
| data.transcript_processed.additional_details | Note → Note Content | Extra details from the call; append them to the activity body. |
| data.recording_url | Note → Note Content (link) | Playback link; may stop working after the call is deleted for GDPR retention. |
| data.call_id | Custom field → Heilo Call ID | Idempotency key. Prevents a second CRM record for the same call. |
| data.duration | Custom field or note | Heilo sends seconds; convert if your Zoho CRM field expects a different format. |
Conditions for correct pairing
- Do not enable strict mode for Zapier/Make — their webhook endpoints return standard 2xx responses but do not echo the challenge.
- Do not mix event types without a filter: call.outbound.attempted does not include the full transcript or recording.
- Add a Zoho CRM custom field named Heilo Call ID and store data.call_id there to avoid duplicates.
- Zoho rejects records with missing required fields: Contacts need Last Name and Deals need at least Deal Name and Stage (depending on your layout also Closing Date) — map safe fallbacks for them.
- When updating an existing lead/deal, first search for an open opportunity for the person, and create a new one only if none exists.
Full data structure (reference)
Every notification has the same structure. The fields under “data” depend on the event type — a completed call, for instance, includes the processed transcript. The Heilo-Signature header signs the payload (HMAC-SHA256), so you can verify a request really came from Heilo.
{
"api_version": "2026-06-15",
"event_id": "<uuid>",
"event_type": "call.completed",
"resource_id": "<call_id>",
"created_at": "2026-06-03T12:34:56Z",
"data": {
"call_id": "...",
"direction": "inbound",
"caller_phone": "+48600100200",
"customer_phone_e164": "+48600100200",
"duration": 87,
"recording_url": "https://heilo.io/api/v1/calls/.../recording.mp3?token=...",
"transcript_processed": {
"caller_name": "Jan Kowalski",
"client_address": "ul. Przykladowa 10",
"client_city": "Warszawa",
"summary": "...",
"service_needed": "Tynki gipsowe w mieszkaniu 65m2",
"subject": "Wycena tynkow - Warszawa, 65m2",
"lead_score": 7,
"preferred_date": "2026-06-10",
"services_match": true,
"additional_details": "Klient wspomnial o terminie do konca czerwca."
},
"transcript_original": "..."
}
}Common issues
- Verification (handshake) failed after adding the subscription
- Your address didn’t confirm within 10 seconds. In Zapier this happens automatically; in Make the scenario must be switched on (and in strict mode you also need a “Webhook response” module). Also check the address has no spaces or “&” characters, fix it, then click “Reverify” on the paused subscription.
- Duplicate contacts are being created in my CRM
- Connector tools don’t normalise phone formats — “+48 600 100 200” and “+48600100200” look like two different numbers. Heilo already sends the number in E.164 format (the customer_phone_e164 field), so use that one to look up the contact. In Zapier you can also add a “Formatter → Phone Number → E.164” step before the lookup.
- The recording link stops working after a while
- The link works as long as the call exists and isn’t scheduled for deletion (GDPR). If the call was deleted, the link returns a 410 error. This is by design.
- A message about exceeding the operation limit
- One Heilo call is usually about 3 operations in the tool (find + create + optional update). Free plans are enough for testing; for higher call volumes consider a paid Zapier or Make plan (Make includes 1000 free operations/month ≈ 330 calls).
Roadmap (v1.1+)
What we're planning for upcoming releases. This list isn't a guarantee — priorities follow your feedback.
- Dedicated recipes for more CRMs: Salesforce, Bitrix24, Livespace
- One-click templates (Zapier/Make) for the most popular CRMs
- Copy-paste deduplication and field-mapping rules
- More event types to map (e.g. contact created/updated)
Missing your CRM or scenario? Email support@heilo.io — we prioritize by real-world need.
Manage keys and webhooks in the panel
Generate API keys, add webhook subscriptions and watch the delivery log after signing in.