
## 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

```bash
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

```bash
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](/docs/entities/deals/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](/docs/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

- [Update deal](/docs/entities/deals/update)
- [Get deal](/docs/entities/deals/get)
- [Deal fields](/docs/entities/deals/fields)
- [Sales pipelines](/docs/entities/deal-categories)
- [CRM dictionaries](/docs/entities/statuses)
