Outbound webhooks

Get Pipeline events as they happen

Send signed, versioned events to your CRM, warehouse, automations, or agent runtime. Each endpoint subscribes to an explicit set of events and can optionally filter campaign activity.

API version 2026-08-17At-least-once deliveryHMAC-SHA256 signatures

Quickstart

  1. 1. Add an endpoint. Open Settings, then Webhooks, and enter a public HTTPS URL.
  2. 2. Store the signing secret. Pipeline reveals the whsec_ secret once.
  3. 3. Select events. Subscriptions are explicit, so future event types are never added without your approval.
  4. 4. Send a test. Return any 2xx response after verifying the signature against the exact raw body.
Example eventjson
{
"id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
"type": "linkedin.reply.received",
"api_version": "2026-08-17",
"timestamp": "2026-08-17T15:04:05.000Z",
"workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
"data": {
"object": {
"id": "reply_123",
"prospect_id": "prospect_123",
"conversation_id": "conversation_123",
"body": "Interested. Can you send over times?",
"body_truncated": false,
"first_reply": true
},
"context": {
"campaign_id": "campaign_123"
},
"actor": {
"type": "system"
}
}
}

Verify every signature

Pipeline signs webhook-id.webhook-timestamp.raw-request-body. Reject stale timestamps, compare signatures in constant time, and do not parse or reserialize the body before verification.

Node.js verificationtypescript
import { createHmac, timingSafeEqual } from 'node:crypto'
 
const secret = process.env.PIPELINE_WEBHOOK_SECRET!
const rawBody = await request.text()
const id = request.headers.get('webhook-id')!
const timestamp = request.headers.get('webhook-timestamp')!
const signatures = request.headers.get('webhook-signature')!.split(' ')
const timestampSeconds = Number(timestamp)
if (!Number.isFinite(timestampSeconds) || Math.abs(Date.now() / 1000 - timestampSeconds) > 300) {
throw new Error('Stale webhook timestamp')
}
const key = Buffer.from(secret.replace('whsec_', ''), 'base64')
const expected = createHmac('sha256', key)
.update(`${id}.${timestamp}.${rawBody}`)
.digest('base64')
const expectedBytes = Buffer.from(expected)
 
const valid = signatures.some((signature) => {
const receivedBytes = Buffer.from(signature.replace('v1,', ''))
return receivedBytes.length === expectedBytes.length && timingSafeEqual(receivedBytes, expectedBytes)
})
if (!valid) {
throw new Error('Invalid webhook signature')
}
webhook-id
Stable event ID. Use it for deduplication.
webhook-timestamp
Unix timestamp used by the signature.
webhook-signature
One or more space-separated v1 signatures during rotation.
Pipeline-Event-Type
Convenience header containing the event type.

Delivery behavior

Success and retries

Only 2xx responses succeed. After the first attempt, retries are scheduled around 5 seconds, 5 minutes, 30 minutes, 2 hours, 5 hours, 10 hours, 14 hours, 20 hours, and 24 hours, with ±10% jitter. Valid Retry-After values are respected up to 24 hours.

Idempotency

Delivery is at least once and ordering is not guaranteed. Deduplicate with the event id or webhook-id.

Timeouts and redirects

Requests time out after 15 seconds. Redirects are not followed and count as failures.

Endpoint health

HTTP 410 pauses an endpoint immediately. Repeated failures can auto-pause it. Resume after fixing the destination to wake due deliveries.

Event catalog

Pipeline publishes compact snapshots of durable business outcomes. Events marked planned document the stable contract but cannot be selected until their authoritative producer ships. Payloads never include credentials, raw provider payloads, prompts, or arbitrary table columns.

Campaigns6
campaign.created
Planned · Campaign filter
Campaign created

A campaign was created.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "campaign.created",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "campaign_123",
      "name": "Founder outreach",
      "status": "draft"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
campaign.started
Available · Campaign filter
Campaign started

A campaign began execution.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "campaign.started",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "campaign_123",
      "name": "Founder outreach",
      "status": "active"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
campaign.paused
Available · Campaign filter
Campaign paused

A campaign was paused.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "campaign.paused",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "campaign_123",
      "name": "Founder outreach",
      "status": "paused"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
campaign.resumed
Available · Campaign filter
Campaign resumed

A paused campaign resumed.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "campaign.resumed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "campaign_123",
      "name": "Founder outreach",
      "status": "active"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
campaign.completed
Available · Campaign filter
Campaign completed

A campaign completed all terminal work.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "campaign.completed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "campaign_123",
      "name": "Founder outreach",
      "status": "completed"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
campaign.failed
Planned · Campaign filter
Campaign failed

A campaign entered a terminal failed state.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "campaign.failed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "campaign_123",
      "name": "Founder outreach",
      "status": "failed",
      "failure_code": "sender_unavailable"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
LinkedIn6
linkedin.connection_request.sent
Planned · Campaign filter
Connection request sent

LinkedIn confirmed a connection request send.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.connection_request.sent",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "action_123",
      "action": "connection_request",
      "prospect_id": "prospect_123",
      "campaign_id": "campaign_123"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
linkedin.connection.accepted
Planned · Campaign filter
Connection accepted

A LinkedIn connection acceptance was persisted.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.connection.accepted",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "connection_123",
      "prospect_id": "prospect_123",
      "campaign_id": "campaign_123"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
linkedin.message.sent
Planned · Campaign filter
Message sent

LinkedIn confirmed a direct message send.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.message.sent",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "action_124",
      "action": "message",
      "prospect_id": "prospect_123",
      "campaign_id": "campaign_123"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
linkedin.inmail.sent
Planned · Campaign filter
InMail sent

