Alpha: the Chrome Web Store listing is still in review. Download the extension and load it unpacked. Download for Chrome
Skip to documentation

Webhooks

When an export finishes, Listful can POST rows to destinations you configure. Sign in, add a destination, choose batch or one row, test.

Setup

Sign in, open /settings, add a destination (HTTPS URL), choose a mode and surfaces, then send a test. You can pause a destination without deleting it. Up to eight destinations per account.

Modes

Batch — one JSON body with a rows array (chunked under 1 MB). Use for n8n, Make, or your own server.

One row — one POST per person with flat fields. Use for Clay, where each webhook submission becomes one table row.

Request

We send POST with Content-Type: application/json. Respond 2xx to acknowledge. Delivery is queued when the export finishes, then retried on a schedule if your endpoint fails.

Method
POST
Content-Type
application/json
Event header
X-Listful-Event
Signature
X-Listful-Signature
Idempotency
Idempotency-Key
Timeout
8–10s
Retries
1m → 5m → 30m → 2h
Replay
7 days from Settings

Retries

Transient failures (network, 408, 429, 5xx) retry on the schedule above. Permanent failures (other 4xx, redirects) stop immediately. Listful never emails on webhook failure. Make handlers idempotent on Idempotency-Key (jobId:chunkIndex or jobId:rowIndex). Replay stops working once the stored payload has been purged after 7 days, and the delivery ends as payload_expired.

Batch payload

application/json
{
  "event": "export.completed",
  "jobId": "8c4f1b9a-0ed2-4e5d-b317-f5e9b08a4c11",
  "surfaceType": "search-people",
  "sourceUrl": "https://www.linkedin.com/search/results/people/?keywords=product%20design",
  "rowCount": 2,
  "stopReason": "done",
  "partial": false,
  "exportedAt": "2026-09-30T12:00:00.000Z",
  "chunkIndex": 0,
  "chunkCount": 1,
  "rows": [
    {
      "profile_url": "https://www.linkedin.com/in/averyparker/",
      "full_name": "Avery Parker",
      "headline": "VP Sales @ Helix Robotics",
      "location": "San Francisco, California, US"
    }
  ]
}
FieldTypeDescription
eventstringexport.completed for batch. Check this first.
jobIdstringExport job id. Use with chunkIndex for idempotency.
surfaceTypeenumsearch-people, sales-search-people, post-reactions, post-comments, connections, group-members, event-attendees, company-employees.
sourceUrlstringThe LinkedIn URL the user clicked Export on.
rowCountnumberTotal rows in the export (all chunks).
stopReasonstringdone, cancelled, cap_daily, and related stop codes.
partialbooleanTrue when stopReason is not done.
exportedAtstringISO timestamp when the payload was stored.
chunkIndexnumber0-based chunk index.
chunkCountnumberTotal chunks for this destination.
rowsobject[]Columnar rows matching the CSV for that surface.

Row payload

application/json
{
  "event": "export.row",
  "jobId": "8c4f1b9a-0ed2-4e5d-b317-f5e9b08a4c11",
  "surfaceType": "search-people",
  "sourceUrl": "https://www.linkedin.com/search/results/people/?keywords=product%20design",
  "rowCount": 240,
  "rowIndex": 0,
  "stopReason": "done",
  "partial": false,
  "exportedAt": "2026-09-30T12:00:00.000Z",
  "profile_url": "https://www.linkedin.com/in/averyparker/",
  "full_name": "Avery Parker",
  "headline": "VP Sales @ Helix Robotics",
  "location": "San Francisco, California, US"
}
FieldTypeDescription
eventstringAlways export.row.
rowIndexnumber0-based index in the export.
profile_url / full_name / …stringCSV columns for that surface, flattened onto the object.

Full header list by surface: CSV columns.

Signing

Every request includes X-Listful-Signature: t={timestamp},v1={hmac}— HMAC-SHA256 of timestamp + "." + rawBody with your secret. Compare with a timing-safe equal. Use the raw body.

Node.js
// Node.js
const crypto = require('crypto');
const header = req.headers['x-listful-signature']; // t=…,v1=…
const parts = Object.fromEntries(
  header.split(',').map((p) => p.trim().split('='))
);
const expected = crypto
  .createHmac('sha256', process.env.LISTFUL_SECRET)
  .update(`${parts.t}.${rawBody}`)
  .digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected))) {
  return res.status(401).end();
}

Examples

n8n

Webhook node → Split Out on rows[]. Verify X-Listful-Signature in a Code node when you want it. Use Batch mode.

Make.com

Custom webhook → Iterator on rows[]. Bodies stay under 1 MB per chunk (Make caps at 5 MB). Use Batch mode.

Clay

Monitor webhook → One row mode. Each person is one POST and one Clay row. Map profile_url as the unique column. Optional auth header for Clay’s token. Clay limits submissions per webhook URL.

Your server

Express, FastAPI, Hono. Verify the signature, then insert. No SDK.

Need to set this up? Sign in, add a destination, send a test.

Configure webhook