For AI agents: markdown of this page — /docs-content-en/stage-history.md documentation index — /llms.txt
Stage history
GET /v1/stage-history
Returns the history of CRM record transitions across stages and statuses — when a record reached each pipeline stage. Used for reports on the velocity of deals, leads and smart-process items and for conversion analysis across pipelines.
Bitrix24 API: crm.stagehistory.list
Scope: crm
Parameters
The set of stage filter fields depends on the record type. For the stage-based types deal, invoice, new-invoice and smart processes, stageId, stageSemanticId, categoryId are available. For the status-based type lead, statusId, statusSemanticId are available. A field that does not belong to the type returns 400 INVALID_FILTER_FIELD.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
ParameterentityType (query) |
Typestring | Requiredno | Defaultdeal |
DescriptionCRM record type: deal, lead, invoice, new-invoice — an alias of invoice. For a smart process, pass its numeric ID as the value of entityType, for example ?entityType=128. The separate query keys entityTypeId and entityTypeID are refused with 400 INVALID_ENTITY_TYPE. List: GET /v1/smart-processes. Supply the parameter at most once |
ParameterownerId (query) |
Typenumber | Requiredno | Default— | DescriptionIdentifier of the record whose transition history to return. Depends on entityType. Sources: GET /v1/deals, GET /v1/leads, GET /v1/invoices, and GET /v1/items/{entityTypeId} for smart processes |
ParametertypeId (query) |
Typenumber | Requiredno | Default— | DescriptionTransition type: 1 — record creation, 2 — move to an intermediate stage, 3 — move to a final stage, 5 — pipeline change |
ParametercreatedAfter (query) |
Typestring | Requiredno | Default— | DescriptionTransitions from the specified moment, inclusive (ISO 8601) |
ParametercreatedBefore (query) |
Typestring | Requiredno | Default— | DescriptionTransitions up to the specified moment, inclusive (ISO 8601) |
ParameterstageId (query) |
Typestring | Requiredno | Default— | DescriptionStage-based types only. Filter by stage. List for deals: GET /v1/statuses?filter[entityId]=DEAL_STAGE; for a smart process: GET /v1/statuses?filter[entityId]=DYNAMIC_{entityTypeId}_STAGE_{categoryId} |
ParameterstageSemanticId (query) |
Typestring | Requiredno | Default— | DescriptionStage-based types only. Stage semantics: P — intermediate, S — successful, F — failed |
ParametercategoryId (query) |
Typenumber | Requiredno | Default— | DescriptionStage-based types only. Pipeline identifier. List for deals: GET /v1/deal-categories; for a smart process: GET /v1/categories/{entityTypeId} |
ParameterstatusId (query) |
Typestring | Requiredno | Default— | Descriptionlead only. Filter by status. List: GET /v1/statuses?filter[entityId]=STATUS |
ParameterstatusSemanticId (query) |
Typestring | Requiredno | Default— | Descriptionlead only. Status semantics: P — intermediate, S — successful, F — failed |
Parameterlimit (query) |
Typenumber | Requiredno | Default50 |
DescriptionNumber of records per call. Maximum 5000 |
Parameteroffset (query) |
Typenumber | Requiredno | Default0 |
DescriptionSelection offset. Rounded down to a multiple of 50 |
For limit > 50, Vibecode automatically paginates the request on the server side. The maximum is 5000 records per call. The meta.hasMore field shows whether there are records beyond the current selection.
The generic filter parameter is not applied by this endpoint. By default, the API preserves the previous HTTP 200 response and data, adds Warning: 299 - "filter is not supported on this endpoint and was ignored", and records unsupported-filter use in the server log.
Examples
curl — personal key
curl "https://vibecode.bitrix24.com/v1/stage-history?entityType=deal&limit=50" \
-H "X-Api-Key: YOUR_API_KEY"
curl — OAuth application
curl "https://vibecode.bitrix24.com/v1/stage-history?entityType=deal&limit=50" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN"
JavaScript — personal key
const params = new URLSearchParams({ entityType: 'deal', limit: '50' })
const res = await fetch(`https://vibecode.bitrix24.com/v1/stage-history?${params}`, {
headers: { 'X-Api-Key': 'YOUR_API_KEY' },
})
const { success, data, meta } = await res.json()
JavaScript — OAuth application
const params = new URLSearchParams({ entityType: 'deal', limit: '50' })
const res = await fetch(`https://vibecode.bitrix24.com/v1/stage-history?${params}`, {
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
},
})
const { success, data, meta } = await res.json()
Response fields
The set of record fields depends on the type: the stage-based types (deal, invoice, new-invoice, smart processes) return stageId, stageSemanticId, categoryId, while the status-based type lead returns statusId, statusSemanticId.
| Field | Type | Description |
|---|---|---|
Fieldsuccess |
Typeboolean | DescriptionAlways true on success |
Fielddata |
Typearray | DescriptionArray of history records, newest to oldest |
Fielddata[].id |
Typenumber | DescriptionHistory record identifier |
Fielddata[].typeId |
Typenumber | DescriptionTransition type: 1 — creation, 2 — intermediate stage, 3 — final stage, 5 — pipeline change |
Fielddata[].ownerId |
Typenumber | DescriptionIdentifier of the record in which the transition occurred |
Fielddata[].createdAt |
Typestring | DescriptionMoment of the transition to the stage (ISO 8601) |
Fielddata[].stageId |
Typestring | DescriptionStage. Stage-based types only |
Fielddata[].stageSemanticId |
Typestring | DescriptionStage semantics: P, S, F. Stage-based types only |
Fielddata[].categoryId |
Typenumber | DescriptionPipeline. Stage-based types only |
Fielddata[].statusId |
Typestring | DescriptionStatus. lead only |
Fielddata[].statusSemanticId |
Typestring | DescriptionStatus semantics: P, S, F. lead only |
Fieldmeta.total |
Typenumber | DescriptionTotal number of records under the filter |
Fieldmeta.hasMore |
Typeboolean | DescriptionWhether there are records beyond the current selection |
Response example
Deal (entityType=deal) — transitions across pipeline stages:
{
"success": true,
"data": [
{
"id": 12857,
"typeId": 1,
"ownerId": 7913,
"createdAt": "2026-06-24T00:03:50+00:00",
"categoryId": 9,
"stageSemanticId": "P",
"stageId": "C9:NEW"
},
{
"id": 12855,
"typeId": 1,
"ownerId": 7911,
"createdAt": "2026-06-23T00:02:34+00:00",
"categoryId": 9,
"stageSemanticId": "P",
"stageId": "C9:NEW"
}
],
"meta": {
"total": 2941,
"hasMore": true
}
}
Lead (entityType=lead) — transitions across statuses:
{
"success": true,
"data": [
{
"id": 3689,
"typeId": 1,
"ownerId": 1001083,
"createdAt": "2026-06-10T18:03:12+00:00",
"statusId": "NEW",
"statusSemanticId": "P"
}
],
"meta": {
"total": 296,
"hasMore": true
}
}
Smart process (entityType=164) — transitions across stages, exactly as for a deal:
{
"success": true,
"data": [
{
"id": 47,
"typeId": 1,
"ownerId": 55,
"createdAt": "2026-08-04T22:07:23+00:00",
"categoryId": 27,
"stageSemanticId": "P",
"stageId": "DT164_27:NEW"
}
],
"meta": {
"total": 1,
"hasMore": false
}
}
Error response example
400 — the filter field does not apply to the record type:
{
"success": false,
"error": {
"code": "INVALID_FILTER_FIELD",
"message": "\"statusId\" is not a valid filter for entityType \"deal\". entityType \"deal\" is stage-based — use stageId."
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| HTTP200 | CodeWarning: 299 |
DescriptionThe filter is ignored by default; previous data is preserved and the warning is sent in the Warning header. |
| HTTP400 (strict mode only) | CodeUNSUPPORTED_FILTER |
DescriptionThe server mode is disabled by default; until it is enabled, the endpoint preserves HTTP 200 and the previous data. |
| HTTP400 | CodeINVALID_ENTITY_TYPE |
DescriptionentityType was not recognised: an unknown name, a non-canonical numeric form, the numeric ID of a dedicated entity (1, 2, 31 — use the name), an entity with no stage history (3, 4, 5, 7), a repeated parameter, or an ID that does not exist on this portal. The separate query keys entityTypeId and entityTypeID are also refused; use entityType, for example ?entityType=128 |
| HTTP400 | CodeINVALID_FILTER_FIELD |
DescriptionThe filter field does not apply to the specified entityType — for example statusId for deal |
| HTTP400 | CodeINVALID_PARAMS |
DescriptionThe parameter was not supplied as a single string value — for example ?ownerId[]=5 or ?ownerId[x]=1. Bracket, repeated and mixed forms are refused: ?ownerId[]=5&ownerId[]=6 and ?ownerId[]=6&ownerId=5 would otherwise silently filter by a single value. The numeric parameters (ownerId, typeId, categoryId, limit, offset) are additionally accepted only as an integer written in full: ?ownerId=1e3 would otherwise read the history of owner 1, and ?ownerId=abc would return a wider selection than requested |
| HTTP403 | CodeSCOPE_DENIED |
DescriptionThe key lacks the crm scope |
| HTTP401 | CodeTOKEN_MISSING |
DescriptionThe key has no access tokens configured |
| HTTP401 | CodeMISSING_API_KEY |
DescriptionThe X-Api-Key header was not provided |
| HTTP429 | CodeERROR_LOOP_DETECTED |
DescriptionToo many consecutive rejected requests on this key. Probing entityTypeId values is a common cause: take the ID from GET /v1/smart-processes instead of guessing |
Full list of common API errors — Errors.
How to get a smart process `entityTypeId`
The numeric type identifier is returned by GET /v1/smart-processes — the entityTypeId field of
each item. It differs from the type id and is not derived from it.
curl "https://vibecode.bitrix24.com/v1/smart-processes" \
-H "X-Api-Key: YOUR_API_KEY"
Pass the value you get as entityType:
curl "https://vibecode.bitrix24.com/v1/stage-history?entityType=164&limit=50" \
-H "X-Api-Key: YOUR_API_KEY"
Do not probe for the identifier. Every request carrying a non-existent entityTypeId reaches
Bitrix24 and is rejected, and a run of such rejections trips 429 ERROR_LOOP_DETECTED for the key —
after which ordinary deal history requests stop going through as well.
Known specifics
Sorting is not configurable. The sort parameter is not accepted — the order of records cannot be changed.