LinkedIn confirmed an InMail send.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.inmail.sent",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "action_125",
      "action": "inmail",
      "prospect_id": "prospect_123",
      "campaign_id": "campaign_123"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
linkedin.reply.received
Available · Campaign filter
Reply received

A LinkedIn reply was persisted.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.reply.received",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "reply_123",
      "prospect_id": "prospect_123",
      "conversation_id": "conversation_123",
      "body": "Interested. Can you send over times?",
      "body_truncated": false,
      "first_reply": true
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
linkedin.action.failed
Planned · Campaign filter
LinkedIn action failed

A LinkedIn action reached a terminal failure.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.action.failed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "action_126",
      "action": "message",
      "prospect_id": "prospect_123",
      "campaign_id": "campaign_123",
      "error_code": "provider_rejected"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
LinkedIn accounts2
linkedin.account.disconnected
Planned
LinkedIn account disconnected

A connected LinkedIn account became unavailable.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.account.disconnected",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "account_123",
      "name": "Founder account",
      "status": "disconnected",
      "reason": "credentials_expired"
    },
    "actor": {
      "type": "system"
    }
  }
}
linkedin.account.reconnected
Planned
LinkedIn account reconnected

A disconnected LinkedIn account returned to ready.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "linkedin.account.reconnected",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "account_123",
      "name": "Founder account",
      "status": "connected"
    },
    "actor": {
      "type": "system"
    }
  }
}
Replies1
reply.classified
Available · Campaign filter
Reply classified

Pipeline persisted a reply intent classification.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "reply.classified",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "classification_123",
      "conversation_id": "conversation_123",
      "prospect_id": "prospect_123",
      "classification": "interested"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
Prospects2
prospect.enrolled
Planned · Campaign filter
Prospect enrolled

A prospect was added to a campaign.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "prospect.enrolled",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "prospect_123",
      "campaign_id": "campaign_123",
      "linkedin_url": "https://www.linkedin.com/in/example"
    },
    "context": {
      "campaign_id": "campaign_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
prospect.stage.changed
Available
Prospect stage changed

A prospect changed canonical conversion stage.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "prospect.stage.changed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "prospect_123",
      "stage": "meeting_booked"
    },
    "previous_attributes": {
      "stage": "interested"
    },
    "actor": {
      "type": "system"
    }
  }
}
Meetings1
meeting.booked
Available
Meeting booked

A meeting booking was persisted and linked.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "meeting.booked",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "meeting_123",
      "prospect_id": "prospect_123",
      "campaign_id": "campaign_123",
      "starts_at": "2026-08-20T14:00:00.000Z"
    },
    "actor": {
      "type": "system"
    }
  }
}
Workflow runs4
workflow.run.started
Available
Workflow run started

A workflow run entered running.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "workflow.run.started",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "run_123",
      "workflow_id": "workflow_123",
      "name": "ICP outbound",
      "status": "running"
    },
    "context": {
      "workflow_run_id": "run_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
workflow.run.completed
Available
Workflow run completed

A workflow run completed successfully.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "workflow.run.completed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "run_123",
      "workflow_id": "workflow_123",
      "name": "ICP outbound",
      "status": "completed"
    },
    "context": {
      "workflow_run_id": "run_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
workflow.run.failed
Available
Workflow run failed

A workflow run failed terminally.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "workflow.run.failed",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "run_123",
      "workflow_id": "workflow_123",
      "name": "ICP outbound",
      "status": "failed"
    },
    "context": {
      "workflow_run_id": "run_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
workflow.run.awaiting_approval
Available
Workflow awaiting approval

A workflow run stopped at an approval gate.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "workflow.run.awaiting_approval",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "run_123",
      "workflow_id": "workflow_123",
      "name": "ICP outbound",
      "status": "awaiting_approval"
    },
    "context": {
      "workflow_run_id": "run_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
Approvals2
approval.required
Available
Approval required

A human approval item was created.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "approval.required",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "approval_123",
      "subject_type": "workflow_run",
      "subject_id": "run_123",
      "status": "required"
    },
    "context": {
      "workflow_run_id": "run_123"
    },
    "actor": {
      "type": "system"
    }
  }
}
approval.resolved
Available
Approval resolved

A human approval item was approved, rejected, or canceled.

API version 2026-08-17
Example payload
{
  "id": "7b60d0cb-b735-4a8c-9c30-4180ab1c98d5",
  "type": "approval.resolved",
  "api_version": "2026-08-17",
  "timestamp": "2026-08-17T15:04:05.000Z",
  "workspace_id": "39dba13f-6246-4b14-a310-a6710aa53009",
  "data": {
    "object": {
      "id": "approval_123",
      "subject_type": "workflow_run",
      "subject_id": "run_123",
      "status": "approved"
    },
    "context": {
      "workflow_run_id": "run_123"
    },
    "actor": {
      "type": "system"
    }
  }
}

Management API

Webhook operations use the same bearer authentication and workspace permissions as the rest of the Pipeline API. Each operation below links to its typed parameters and response schemas.

Manual redelivery requires an Idempotency-Key header so a retried API request cannot enqueue the same redelivery twice.

Troubleshooting

Signature verification fails
Read the raw request body exactly once, use the unmodified bytes, and verify every space-separated v1 signature during secret rotation.
Deliveries keep retrying
Return a 2xx response within 15 seconds. Inspect the delivery timeline for the normalized error and HTTP status, then redeliver after correcting the receiver.
Endpoint was paused
HTTP 410 pauses immediately. Repeated failures can also auto-pause after the failure window. Fix the destination, then resume the endpoint in Settings.
Duplicate events
Delivery is at least once. Deduplicate using the stable event id or webhook-id header.
Webhooks | Pipeline