Back to Help Center

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.

Still stuck? Email [email protected] or browse answered questions.