## Create a form

`POST /v1/crm-forms`

Creates a CRM form with fields, a CRM binding, responsible users and result texts.

## Request fields (body)

Pass either a flat body or an object in `fields`: `{"fields":{"name":"VIBE-PROBE 777758 parity"}}`. An array in `fields` is the form field section of a flat body. Do not combine an object in `fields` with other top-level properties — this returns `400 INVALID_PARAMS`. Bitrix24 validates the form properties and values.

Before creating, you can check a draft without saving it: [Validate a form](/docs/entities/crm-forms/validate).

| Field | Type | Required | Description |
|------|-----|:-----:|----------|
| `name` | string | yes | Form name in the forms list |
| `crm` | object | yes | CRM binding. Take nested settings from the configuration of a specific form |
| `crm.entityScheme` | integer | yes | Scheme of the CRM records the form creates. List: `data.entitySchemes` in [`GET /v1/crm-forms/configuration`](/docs/entities/crm-forms/configuration) |
| `active` | boolean | no | Whether the form is enabled. Defaults to `true`. The state also has dedicated operations: [activation](/docs/entities/crm-forms/activate) and [deactivation](/docs/entities/crm-forms/deactivate) |
| `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) |
| `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. To create a form based on an existing one, take the names of nested properties and the initial section values 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 POST "https://vibecode.bitrix24.com/v1/crm-forms" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VIBE-PROBE 777758 parity",
    "active": false,
    "crm": { "entityScheme": 1 },
    "fields": [
      { "name": "LEAD_NAME", "type": "string", "required": false, "multiple": false }
    ]
  }'
```

### curl — OAuth application

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/crm-forms" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VIBE-PROBE 777758 parity",
    "active": false,
    "crm": { "entityScheme": 1 },
    "fields": [
      { "name": "LEAD_NAME", "type": "string", "required": false, "multiple": false }
    ]
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/crm-forms', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'VIBE-PROBE 777758 parity',
    active: false,
    crm: { entityScheme: 1 },
    fields: [
      { name: 'LEAD_NAME', type: 'string', required: false, multiple: false },
    ],
  }),
})

const { data } = await res.json()
console.log('Form ID:', data.id, 'updatedTime:', data.updatedTime)
```

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/crm-forms', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'VIBE-PROBE 777758 parity',
    active: false,
    crm: { entityScheme: 1 },
    fields: [
      { name: 'LEAD_NAME', type: 'string', required: false, multiple: false },
    ],
  }),
})

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

## Response fields

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

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | `true` on success |
| `data` | object | The created 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 | ID of the created form |
| `data.name` | string | Form name |
| `data.active` | boolean \| null | Whether the form is enabled |
| `data.updatedTime` | string \| null | Time of the last change. Passed to [`PATCH /v1/crm-forms/:id`](/docs/entities/crm-forms/update) |
| `data.fields` | array | Form fields as saved, including `required` and `multiple` |
| `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: `201` with only `data.id` and `meta.warnings[].code: "CRM_FORM_READBACK_FAILED"`. GET the form before another write 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 parity",
    "active": false,
    "system": false,
    "createdTime": "2026-11-05T08:16:55Z",
    "updatedTime": "2026-11-05T08:16:55Z",
    "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

400 — an object in `fields` is combined with another top-level property:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "Use either a flat body or {fields:{...}}"
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_PARAMS` | The body is not a JSON object, or a query string parameter was passed |
| 400 | `INVALID_PARAMS` | Bitrix24 rejected the configuration, for example `crm.entityScheme` was not passed. Violations are listed in `error.validation` |
| 400 | `CRM_FORM_PARTIALLY_CREATED` | The form exists: `error.id` is its ID, `error.b24Code` is the original error code, and `error.validation` describes failed sections. GET the form, then correct or delete it. Do not repeat creation |
| 402 | `CRM_FORM_WRITE_RESTRICTED` | The Bitrix24 plan (free or demo) does not allow writing CRM forms |
| 402 | `CRM_FORM_ACTIVATION_LIMIT_REACHED` | The form is created as enabled, and the active form limit is reached. The limit is `data.limits.activeForms` in [`GET /v1/crm-forms/configuration`](/docs/entities/crm-forms/configuration) |
| 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 |
| 404 | `ENTITY_NOT_FOUND` | Bitrix24 did not find the requested entity or field descriptor. The original code is in `error.b24Code` |
| 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` | Any other Bitrix24 refusal. The original message is kept in `error.message` |
| 500 | `CRM_FORM_SIDE_EFFECT_FAILED` | The form is already saved, but a subsequent step on the Bitrix24 side failed. `error.id` is the ID of the created form. Read the form before retrying |
| 502 | `BITRIX_UNAVAILABLE` | Bitrix24 is unavailable or returned a malformed response. The form may already be created — find it in the [forms list](/docs/entities/crm-forms/list) 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).

## See also

- [Validate a form](/docs/entities/crm-forms/validate)
- [Get a form](/docs/entities/crm-forms/get)
- [Update a form](/docs/entities/crm-forms/update)
- [Activate a form](/docs/entities/crm-forms/activate)
- [Form contract fields](/docs/entities/crm-forms/fields)
- [Get the builder configuration](/docs/entities/crm-forms/configuration)
- [List entity fields](/docs/entities/crm-forms/entity-fields)
- [Limits and optimization](/docs/optimization)
