## Add a block to a page

`POST /v1/pages/:pageId/blocks`

Adds a block from the Bitrix24 account block catalog to a landing page, with the catalog markup or with your own.

Fields are passed flat at the root of the JSON, without a `fields` wrapper. Working with pages and their blocks is covered in [Pages](/docs/entities/pages).

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|---------|
| `pageId` (path) | number | yes | Page ID. List: [`GET /v1/pages`](/docs/entities/pages/list) |
| `scope` (query) | string | no | Bitrix24 section the page belongs to: `KNOWLEDGE` for the knowledge base, `GROUP` for a workgroup knowledge base, `MAINPAGE` for the main page. Not passed for a page of a regular site |

## Request fields (body)

| Field | Type | Required | Description |
|------|-----|:-----:|---------|
| `code` | string | yes | Block code from the catalog. Catalog: [`GET /v1/block-repository`](/docs/entities/pages/catalog). The code is the item key in the section's `items` |
| `afterId` | number | no | ID of a block on this page after which the new block is placed. List: [`GET /v1/pages/:pageId/blocks`](/docs/entities/pages/blocks/list). Without this field, the new block is placed first on the page |
| `active` | boolean | no | Block visibility. `false` creates the block hidden. By default the block is visible. Also accepts the strings `"true"`, `"false"`, `"1"`, `"0"` and the numbers `1`, `0` |
| `content` | string | no | HTML markup of the block instead of the catalog markup. Without this field, the block gets the catalog markup |

## Examples

### curl — personal key

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/pages/20/blocks" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "03.1.three_cols_big_with_text_and_titles",
    "afterId": 30,
    "content": "<section class=\"landing-block\"><div class=\"container\"><h2>Hello</h2></div></section>"
  }'
```

### curl — OAuth application

```bash
curl -X POST "https://vibecode.bitrix24.com/v1/pages/20/blocks" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "03.1.three_cols_big_with_text_and_titles",
    "afterId": 30,
    "content": "<section class=\"landing-block\"><div class=\"container\"><h2>Hello</h2></div></section>"
  }'
```

### JavaScript — personal key

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/pages/20/blocks', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    code: '03.1.three_cols_big_with_text_and_titles',
    afterId: 30,
    content: '<section class="landing-block"><div class="container"><h2>Hello</h2></div></section>',
  }),
})

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

### JavaScript — OAuth application

```javascript
const res = await fetch('https://vibecode.bitrix24.com/v1/pages/20/blocks', {
  method: 'POST',
  headers: {
    'X-Api-Key': 'YOUR_APP_KEY',
    'Authorization': 'Bearer USER_SESSION_TOKEN',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    code: '03.1.three_cols_big_with_text_and_titles',
    afterId: 30,
    content: '<section class="landing-block"><div class="container"><h2>Hello</h2></div></section>',
  }),
})

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

## Response fields

| Field | Type | Description |
|------|-----|---------|
| `success` | boolean | Always `true` on success |
| `data` | object | The created block and how to publish it |
| `data.id` | number | ID of the created block in the page draft. Pass it to [`PATCH /v1/pages/:pageId/blocks/:blockId`](/docs/entities/pages/blocks/update) and [`DELETE /v1/pages/:pageId/blocks/:blockId`](/docs/entities/pages/blocks/delete) |
| `data.version` | string | Page version the block was added to. Always `draft` |
| `data.published` | boolean | Whether the change is published. Always `false` |
| `data.publishWith` | string | The call that publishes the page together with the new block, with the page ID filled in |

## Response example

```json
{
  "success": true,
  "data": {
    "id": 32,
    "version": "draft",
    "published": false,
    "publishWith": "POST /v1/pages/20/publication"
  }
}
```

## Error response example

422 — the block code is not in the catalog:

```json
{
  "success": false,
  "error": {
    "code": "BLOCK_CANT_BE_ADDED",
    "message": "Bitrix24 refused to add this block. Check that `code` is a code from GET /v1/block-repository."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|---------|
| 400 | `MISSING_BLOCK_CODE` | `code` is missing or is an empty string |
| 400 | `INVALID_AFTER_ID` | `afterId` is not a positive integer |
| 400 | `INVALID_ACTIVE` | `active` is not a boolean value |
| 400 | `INVALID_CONTENT` | `content` is not a string |
| 400 | `INVALID_PAGE_ID` | `pageId` in the path is not a positive integer |
| 400 | `INVALID_SCOPE` | `scope` is not `KNOWLEDGE`, `GROUP` or `MAINPAGE` |
| 400 | `INVALID_PARAMS` | Bitrix24 rejected the request: a required parameter is missing |
| 404 | `ENTITY_NOT_FOUND` | The page does not exist or is not visible to the key. A knowledge base, workgroup or main page requires the `scope` parameter |
| 422 | `BLOCK_CANT_BE_ADDED` | Bitrix24 refused to add the block: the `code` value is not in the catalog |
| 422 | `BLOCK_WRONG_VERSION` | The catalog block requires a newer version of the sites module than the one installed on the Bitrix24 portal |
| 502 | `BLOCK_ADD_UNCONFIRMED` | Bitrix24 did not return the ID of the new block: creation is not confirmed |
| 403 | `BITRIX_ACCESS_DENIED` | The employee the key was issued for has no access to the page in Bitrix24 |
| 422 | `BITRIX_ERROR` | Bitrix24 rejected the request; the error text is in `message` |
| 403 | `SCOPE_DENIED` | The API key does not have the `landing` scope |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is in read-only mode |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |

Full list of common API errors: [Errors](/docs/errors).

## Known specifics

**Markup is returned in a wrapper.** Reading [`GET /v1/pages/:pageId/blocks?content=true`](/docs/entities/pages/blocks/list) returns the markup from `content` inside a `<div id="b<id>" class="block-wrapper block-<code>">` element. In the wrapper class, dots and underscores of the block code are replaced with hyphens: for `03.1.three_cols_big_with_text_and_titles` it is `block-03-1-three-cols-big-with-text-and-titles`.

**A non-existent `afterId` is not rejected.** If the page has no block with this ID, the block is still created with a `201` response, but it lands somewhere on the page other than first or last. Before the call, take `afterId` from the [block list](/docs/entities/pages/blocks/list), and after the call, check the new block's position with the same list.

## See also

- [List page blocks](/docs/entities/pages/blocks/list)
- [Replace block markup](/docs/entities/pages/blocks/update)
- [Delete a block](/docs/entities/pages/blocks/delete)
- [Restore a block](/docs/entities/pages/blocks/restore)
- [Block catalog](/docs/entities/pages/catalog)
- [Publish a block](/docs/entities/pages/block-publication)
- [Pages](/docs/entities/pages)
