For AI agents: markdown of this page — /docs-content-en/entities/leads/move.md documentation index — /llms.txt
Move lead to another status
POST /v1/leads/:id/move
Moves a lead to another status — from a new request to in-progress, for example.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id (path) |
number | yes | Lead ID. List: GET /v1/leads |
Request fields (body)
| Field | Type | Description |
|---|---|---|
statusId |
string | Identifier of the target status. List: GET /v1/statuses?filter[entityId]=STATUS |
stageId |
string | A second name for the same field. Accepted interchangeably with statusId and means the same status |
Fields outside the table are ignored.
Examples
curl — personal key
curl -X POST "https://vibecode.bitrix24.com/v1/leads/42/move" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"statusId": "IN_PROCESS"
}'
curl — OAuth application
curl -X POST "https://vibecode.bitrix24.com/v1/leads/42/move" \
-H "X-Api-Key: YOUR_APP_KEY" \
-H "Authorization: Bearer USER_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"statusId": "IN_PROCESS"
}'
JavaScript — personal key
const res = await fetch('https://vibecode.bitrix24.com/v1/leads/42/move', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
statusId: 'IN_PROCESS',
}),
})
const { success, data } = await res.json()
JavaScript — OAuth application
const res = await fetch('https://vibecode.bitrix24.com/v1/leads/42/move', {
method: 'POST',
headers: {
'X-Api-Key': 'YOUR_APP_KEY',
'Authorization': 'Bearer USER_SESSION_TOKEN',
'Content-Type': 'application/json',
},
body: JSON.stringify({
statusId: 'IN_PROCESS',
}),
})
const { success, data } = await res.json()
Response fields
| Field | Type | Description |
|---|---|---|
success |
boolean | true on a successful call |
data |
object | The lead after the call, all fields — see Lead fields |
data.stageId |
string | The status of the lead after the call. The value arrives in this field regardless of which name it was passed under in the request body |
data.movedTime |
string | Timestamp of the last status change, ISO 8601 |
Response example
The main fields are shown.
{
"success": true,
"data": {
"id": 42,
"title": "Website request",
"name": "Maria",
"stageId": "IN_PROCESS",
"stageSemanticId": "P",
"assignedById": 1,
"movedBy": 1,
"movedTime": "2026-08-25T10:47:20+00:00",
"updatedTime": "2026-08-25T10:47:20.000Z",
"entityTypeId": 1
}
}
Error response example
404 — no lead with that id:
{
"success": false,
"error": {
"code": "ENTITY_NOT_FOUND",
"message": "Item not found"
}
}
422 — the status that was sent was not applied (a value absent from the dictionary, for example). By that point the write had already reached Bitrix24 and the record had been re-read, so the refusal carries the re-read lead in data, and error.details carries the list of unapplied fields with their current values:
{
"success": false,
"error": {
"code": "STAGE_NOT_APPLIED",
"message": "Bitrix24 accepted the write but did not apply it: stageId requested \"BOGUS_STATUS\", still \"NEW\" after re-read. The value is likely not a valid id for this lead — check GET /v1/statuses?filter[entityId]=... (or GET /v1/deal-categories for a pipeline id) for the valid set before retrying. The record was already written and re-read: any OTHER field in the same request may have been applied, so correct the value and send only what still needs changing rather than repeating the whole body.",
"details": {
"unappliedFields": ["stageId"],
"currentValues": {
"stageId": "NEW"
}
}
},
"data": {
"id": 42,
"title": "Website request",
"name": "Maria",
"stageId": "NEW",
"entityTypeId": 1
}
}
Errors
| HTTP | Code | Description |
|---|---|---|
| 404 | ENTITY_NOT_FOUND |
No lead with the given id |
| 422 | STAGE_NOT_APPLIED |
The statusId/stageId that was sent was not applied — after the call the status was still the old one (usually a value absent from the dictionary). Such a call used to answer 200 with no warning; now it is an explicit error: details in error.message and error.details, the re-read lead in data |
| 422 | BITRIX_ERROR |
Bitrix24 rejected the call itself (not the status value specifically) — a malformed field, for example. The reason arrives in error.message, the machine-readable Bitrix24 code in error.b24Code |
| 403 | BITRIX_ACCESS_DENIED |
Bitrix24 denied access to the lead |
| 403 | SCOPE_DENIED |
The key lacks the crm scope |
| 403 | WRITE_BLOCKED_READONLY_KEY |
A key in read-only mode called a write method |
| 401 | TOKEN_MISSING |
The API key has no configured tokens |
| 429 | RATE_LIMITED |
Request limit exceeded. The response carries a Retry-After header with the recommended pause |
Full list of common API errors — Errors.
Known specifics
- An empty body is not an error. A call with no
statusId/stageIdin the body answers200, and the lead stays on its previous status: there is nothing to compare, so this is notSTAGE_NOT_APPLIED— the platform only verifies the fields that were actually sent.