## Update a form

`PATCH /v1/crm-forms/:id`

Changes the settings of a saved CRM form: name, fields, CRM binding, responsible users and texts.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|----------|
| `id` (path) | integer | yes | Form ID. List: [`GET /v1/crm-forms`](/docs/entities/crm-forms/list) |

## Request fields (body)

Pass either a flat body or an object in `fields`: `{"fields":{"name":"Contact form"}}`. In a flat body, an array in `fields` is the list of form fields. Do not combine an object in `fields` with other top-level properties except `updatedTime` — this returns `400 INVALID_PARAMS`. Bitrix24 validates the form properties and values.

| Field | Type | Required | Description |
|------|-----|:-----:|----------|
| `updatedTime` | string | yes | Current form version — `data.updatedTime` from [`GET /v1/crm-forms/:id`](/docs/entities/crm-forms/get) or from the response of the previous write |
| `name` | string \| null | no | Form name in the forms list |
| `languageId` | string \| null | no | Form language. List: `data.languages` in [`GET /v1/crm-forms/configuration`](/docs/entities/crm-forms/configuration) |
| `templateId` | string \| null | no | Scenario the form was created from. List: [List scenarios](/docs/entities/crm-forms/scenarios) |
| `crm` | object | no | CRM binding |
| `crm.entityScheme` | integer | no | Scheme of the CRM records the form creates. List: `data.entitySchemes` in [`GET /v1/crm-forms/configuration`](/docs/entities/crm-forms/configuration) |
| `appearance` | object | no | Appearance: `title`, `description`, button caption `buttonCaption` and other properties |
| `fields` | array \| object | no | Form fields as an array, or a request envelope as an object |
| `fields[].name` | string | no | Field name, for example `LEAD_NAME`. List: [`GET /v1/crm-forms/entity-fields`](/docs/entities/crm-forms/entity-fields) |
| `fields[].type` | string | no | Field type. List: `data.fieldTypes` in [`GET /v1/crm-forms/configuration`](/docs/entities/crm-forms/configuration) |
| `fields[].label` | string | no | Field label in the form |
| `fields[].required` | boolean | no | Whether the field is required for submission. Pass it explicitly: without the flag, `true` is saved |
| `fields[].multiple` | boolean | no | Whether the field accepts multiple values. Pass it explicitly: without the flag, `true` is saved |
| `responsible` | object | no | Users responsible for the form results |
| `responsible.userIds` | array of integer | no | IDs of responsible users. List: [`GET /v1/users`](/docs/entities/users) |
| `agreements` | object | no | Agreement settings in the Bitrix24 format |
| `submission` | object | no | Post-submission settings: texts and redirect URLs on success and on error |
| `callback` | object | no | Callback settings |
| `payment` | object | no | Payment settings |
| `booking` | object | no | Booking settings |
| `presetFields` | array | no | Preset field values |
| `dependencies` | array | no | Dependencies between fields |
| `analytics` | object | no | Analytics settings |
| `integrations` | object | no | Integration settings |
| `spamProtection` | object | no | Spam protection settings |

The [Form contract fields](/docs/entities/crm-forms/fields) reference describes top-level metadata only. Take the names of nested properties and the current section values of a saved form from the full [Get a form](/docs/entities/crm-forms/get) response. Sections are passed in the Bitrix24 format; Bitrix24 decides which settings can be written.

## Examples

### curl — personal key

```bash
curl -X PATCH "https://vibecode.bitrix24.com/v1/crm-forms/91" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "updatedTime": "2026-11-05T08:16:55Z",
    "name": "VIBE-PROBE 777758 flat, companies"
  }'
```

### curl — OAuth application

```bash
curl -X PATCH "https://vibecode.bitrix24.com/v1/crm-forms/91" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "updatedTime": "2026-11-05T08:16:55Z",
    "name": "VIBE-PROBE 777758 flat, companies"
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/crm-forms/91', {
  method: 'PATCH',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    updatedTime: '2026-11-05T08:16:55Z',
    name: 'VIBE-PROBE 777758 flat, companies',
  }),
})

const { data } = await res.json()
console.log('New version:', data.updatedTime)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/crm-forms/91', {
  method: 'PATCH',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    updatedTime: '2026-11-05T08:16:55Z',
    name: 'VIBE-PROBE 777758 flat, companies',
  }),
})

const { data } = await res.json()
```

## Response fields

