Setting up webhooks
Webhooks push events from Crispy to your systems in real time, signed so you can verify authenticity.
Creating a webhook
Use 'create_webhook' with an HTTPS URL and the events you want. The response includes a signing secret. Save it, you need it to verify deliveries.
- 'list_webhooks' shows every webhook with its URL, events, and enabled status
- 'update_webhook' changes the URL, events, or enabled flag
- 'test_webhook' fires a test payload and returns the delivery status code
- 'get_webhook_deliveries' shows recent attempts with status codes, errors, and the retry schedule
- 'delete_webhook' removes one
Verifying signatures
Every delivery carries a Webhook-Signature header in the form v1,t=<timestamp>,s=<hex>. The signature is HMAC-SHA256 over the string v1.<timestamp>.<raw body> using your signing secret. Compute the digest over the raw request body, not re-serialized JSON, and compare with a timing-safe check.
Deduplication
Retries reuse the same Webhook-Event-Id header. Store processed event IDs and skip duplicates. The top-level id field in the payload matches this header.
Handling message.received
message.received fires for every message in a chat, including replies the account owner sends themselves from the LinkedIn app or another device. Branch on data.direction or data.is_sender: process inbound messages, acknowledge and skip outbound ones.
Event examples
- message.received and invitation.accepted for inbox and outreach flows
- contact.connection_status_changed when someone becomes a connection
- campaign.started, campaign.paused, campaign.completed for campaign lifecycle
- lead.added and contact.added_to_list for CRM sync
Payloads use a stable format: payload_version, event name, timestamp, and a data block with identifiers (Crispy ID, LinkedIn URL, email) plus curated fields, never raw database rows.