For AI agents: markdown of this page — /docs-content-en/entities/deals/move.md documentation index — /llms.txt

Move deal to another stage

POST /v1/deals/:id/move

Moves a deal to another stage of its pipeline. The same call can also move the deal to a different pipeline.

Parameters

Parameter Type Required Description
id (path) number yes Deal ID. List: GET /v1/deals

Request fields (body)

Field Type Description
stageId string Identifier of the target stage. Stages of the main pipeline — GET /v1/statuses?filter[entityId]=DEAL_STAGE, stages of the pipeline whose categoryId equals {N} — GET /v1/statuses?filter[entityId]=DEAL_STAGE_{N}
categoryId number ID of the target pipeline. Pass it together with a stageId from that same pipeline when the deal moves between pipelines. List: GET /v1/deal-categories

Fields not listed in the table are ignored.

Examples

curl — personal key

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/deals/741/move" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "stageId": "C1:PREPARATION"
  }'

curl — OAuth application

Terminal
curl -X POST "https://vibecode.bitrix24.com/v1/deals/741/move" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "stageId": "C1:PREPARATION"
  }'

JavaScript — personal key

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/deals/741/move', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    stageId: 'C1:PREPARATION',
  }),
})

const { success, data } = await res.json()

JavaScript — OAuth application

javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/deals/741/move', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    stageId: 'C1:PREPARATION',
  }),
})

const { success, data } = await res.json()

Moving to another pipeline

The request body contains a stage of the target pipeline and that pipeline's categoryId:

JSON
{
  "stageId": "C11:NEW",
  "categoryId": 11
}

Response fields

Field Type Description
success boolean true on a successful call
data object The deal after the call, all fields — see Deal fields
data.stageId string The stage the deal is on after the call
data.previousStageId string The stage the deal was on before the call
data.categoryId number The pipeline the deal belongs to after the call
data.movedTime string Timestamp of the last stage change, ISO 8601

Response example

The main fields are shown.

JSON
{
  "success": true,
  "data": {
    "id": 741,
    "title": "Equipment delivery",
    "categoryId": 1,
    "stageId": "C1:PREPARATION",
    "previousStageId": "C1:NEW",
    "stageSemanticId": "P",
    "assignedById": 1,
    "movedBy": 1,
    "movedTime": "2026-08-25T10:47:14.000Z",
    "updatedAt": "2026-08-25T10:47:14.000Z"
  }
}

Error response example

404 — no deal with that id:

JSON
{
  "success": false,
  "error": {
    "code": "ENTITY_NOT_FOUND",
    "message": "Item not found"
  }
}

422 — the stage/pipeline that was sent was not applied (for example, a stageId that is not in the dictionary). By that point Bitrix24 has already accepted the write and the deal has been re-read, so the error response contains the re-read deal in data, and error.details lists the unapplied fields with their current values:

JSON
{
  "success": false,
  "error": {
    "code": "STAGE_NOT_APPLIED",
    "message": "Bitrix24 accepted the write but did not apply it: stageId requested \"C1:BOGUS\", still \"C1:NEW\" after re-read. The value is likely not a valid id for this deal — 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": "C1:NEW"
      }
    }
  },
  "data": {
    "id": 741,
    "title": "Equipment delivery",
    "categoryId": 1,
    "stageId": "C1:NEW"
  }
}

Errors

HTTP Code Description
404 ENTITY_NOT_FOUND No deal with the given id
422 STAGE_NOT_APPLIED The stageId/categoryId that was sent was not applied — after the call the value was still the old one (this usually means the stage or pipeline does not exist). Such a call used to return 200 with no warning; now it is an explicit error: details in error.message and error.details, the re-read deal in data
422 BITRIX_ERROR Bitrix24 rejected the call itself (not the stage value specifically) — a malformed field, for example. The reason is returned in error.message, and the machine-readable Bitrix24 code in error.b24Code
403 BITRIX_ACCESS_DENIED Bitrix24 denied access to the deal
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 includes a Retry-After header with the recommended delay

Full list of common API errors — Errors.

Known specifics

  • An empty body is not an error. A call with no stageId/categoryId in the body returns 200, and the deal stays on its previous stage: there is nothing to compare, so this is not STAGE_NOT_APPLIED — the platform only verifies the fields that were actually sent.

See also