HTTP `200`. The response is the saved form, re-read after the change. Form properties other than `id` are present only when this read succeeds.

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` on success |
| `data` | object | The updated form in the same format as [Get a form](/docs/entities/crm-forms/get). Top-level property metadata: [Form contract fields](/docs/entities/crm-forms/fields) |
| `data.id` | integer | Form ID |
| `data.name` | string | Form name |
| `data.updatedTime` | string \| null | New form version. Pass it in the next write request |
| `data.fields` | array | Form fields as saved |
| `meta.warnings` | array | Present when the saved state could not be read |
| `meta.redacted` | array of string | JSON paths where current connection credentials were replaced. Do not save this representation back as a complete configuration |

If the write succeeds but the follow-up read fails, the response stays successful: `200` with only `data.id` and `meta.warnings[].code: "CRM_FORM_READBACK_FAILED"`. Before the next write, re-read the form with GET to obtain its current `updatedTime`. Do not repeat the successful write.

## Response example

The example is abbreviated. Take nested property names and values from the full [GET response](/docs/entities/crm-forms/get) for your configured form. [Form contract fields](/docs/entities/crm-forms/fields) describes top-level metadata only.

```json
{
  "success": true,
  "data": {
    "id": 91,
    "code": "91",
    "name": "VIBE-PROBE 777758 flat, companies",
    "active": false,
    "system": false,
    "createdTime": "2026-11-05T08:16:55Z",
    "updatedTime": "2026-11-05T08:25:29Z",
    "crm": {
      "entityScheme": 1,
      "duplicateMode": "",
      "dealCategoryId": null,
      "dealDuplicateControlEnabled": false,
      "smartProcessCategoryId": null,
      "smartProcessDuplicateControlEnabled": false
    },
    "fields": [
      {
        "name": "LEAD_NAME",
        "type": "string",
        "label": null,
        "sort": 10,
        "required": false,
        "multiple": false,
        "placeholder": null,
        "valueType": null,
        "value": null
      }
    ],
    "agreements": {
      "enabled": false,
      "items": []
    }
  }
}
```

## Error response example

409 — the form changed after it was read; the passed `updatedTime` is outdated:

```json
{
  "success": false,
  "error": {
    "code": "CRM_FORM_VERSION_MISMATCH",
    "message": "The CRM form version is outdated. Changes were not saved. Get the form again and retry the request",
    "b24Code": "CRM_FORM_VERSION_MISMATCH",
    "currentUpdatedTime": "2026-11-05T08:25:30Z"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 409 | `CRM_FORM_VERSION_MISMATCH` | `updatedTime` does not match the current form version. Changes were not saved; the current version is in `error.currentUpdatedTime` |
| 404 | `ENTITY_NOT_FOUND` | No form with this `id` |
| 400 | `INVALID_PARAMS` | The body has no `updatedTime` |
| 400 | `INVALID_PARAMS` | `id` is not a positive integer, the body is not a JSON object, the body formats are mixed, or a query string parameter was passed |
| 402 | `CRM_FORM_WRITE_RESTRICTED` | The Bitrix24 plan (free or demo) does not allow writing CRM forms |
| 403 | `CRM_FORM_SYSTEM_IMMUTABLE` | The form is a system form; its settings cannot be changed |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is read-only. A key with write access is required |
| 403 | `BITRIX_INSUFFICIENT_SCOPE` | The Bitrix24 token lacks the required scope |
| 409 | `CRM_FORM_REST_NOT_ENABLED` | The CRM form methods are disabled on the Bitrix24 account |
| 403 | `BITRIX_ACCESS_DENIED` | Bitrix24 denied access: the user has no permission to change CRM forms |
| 403 | `SCOPE_DENIED` | The key lacks the `crm` scope |
| 401 | `MISSING_API_KEY` | `X-Api-Key` was not passed |
| 401 | `TOKEN_MISSING` | The key has no Bitrix24 access tokens |
| 422 | `BITRIX_ERROR` | Another Bitrix24 refusal. The original message is kept in `error.message` |
| 500 | `CRM_FORM_SIDE_EFFECT_FAILED` | The changes are already written, but a subsequent step on the Bitrix24 side failed. Read the form before retrying |
| 502 | `BITRIX_UNAVAILABLE` | Bitrix24 is unavailable or returned a malformed response. The changes may have been saved — read the form before retrying |

Bitrix24 errors include the original code in `error.b24Code` and field violations in `error.validation` when provided. `CRM_FORM_*` codes retain their HTTP status, code and message. Common 429, 502 and 503 responses: [Limits and optimization](/docs/optimization). Full list of common API errors: [Errors](/docs/errors).

## Known specifics

**Partial update.** Properties absent from the body stay unchanged. A passed array or object replaces the previous one entirely: to add one form field, pass all fields in `fields` together with the new one. An empty array clears the collection; `null` on a scalar property clears its value.

## See also

- [Get a form](/docs/entities/crm-forms/get)
- [Validate a form](/docs/entities/crm-forms/validate)
- [Create a form](/docs/entities/crm-forms/create)
- [Activate a form](/docs/entities/crm-forms/activate)
- [Deactivate a form](/docs/entities/crm-forms/deactivate)
- [Form contract fields](/docs/entities/crm-forms/fields)
- [Get the builder configuration](/docs/entities/crm-forms/configuration)
- [Limits and optimization](/docs/optimization)
