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 also moves the deal into 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 outside 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 app

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 app

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 carries the stage of the target pipeline and its 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",
    "entityTypeId": 2
  }
}

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 (a stageId 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 deal in data, and error.details carries the list of 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",
    "entityTypeId": 2
  }
}

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 (usually a nonexistent stage or pipeline). 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 deal in data
422 BITRIX_ERROR Bitrix24 rejected the call itself (not the stage 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 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 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 stageId/categoryId in the body answers 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