Send leads in from your own systems or a partner's, and read what became of them: where each lead is now, and a feed of what has happened to them.
These need a server-only application with the crm scope. An application only sees the leads it sent. The guide
Send leads and read what happened to them
walks through it.
Send a lead
POST
https://subcontext.com/api/v1/crm/ingests
Try it
Token scopes:
write and crm
Sends a lead: who the person is (identity), what you know about
them, and where they came from. Server-only applications.
The answer is 202 Accepted. Subcontext has stored the lead, and works out who it's about and reads it in the background. Poll
What became of a lead
(the Location header has its address) to see how that went.
The body is open. data takes any JSON your system has, and Subcontext reads it. Values you want stored exactly as
given go in declared. You need at least one of data, text,
declared or identity.
Idempotency: send an Idempotency-Key header (your own record's
id is ideal). The same key again within 10 minutes gives back the
first answer, with an Idempotent-Replay: true header. After that it still never makes a second lead (duplicate is true). The same
content from the same source within 5 minutes is also treated as a
retry.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| Idempotency-Key | header | string | A value unique to this request in your system, so a retry doesn't do it twice. |
Request body application/json
| Field | Type | Description |
|---|---|---|
| source required | string |
Your system's name, such as |
| campaign | string |
The key of the campaign the lead is for (in the dashboard, under CRM, Campaigns). Without it, only your organisation-wide rules apply. |
| identity | object |
Who the person is. Any of |
| data | object |
Anything else you know, in any shape. Subcontext reads it. |
| text | string |
Free text about the lead (a message, notes), read the same way. |
| declared | object |
Values stored exactly as you give them, by field key, never interpreted. Values must be plain (not nested objects). |
| consent | object |
What the person agreed to, as your form recorded it: for
example |
| context | object |
What you know about the person's visit, such as |
| provenance | ProvenanceInput |
Where the customer was when they filled it in, for your reports on
what brings people in: |
| occurred_at | string (date-time) |
When the lead happened, if not now (ISO 8601). |
| source_reference | string |
Your own reference for this lead, shown back to you. |
{
"source": "my_website",
"campaign": "spring-life-2026",
"identity": {
"first_name": "Ada",
"last_name": "Lovelace",
"email": "ada@example.com",
"phone": "07700 900123"
},
"data": {
"cover_wanted": 250000,
"reason": "New mortgage"
},
"consent": {
"service": {
"email": true,
"phone": true
},
"method": "web_form"
},
"provenance": {
"page_url": "https://www.example.com/life?utm_source=newsletter&utm_campaign=spring"
},
"source_reference": "web-12345"
}
Responses
202 The lead is stored and processed in the background. Poll its address (in the `Location` header) for what became of it.
| Field | Type | Description |
|---|---|---|
| data required | Ingest |
A lead you sent, and what became of it. Fields with nothing to say are left out. |
| data.id required | string (uuid) | |
| data.status required | string |
"received", "resolving", "extracting", "applied", "needs_review", "deferred", "failed", "discarded", "held"
|
| data.source required | string | |
| data.source_reference | string |
Your reference, if you sent one. |
| data.received_at required | string (date-time) | |
| data.processed_at | string (date-time) |
When it was finished with. |
| data.contact_id | string (uuid) |
The lead it was applied to. Use it with Get a lead. |
| data.facts_written required | integer |
How many facts about the person were recorded. |
| data.fields_proposed required | integer |
How many values were put to your team because they differ from what's held. |
| data.activities_written required | integer | |
| data.truncated required | boolean |
Whether the lead was too long to read in full. |
| data.retry_after | string (date-time) |
For a deferred lead, when it carries on. |
| data.error | string |
Why it was deferred or failed. |
| data.validation_failures | array of object |
For a held lead, which of the campaign's rules it didn't meet, in your field names. |
| data.validation_failures[].field required | string | |
| data.validation_failures[].rule required | string or null | |
| data.validation_failures[].reason required | string or null | |
| data.provenance | object |
Where the lead was captured, as Subcontext understood it from your |
| data.explanation required | string |
What happened, in words. |
| data.duplicate | boolean |
Only in the answer to Send a lead: |
{
"data": {
"id": "0199a3c2-8100-7411-9d92-162738a9bacb",
"status": "received",
"source": "my_website",
"source_reference": "web-12345",
"received_at": "2026-10-12T10:40:12+01:00",
"facts_written": 0,
"fields_proposed": 0,
"activities_written": 0,
"truncated": false,
"provenance": {
"v": 1,
"captured_at": "2026-10-12T09:40:12Z",
"surface": "api",
"page_url": "https://www.example.com/life?utm_source=newsletter&utm_campaign=spring",
"host": "www.example.com",
"path": "/life",
"utm": {
"source": "newsletter",
"campaign": "spring"
},
"in_iframe": false,
"channel": "my_website"
},
"explanation": "Accepted; working out who this is about.",
"duplicate": false
}
}
401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_token",
"message": "The access token has expired. Ask for a new one."
}
}
403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "forbidden",
"message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
}
}
409 The campaign isn't taking leads (`campaign_paused` or `campaign_archived`). The lead itself may be fine. Send it again when the campaign is active.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "campaign_paused",
"message": "this campaign is not accepting leads"
}
}
422 The lead can never be accepted as sent: - `unknown_campaign`: no campaign with that key in your organisation. - `validation_failed`: the message says what's wrong, for example a missing or malformed `source`, nothing to go on, or more than 256 KB (`fields` names the input, when it's one).
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "validation_failed",
"message": "source is required and must look like 'hubspot_webhook'",
"fields": {
"source": "source is required and must look like 'hubspot_webhook'"
}
}
}
What became of a lead
GET
https://subcontext.com/api/v1/crm/ingests/{id}
Try it
Token scopes:
read and crm or write and crm
Where a lead you sent has got to: still being read, applied to a
contact (contact_id, which is also the lead's id), held by your
campaign's rules, or waiting for a person to decide who it's about.
explanation says it in words. Server-only applications, and
only the application that sent it can see it.
A lead is done when status is applied, needs_review, held,
failed or discarded. Until then, poll every few seconds.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| id required | path | string (uuid) | The ingest's id, from Send a lead. |
Responses
200 The ingest.
| Field | Type | Description |
|---|---|---|
| data required | Ingest |
A lead you sent, and what became of it. Fields with nothing to say are left out. |
| data.id required | string (uuid) | |
| data.status required | string |
"received", "resolving", "extracting", "applied", "needs_review", "deferred", "failed", "discarded", "held"
|
| data.source required | string | |
| data.source_reference | string |
Your reference, if you sent one. |
| data.received_at required | string (date-time) | |
| data.processed_at | string (date-time) |
When it was finished with. |
| data.contact_id | string (uuid) |
The lead it was applied to. Use it with Get a lead. |
| data.facts_written required | integer |
How many facts about the person were recorded. |
| data.fields_proposed required | integer |
How many values were put to your team because they differ from what's held. |
| data.activities_written required | integer | |
| data.truncated required | boolean |
Whether the lead was too long to read in full. |
| data.retry_after | string (date-time) |
For a deferred lead, when it carries on. |
| data.error | string |
Why it was deferred or failed. |
| data.validation_failures | array of object |
For a held lead, which of the campaign's rules it didn't meet, in your field names. |
| data.validation_failures[].field required | string | |
| data.validation_failures[].rule required | string or null | |
| data.validation_failures[].reason required | string or null | |
| data.provenance | object |
Where the lead was captured, as Subcontext understood it from your |
| data.explanation required | string |
What happened, in words. |
| data.duplicate | boolean |
Only in the answer to Send a lead: |
{
"data": {
"id": "0199a3c2-8100-7411-9d92-162738a9bacb",
"status": "applied",
"source": "my_website",
"source_reference": "web-12345",
"received_at": "2026-10-12T10:40:12+01:00",
"processed_at": "2026-10-12T10:40:15+01:00",
"contact_id": "0199a3c2-8200-7522-8ea3-2738a9bacbdc",
"facts_written": 3,
"fields_proposed": 0,
"activities_written": 0,
"truncated": false,
"explanation": "Applied to contact 0199a3c2-8200-7522-8ea3-2738a9bacbdc; 3 fact(s) recorded."
}
}
401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_token",
"message": "The access token has expired. Ask for a new one."
}
}
403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "forbidden",
"message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
}
}
404 There's no such record in your organisation.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "not_found",
"message": "Resource not found"
}
}
List your leads
GET
https://subcontext.com/api/v1/crm/leads
Try it
Token scopes:
read and crm or write and crm
The leads this application sent, and where each is now, oldest change first. A lead that changes comes round again, so this is a feed of what has changed. Server-only applications.
Page through with cursor, as every list in the API does. Pass each page's next_cursor to get the next, and keep the last one to ask
"what's changed since?" next time. A page with fewer than limit
leads is the last for now. To start from a time rather than the
beginning, send updated_since (and no cursor).
Filter by status (one or more, comma separated) and campaign_id.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| status | query | string | Only leads with these outcomes, comma separated (for example
|
| campaign_id | query | string (uuid) | Only leads for this campaign. |
| cursor | query | string | Carry on after the page this came from (its |
| updated_since | query | string (date-time) | Start with the leads changed at or after this time (ISO 8601), instead of from the beginning. Ignored when you send |
| limit | query | integer | How many leads per page, 1 to 200. |
Responses
200 A page of leads.
| Field | Type | Description |
|---|---|---|
| data required | array of Lead |
The leads, oldest change first. |
| data[].contact_id required | string (uuid) |
The lead's id. |
| data[].external_system_id required | string or null |
The lead's id in your organisation's own CRM, if it has one. |
| data[].status required | string |
The lead's outcome so far. One of:"open", "won", "lost", "dormant", "disqualified", "duplicate", "invalid", "not_interested", "ineligible"
|
| data[].terminal required | boolean |
Whether that's final (won, lost, or ruled out). |
| data[].stage required | object | |
| data[].stage.key required | string | |
| data[].stage.name required | string | |
| data[].stage.kind required | string |
One of: "open", "won", "lost"
|
| data[].stage.probability required | integer or null |
The chance of a sale from this stage, as a percentage. |
| data[].stage_entered_at required | string (date-time) | |
| data[].owner_assigned required | boolean |
Whether someone on your team owns it. |
| data[].score required | integer |
How promising the lead is, from 0 to 100. |
| data[].campaign_id required | string or null (uuid) | |
| data[].first_touched_at required | string or null (date-time) |
When your team first contacted them. |
| data[].last_touched_at required | string or null (date-time) | |
| data[].created_at required | string (date-time) | |
| data[].updated_at required | string (date-time) | |
| next_cursor required | NextCursor |
Pass as |
{
"data": [
{
"contact_id": "0199a3c2-8200-7522-8ea3-2738a9bacbdc",
"external_system_id": "CRM-88123",
"status": "won",
"terminal": true,
"stage": {
"key": "won",
"name": "Won",
"kind": "won",
"probability": 100
},
"stage_entered_at": "2026-10-14T16:02:11+01:00",
"owner_assigned": true,
"score": 71,
"campaign_id": "0199a3c2-8300-7633-9fb4-38a9bacbdced",
"first_touched_at": "2026-10-12T10:52:40+01:00",
"last_touched_at": "2026-10-14T16:02:11+01:00",
"created_at": "2026-10-12T10:40:15+01:00",
"updated_at": "2026-10-14T16:02:11+01:00"
}
],
"next_cursor": "MjAyNi0xMC0xNFQxNTowMjoxMS4wMDAwMDBafDAxOTlhM2MyLTgyMDAtNzUyMi04ZWEzLTI3MzhhOWJhY2JkYw"
}
401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_token",
"message": "The access token has expired. Ask for a new one."
}
}
403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "forbidden",
"message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
}
}
422 `invalid_parameter`: `cursor` isn't one the API gave you, `updated_since` isn't an ISO 8601 time, or `status` has a value that isn't a lead status. `fields` names it.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_parameter",
"message": "cursor isn't one this API gave you: pass a page's next_cursor as it came.",
"fields": {
"cursor": "isn't one this API gave you: pass a page's next_cursor as it came"
}
}
}
Get a lead
GET
https://subcontext.com/api/v1/crm/leads/{id}
Try it
Token scopes:
read and crm or write and crm
Where one lead you sent is now: its stage, its outcome, whether
someone owns it, and its score. Find it by the contact_id from
What became of a lead.
Server-only applications, and only the leads this application sent.
It doesn't include the person's details, since you sent them.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| id required | path | string (uuid) | The lead's |
Responses
200 The lead.
| Field | Type | Description |
|---|---|---|
| data required | Lead |
Where a lead is now, without the person's details. |
| data.contact_id required | string (uuid) |
The lead's id. |
| data.external_system_id required | string or null |
The lead's id in your organisation's own CRM, if it has one. |
| data.status required | string |
The lead's outcome so far. One of:"open", "won", "lost", "dormant", "disqualified", "duplicate", "invalid", "not_interested", "ineligible"
|
| data.terminal required | boolean |
Whether that's final (won, lost, or ruled out). |
| data.stage required | object | |
| data.stage.key required | string | |
| data.stage.name required | string | |
| data.stage.kind required | string |
One of: "open", "won", "lost"
|
| data.stage.probability required | integer or null |
The chance of a sale from this stage, as a percentage. |
| data.stage_entered_at required | string (date-time) | |
| data.owner_assigned required | boolean |
Whether someone on your team owns it. |
| data.score required | integer |
How promising the lead is, from 0 to 100. |
| data.campaign_id required | string or null (uuid) | |
| data.first_touched_at required | string or null (date-time) |
When your team first contacted them. |
| data.last_touched_at required | string or null (date-time) | |
| data.created_at required | string (date-time) | |
| data.updated_at required | string (date-time) |
{
"data": {
"contact_id": "0199a3c2-8200-7522-8ea3-2738a9bacbdc",
"external_system_id": "CRM-88123",
"status": "won",
"terminal": true,
"stage": {
"key": "won",
"name": "Won",
"kind": "won",
"probability": 100
},
"stage_entered_at": "2026-10-14T16:02:11+01:00",
"owner_assigned": true,
"score": 71,
"campaign_id": "0199a3c2-8300-7633-9fb4-38a9bacbdced",
"first_touched_at": "2026-10-12T10:52:40+01:00",
"last_touched_at": "2026-10-14T16:02:11+01:00",
"created_at": "2026-10-12T10:40:15+01:00",
"updated_at": "2026-10-14T16:02:11+01:00"
}
}
401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_token",
"message": "The access token has expired. Ask for a new one."
}
}
403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "forbidden",
"message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
}
}
404 There's no lead for that contact id that this application sent.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "not_found",
"message": "No lead for that contact id."
}
}
List what happened to your leads
GET
https://subcontext.com/api/v1/crm/events
Try it
Token scopes:
read and crm or write and crm
A feed of what has happened to the leads this application sent, oldest first: stage changes, outcomes, owners assigned, messages and calls. Server-only applications.
Each event says what happened and to whom, but not what was said or written. Use it as a prompt to get the lead.
To keep up, pass the last page's next_cursor as cursor. Events
are kept for your organisation's retention period, so poll at least
that often.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
| cursor | query | string | Carry on after the page this came from (its |
| contact_id | query | string (uuid) | Only this lead's events. |
| event | query | string | Only these kinds of event, comma separated (for example |
| limit | query | integer | How many events per page, 1 to 500. |
Responses
200 A page of events.
| Field | Type | Description |
|---|---|---|
| data required | array of LeadEvent |
The events, oldest first. |
| data[].id required | string (uuid) | |
| data[].event required | string |
What happened, such as |
| data[].contact_id required | string (uuid) | |
| data[].campaign_id required | string or null (uuid) | |
| data[].occurred_at required | string (date-time) | |
| data[].detail required | object |
The change but not its content (such as |
| data[].detail.from | any | |
| data[].detail.to | any | |
| data[].detail.stage | any | |
| data[].detail.kind | any | |
| data[].detail.fields | any | |
| data[].detail.reason | any | |
| data[].detail.status | any | |
| data[].detail.channel | any | |
| data[].detail.occurred_at | any | |
| next_cursor required | NextCursor |
Pass as |
{
"data": [
{
"id": "0199a3c2-8400-7744-8ac5-49bacbdcedfe",
"event": "lead.stage_changed",
"contact_id": "0199a3c2-8200-7522-8ea3-2738a9bacbdc",
"campaign_id": "0199a3c2-8300-7633-9fb4-38a9bacbdced",
"occurred_at": "2026-10-13T09:12:30+01:00",
"detail": {
"from": "new",
"to": "quoted"
}
},
{
"id": "0199a3c2-8401-7855-9bd6-5acbdcedfe0f",
"event": "lead.status_changed",
"contact_id": "0199a3c2-8200-7522-8ea3-2738a9bacbdc",
"campaign_id": "0199a3c2-8300-7633-9fb4-38a9bacbdced",
"occurred_at": "2026-10-14T16:02:11+01:00",
"detail": {
"from": "open",
"to": "won"
}
}
],
"next_cursor": "MDE5OWEzYzItODQwMS03ODU1LTliZDYtNWFjYmRjZWRmZTBm"
}
401 No token was sent, or it isn't valid because it has expired, was revoked (for example because the application's secret was rotated), or was cut short. Get a new token and try once more.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_token",
"message": "The access token has expired. Ask for a new one."
}
}
403 The token can't be used here. It's missing a scope, it was used from the wrong place (a server-only application's token in a browser, or a browser application's token from a server, another website or a request only server-only applications may make), or it wasn't asked for with `resource=https://subcontext.com/api/v1`.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "forbidden",
"message": "origin 'https://www.example.com' is not allowlisted for this OAuth application"
}
}
422 `invalid_parameter`: `event` has a kind of event the feed doesn't record, or `cursor` isn't one the API gave you. `fields` names it.
| Field | Type | Description |
|---|---|---|
| error required | object | |
| error.code required | string |
A short code for the kind of error, such as |
| error.message required | string |
What went wrong and what to do about it, in plain English. |
| error.fields | object |
When the error is about particular inputs, which ones and why,
by name: a nested one with a dot ( |
{
"error": {
"code": "invalid_parameter",
"message": "event has \"lead.stage_change\", not an event this feed records.",
"fields": {
"event": "has \"lead.stage_change\", not an event this feed records"
}
}
}