The inbound lead webhook
What this page is — the API contract for creating leads from outside the application: the endpoint, the payload, and what happens after a lead arrives.
What it is for — wiring a website form, a landing page or a partner feed into Pulse so enquiries become leads without anybody typing them in.
The problem it solves — knowing which fields matter. A minimal request works, but omitting the source or the pipeline changes where the lead lands and whether reports can attribute it. This page says what to send and what happens to what you leave out.
Endpoint: POST /api/v1/webhooks/leads
Authentication: an API key created on the Webhooks tab
Permission to manage keys: Create/delete API keys · to view keys and logs: View API keys and logs
1. What it is, and what it is not
| Inbound webhook | Marketing form | CSV import | |
|---|---|---|---|
| Caller | Any system with an API key | The Orbit form builder | A person with a file |
| Auth | API key | None — public form | Session |
| De-duplicates | Yes | Yes | No |
| Runs assignment | Yes | Yes | Yes |
| Runs scoring | No | No | No |
| Sets pipeline and status | If supplied | From the form's defaults | No |
The webhook looks up an existing lead by email, phone or external_id before creating one, and
increments submission_count on a repeat instead of inserting a duplicate. Neither the CSV import nor
POST /leads does this — see lead import.
2. The request
{
"full_name": "Marion Ashgrove",
"phone": "+44 7700 900118",
"company_name":"Ashgrove Diagnostics",
"job_title": "Director of Operations",
"source_id": "8479ad7a-bc44-4a02-97c6-9ebdfc24b32d",
"pipeline_id": "22222222-2222-2222-2222-222222222222",
"status_id": "a7e3e5c1-441b-488f-9192-bd386024b573",
"custom_fields": { "industry": "Healthcare", "is_decision_maker": true },
"utm_source": "google",
"utm_campaign":"q3-diagnostics",
"consent_email": true,
"external_id": "crm-9912",
"update_if_exists": true
}
Required
A name (full_name, or first_name and last_name), and either an email or a phone. A
request with neither contact handle is rejected.
Worth setting explicitly
| Field | Why |
|---|---|
source_id | Otherwise the lead has no source and Acquisition reports cannot attribute it |
pipeline_id and status_id | Optional. Omit them and the project's default pipeline is used |
custom_fields | Must be a JSON object, see the danger below |
external_id | Lets you reconcile and de-duplicate against your own record id |
update_if_exists | On a duplicate, updates the existing lead rather than only counting the submission |
Stamped server-side, never accepted from the caller
consent_timestamp is set by the server when any consent flag arrives. A compliance record must not
depend on the caller's clock, so sending it has no effect.
custom_fields must be a JSON object, not text containing JSONMany integration platforms stringify nested JSON by default. Send the object:
"custom_fields": { "industry": "Healthcare" }
not
"custom_fields": "{\"industry\":\"Healthcare\"}"
The second form is rejected with "custom_fields must be a JSON object", so you will see the problem straight away rather than discovering later that no rule matches.
3. Consent
| Field | Type |
|---|---|
consent_email | boolean |
consent_sms | boolean |
consent_whatsapp | boolean |
consent_source | free text — where consent was captured |
These are pointers server-side, so an explicit false is distinguishable from an omitted field. Send
false when consent was refused; omit when it was never asked.
4. What happens on arrival
Note what is absent from that diagram: scoring. A lead arriving by webhook has a score of 0 until somebody runs a recalculate. See status, grade and score.
Omit them and the lead is given the project's default pipeline and its first status, so it still appears on the board. Send them explicitly when the lead belongs somewhere other than the default.
5. The admin contract
| Must exist first | Or else |
|---|---|
| An API key | Every request is rejected |
A lead source you can name in source_id | The lead has no attribution |
| A pipeline and a status | Not required — the project default is used |
| Custom field definitions matching the keys you send | Requests naming an unknown key are rejected |
| Assignment rules, if you want automatic routing | The lead arrives unowned |
6. Downstream
| A webhook lead reaches | How |
|---|---|
| The leads list and board | Immediately |
| An owner | Automatically, if an assignment rule matches |
| A queue | If a rule routes it to one |
| Acquisition reports | Through the lead's source and its UTM fields |
| A contact or deal | Only through conversion |
7. Don't confuse this with…
| This | Not this |
|---|---|
POST /api/v1/webhooks/leads — inbound, API key | POST /api/v1/org/marketing/leads — session, no de-duplication |
| The Webhooks tab's Test button | The webhook logs, which record what actually arrived |
| Webhook logs | The lead's activity timeline |
8. Troubleshooting
| Symptom | Cause |
|---|---|
| 401 or 403 | API key missing, revoked or inactive |
| Rejected with a validation error | No name, or neither email nor phone |
| Lead is on an unexpected pipeline | None was sent, so the project default was used. Section 4 |
| Request rejected, custom_fields | Sent as text containing JSON rather than an object. Section 2 |
| Score lower than expected | A rule may have changed since the lead arrived — run Recalculate |
| Repeat submissions create no new lead | Correct — de-duplication is working. Check submission_count |
| Score lower than expected after a rule change | Run Recalculate to apply new rules to existing leads |