Webhook events reference

Every event Funkel can send, payload shape, and when each one fires.

Funkel can push events to any HTTPS endpoint you control. Each event is an HTTP POST with a JSON body and a signed header. This page is the canonical list of events and their payloads.

Envelope

Every event shares the same outer shape:

{
  "event": "lead.discovered",
  "timestamp": "2026-05-04T12:34:56Z",
  "data": { /* event-specific fields */ }
}

Headers

  • Content-Type: application/json
  • X-LeadPilot-Event: the event name (e.g. lead.discovered)
  • X-LeadPilot-Signature: sha256=<hex>, see Verifying webhook signatures

Note · The signature header still uses the legacy LeadPilot prefix while we finish the rename to Funkel. Match on the header name; don’t hard-code “Funkel” in a prefix check.

Events

lead.discovered

An agent has found a lead matching one of its signals.

{
  "lead_id":     "uuid",
  "agent_id":    "uuid",
  "agent_name":  "Founders posting about Outreach",
  "first_name":  "Mira",
  "last_name":   "Jensen",
  "company":     "Acme",
  "headline":    "Head of GTM at Acme",
  "profile_url": "https://www.linkedin.com/in/mira-jensen",
  "signal_key":  "competitor_post_engagement"
}

lead.approved

A discovered lead has been approved into a campaign (manual or auto).

{
  "lead_id":     "uuid",
  "campaign_id": "uuid",
  "approved_at": "2026-05-04T12:34:56Z"
}

action.executed

A scheduled workflow action (invite, message, follow-up) has been sent.

{
  "action_id":   "uuid",
  "action_type": "message",
  "lead_id":     "uuid",
  "campaign_id": "uuid"
}

reply.received

A lead has replied to one of your campaigns. Fires once per lead, on the first reply.

{
  "lead_id":         "uuid",
  "campaign_id":     "uuid",
  "conversation_id": "uuid",
  "first_name":      "Mira",
  "last_name":       "Jensen",
  "message_preview": "Sure, 15 min Thursday works…"
}

message.received

An incoming message landed on a connected LinkedIn sender (any message, including from leads not in your campaigns).

{
  "conversation_id":     "uuid",
  "lead_id":             "uuid | null",
  "campaign_id":         "uuid | null",
  "sender_name":         "Mira Jensen",
  "sender_provider_id":  "ACoAA...",
  "message":             "...",
  "is_first_reply":      true
}

campaign.completed

Every lead in a campaign has reached a terminal state (replied, exhausted workflow, or canceled).

campaign.paused

A campaign has been paused, manually or by the system.

Delivery and retries

Webhooks are best-effort. Funkel attempts delivery once with a 10-second timeout. Non-2xx responses are logged but not retried in v1. Make your endpoint idempotent, process by data.lead_id or data.action_id, and you’ll be safe even if delivery is occasionally repeated in future versions.