Integrations / CRM sync
Sync contacts to your CRM
Keep HubSpot, Attio, Pipedrive, Salesforce or a spreadsheet in step with Crispy without polling. Crispy sends a webhook when a contact is created and when a contact field changes. Your Zapier, n8n, Make or Clay flow upserts the record on the other side.
The events
contact.createdfires once for every new contact, whatever created it: for example an import, the REST API, an MCP tool, a connection sync, message sync, a profile viewer, or a send to someone not yet in your contacts.data.sourcenames the path. Contacts written to your own database (bring-your-own storage) do not send it.contact.updatedfires when a write through Crispy changes a field the payload carries: name, headline, company, company domain, location, country, phone, email, LinkedIn URL, tags, custom attributes or external IDs.data.changed_fieldslists the payload keys that changed. A write that changes nothing sends nothing.- One change is one event. A contact created and then filled in by the same call (for example
upsert_leador an import) sends onecontact.createdthat already carries the filled-in fields, not a created event followed by an updated one. - Every payload carries the contact's current fields and its
identifiersblock, so you can upsert onidentifiers.crispy_idor on an ID you imported intoexternal_ids. Payloads never include message text.
What does not send contact.updated
Background refreshes keep Crispy's own copy current but do not send an update:
- Profile details refreshed when you send to, or are viewed by, an existing contact.
- Empty fields filled in when Crispy matches an existing contact during message sync, connection sync or a REST import (
POST /api/v1/contacts/import). An MCPimport_contactsmerge does send it. - Connection status, campaign state and pipeline status. Use
invitation.accepted,lead.addedand the campaign events for those. - Merges. Subscribe to
contact.mergedto retire the losing record.
To reconcile anything a webhook did not carry, read the contact with GET /api/v1/contacts.
Setup
- In your automation tool, create a flow with a webhook trigger. Copy its URL.
- Subscribe Crispy to both events:
The MCP toolcurl -X POST https://crispy.sh/api/v1/webhooks \ -H "Authorization: Bearer crispy_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "url": "https://hook.us2.make.com/your-make-webhook-id", "events": ["contact.created", "contact.updated"] }'create_webhooktakes the same arguments. - Verify the signature with the HMAC verification snippet and skip any
Webhook-Event-Idyou have already processed. Crispy retries failed deliveries with the same ID. - Upsert the CRM record. Search by
identifiers.external_ids(or email), update the match, otherwise create it and write the CRM ID back to Crispy withupsert_leadandexternal_ids. That write-back changesexternal_ids, so expect onecontact.updatedfor it and ignore updates whose only changed field isexternal_idsif you do not need them.
Sample payloads
{
"payload_version": "1",
"id": "00000000-0000-0000-0000-000000000991",
"event": "contact.created",
"timestamp": "2026-10-13T09:15:02.000Z",
"webhook_id": "00000000-0000-0000-0000-0000000009h3",
"account_id": null,
"data": {
"identifiers": {
"crispy_id": "contact_00000000000000000009c3",
"linkedin_url": "https://www.linkedin.com/in/sam-rivera-example",
"linkedin_provider_id": "ACoAAB9c3Sam",
"member_id": null,
"email": null,
"external_ids": {}
},
"name": "Sam Rivera",
"first_name": "Sam",
"last_name": "Rivera",
"headline": "Head of Growth at Example Co",
"company_name": "Example Co",
"connection_status": "connected",
"tags": [],
"custom_attrs": {},
"contact_id": "00000000-0000-0000-0000-0000000009c3",
"account_id": "00000000-0000-0000-0000-0000000009a1",
"source": "connection_sync",
"created_at": "2026-10-13T09:15:01.000Z"
}
}{
"payload_version": "1",
"id": "00000000-0000-0000-0000-000000000992",
"event": "contact.updated",
"timestamp": "2026-10-13T11:40:12.000Z",
"webhook_id": "00000000-0000-0000-0000-0000000009h3",
"account_id": null,
"data": {
"identifiers": {
"crispy_id": "contact_00000000000000000009c3",
"linkedin_url": "https://www.linkedin.com/in/sam-rivera-example",
"linkedin_provider_id": "ACoAAB9c3Sam",
"member_id": null,
"email": "[email protected]",
"external_ids": { "hubspot_contact_id": "hs-991" }
},
"name": "Sam Rivera",
"headline": "VP Growth at Example Co",
"company_name": "Example Co",
"tags": ["q4-target"],
"custom_attrs": {},
"contact_id": "00000000-0000-0000-0000-0000000009c3",
"account_id": "00000000-0000-0000-0000-0000000009a1",
"source": "upsert_lead",
"changed_fields": ["headline", "email", "tags"],
"updated_at": "2026-10-13T11:40:11.000Z"
}
}