Webhook & CRM integration
When a creditor chooses your agency, we can POST the lead straight into your CRM at the same moment it lands in your dashboard and inbox. One JSON payload, one endpoint, no polling.
Setting it up
- Create an endpoint that accepts a JSON
POSTover HTTPS. Most CRMs have an inbound-webhook or “catch hook” feature; Zapier (Webhooks by Zapier → Catch Hook) and Make (Custom webhook) both work out of the box if yours doesn’t. - Configure it in your dashboard — Profile → Webhook: tick Enable webhook, paste your URL, set the auth header (see Authentication) and press Save profile.
- Press “Send test webhook” on the same tab. We fire a clearly-marked sample lead (
event: "lead.test") at your saved settings and show you your endpoint’s response code. - Map the fields into your CRM using the reference below, keyed on
lead.id.
When it fires
You receive one POST per lead, at the moment the lead is assigned to you:
- a creditor compares the panel and chooses your agency, or
- Collect Compare reassigns an existing case to you (for example, when another agency couldn’t act on it).
The webhook is a mirror of the lead you’re also sent by email and shown in your dashboard — same data, machine-readable.
The payload
A single JSON object, sent with content-type: application/json:
{
"version": 2,
"event": "lead.assigned",
"lead": {
"id": 4182,
"created_at": "2026-07-19T09:41:22.310Z",
"status": "Active",
"compare_or_match": "compare",
"debt": {
"amount_pence": 745000,
"amount_gbp": 7450,
"purpose": "unpaid_invoice",
"ccj_status": "no",
"description": "Three unpaid invoices from a wholesale customer, oldest is 5 months overdue."
},
"location": {
"postcode": null,
"region": "North West"
},
"creditor": {
"name": "Jane Example",
"email": "[email protected]",
"phone": "07123456789",
"address": null
}
}
} Field reference
Any field can be null where marked — build your import to tolerate that.
| Field | Type | Meaning |
|---|---|---|
version | integer | Payload contract version. Currently 2 — only bumped for breaking changes. |
event | string | "lead.assigned" for real leads. "lead.test" for test fires from your dashboard. |
test | boolean | Present (and true) only on test fires. Real leads never carry this field. |
lead.id | integer | Our unique lead reference — use it as your upsert key. 0 on test fires. |
lead.created_at | string | ISO 8601 UTC timestamp of when the creditor made their enquiry. |
lead.status | string | Lead status at the moment of delivery (currently always "Active"). |
lead.compare_or_match | string | null | "compare" — the creditor compared the panel and picked you. "match" — they asked to be matched. |
lead.debt.amount_pence | integer | null | Total debt in pence (all debts combined). Null if the creditor didn’t give a figure. |
lead.debt.amount_gbp | number | null | The same figure in pounds, for convenience. |
lead.debt.purpose | string | null | One of "unpaid_invoice", "commercial_rent", "residential_rent", "other". |
lead.debt.ccj_status | string | null | Whether a CCJ already exists: "yes", "no" or "unsure". |
lead.debt.description | string | null | The creditor’s own free-text description of the situation, when they gave one. Genuinely useful first-call context. |
lead.location.postcode | string | null | Debtor postcode. Usually null — we no longer ask for it. |
lead.location.region | string | null | UK region of the debtor (e.g. "North West"). May be "Unknown". |
lead.creditor.name | string | null | The creditor’s name — your new client. |
lead.creditor.email | string | null | Creditor email address. |
lead.creditor.phone | string | null | Creditor phone number (UK format). |
lead.creditor.address | string | null | Creditor address, when captured. |
Authentication
Set an auth header in your dashboard so your endpoint can reject anything that isn’t from us:
- Bearer token (recommended): set the header type to
Bearerand the value to a long random secret. We sendAuthorization: Bearer <your secret>with every delivery. - Custom scheme: any other header type
Xwith valueVis sent asAuthorization: X: V. - Leave both blank and no
Authorizationheader is sent — fine for catch-hook URLs that are themselves secret, but a token is better.
Verify the header on every request and respond 401 to anything that doesn’t match. Your token is stored securely and never shown again after saving — leave the field blank when saving other changes to keep the existing one.
Delivery behaviour
- One attempt, no retries. If your endpoint is down or slow, the delivery is not re-tried — but you still have the lead: the email notification and your dashboard are the canonical channels, and both are unaffected.
- Respond fast with a 2xx. We record your response code but ignore the response body. Do any heavy processing after acknowledging.
- Delivery results are logged against the lead on our side, so if your CRM ever misses one we can tell you exactly what your endpoint returned.
- Order isn’t guaranteed and, as with any webhook, build your import as an upsert on
lead.idso a duplicate delivery can never create a duplicate record.
Testing
The Send test webhook button in your dashboard fires this at your saved settings — identical shape to a real lead, but marked so you can’t mistake it for one: event is "lead.test", a top-level test: true is present, and lead.id is 0.
To exercise your endpoint locally before saving anything, replay the same shape with cURL:
curl -X POST https://your-crm.example.com/webhooks/collect-compare \
-H 'content-type: application/json' \
-H 'authorization: Bearer YOUR_TOKEN' \
-d '{"version":2,"event":"lead.test","test":true,"lead":{"id":0,"created_at":"2026-07-19T09:00:00.000Z","status":"Active","compare_or_match":"compare","debt":{"amount_pence":745000,"amount_gbp":7450,"purpose":"unpaid_invoice","ccj_status":"no","description":"Sample only"},"location":{"postcode":null,"region":"North West"},"creditor":{"name":"Test Creditor (webhook test)","email":"[email protected]","phone":"07000000000","address":null}}}' Example receiver
// Node / Express example
app.post('/webhooks/collect-compare', (req, res) => {
// reject anything without your secret
if (req.get('authorization') !== `Bearer ${process.env.CC_WEBHOOK_TOKEN}`) {
return res.sendStatus(401);
}
const { event, lead } = req.body;
if (event === 'lead.test') return res.sendStatus(200); // test fire — nothing to import
// upsert into your CRM keyed on lead.id, then acknowledge
importLead(lead);
res.sendStatus(200);
}); Data protection
The payload contains the creditor’s personal contact details, shared with you solely for this introduction under our agency terms and privacy policy. If a lead is ever reassigned away from you, we’ll email you asking you to delete the creditor’s details from your systems — that includes whatever your webhook imported into your CRM.
Questions, or need a hand wiring it up?
Email [email protected] and we’ll help you get connected. Not listed yet?