## Rebuild a card set

`PUT /v1/pages/:pageId/blocks/:blockId/cards`

Rebuilds a block's card set from source cards and, in the same call, sets the node content of the new cards.

## Parameters

| Parameter | Type | Required | Description |
|----------|-----|:-----:|----------|
| `pageId` (path) | number | yes | Page ID. List: [`GET /v1/pages`](/docs/entities/pages/list) |
| `blockId` (path) | number | yes | ID of a block on this page. List: [`GET /v1/pages/:pageId/blocks`](/docs/entities/pages/blocks/list). A block of another page returns `404` |
| `scope` (query) | string | no | Internal landing area: `KNOWLEDGE` — knowledge base, `GROUP` — workgroup knowledge base, `MAINPAGE` — main page. Omit for a regular site |

## Request fields (body)

| Field | Type | Required | Description |
|------|-----|:-----:|----------|
| `selector` | string | yes | Card set selector without `@N`, for example `.landing-block-card`. This method takes no index. Set selectors are the keys of the `cards` object in the [`GET /v1/pages/:pageId/blocks/:blockId/content`](/docs/entities/pages/block-content) response |
| `source` | array | yes | Sources of the new cards, in order: after the write, the set contains one card per element. An empty array is not accepted |
| `source[].type` | string | no | `card` — a copy of a card from the current set, `preset` — a card preset from the block manifest. Defaults to `card` |
| `source[].value` | number \| string | no | For `card` — the zero-based index of a card in the current set. For `preset` — the preset key from `cards.<selector>.presets` in the [`GET /v1/block-repository/:code/manifest`](/docs/entities/pages/catalog-manifest) response, or the position in it for a `presets` array. The block code is `data.code` in the [`GET /v1/pages/:pageId/blocks/:blockId`](/docs/entities/pages/block-get) response. Defaults to `0` |
| `values` | object | yes | Node content after the rebuild. Top-level keys are arbitrary edit group names. Inside a group, the key is a node selector with an index, and the value is the new content |
| `values.<group>.<node>@N` | string \| number \| object | yes | Node content. `N` is the position among all nodes with this selector in the block after the rebuild, not within the card. A text node accepts a string, an integer or an object with a `text` field. `null` is not accepted. Node selectors are the keys of the `nodes` object in the [`GET /v1/pages/:pageId/blocks/:blockId/content`](/docs/entities/pages/block-content) response |

## Examples

The block has the cards `First` and `Second`. The request keeps both, adds a third one as a copy of the second, and names it `Third`.

### curl — personal key

```bash
curl -X PUT "https://vibecode.bitrix24.com/v1/pages/42/blocks/50/cards" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"selector":".landing-block-card","source":[{"type":"card","value":0},{"type":"card","value":1},{"type":"card","value":1}],"values":{"third":{".landing-block-node-title@2":"Third"}}}'
```

### curl — OAuth application

```bash
curl -X PUT "https://vibecode.bitrix24.com/v1/pages/42/blocks/50/cards" \
  -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"selector":".landing-block-card","source":[{"type":"card","value":0},{"type":"card","value":1},{"type":"card","value":1}],"values":{"third":{".landing-block-node-title@2":"Third"}}}'
```

### JavaScript — personal key

```javascript
const response = await fetch("https://vibecode.bitrix24.com/v1/pages/42/blocks/50/cards", {
  method: "PUT",
  headers: {"X-Api-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
  body: JSON.stringify({"selector": ".landing-block-card", "source": [{"type": "card", "value": 0}, {"type": "card", "value": 1}, {"type": "card", "value": 1}], "values": {"third": {".landing-block-node-title@2": "Third"}}}),
})
const result = await response.json()
if (!response.ok) throw new Error(result.error.message)
console.log(result.data)
```

### JavaScript — OAuth application

```javascript
const response = await fetch("https://vibecode.bitrix24.com/v1/pages/42/blocks/50/cards", {
  method: "PUT",
  headers: {"X-Api-Key": "YOUR_APP_KEY", "Authorization": "Bearer USER_SESSION_TOKEN", "Content-Type": "application/json"},
  body: JSON.stringify({"selector": ".landing-block-card", "source": [{"type": "card", "value": 0}, {"type": "card", "value": 1}, {"type": "card", "value": 1}], "values": {"third": {".landing-block-node-title@2": "Third"}}}),
})
const result = await response.json()
if (!response.ok) throw new Error(result.error.message)
console.log(result.data)
```

## Response fields

| Field | Type | Description |
|------|-----|----------|
| `success` | boolean | Always `true` on success |
| `data.cards` | object | Block cards after the write. The key is the set selector, the value is the array of the set's cards in order |
| `data.cards.<selector>[].index` | number | Current zero-based position of the card in the set |
| `data.cards.<selector>[].content` | string | Card HTML |

## Response example

```json
{
  "success": true,
  "data": {
    "cards": {
      ".landing-block-card": [
        {
          "index": 0,
          "content": "<div class=\"landing-block-card\"><h3 class=\"landing-block-node-title\">First</h3></div>"
        },
        {
          "index": 1,
          "content": "<div class=\"landing-block-card\"><h3 class=\"landing-block-node-title\">Second</h3></div>"
        },
        {
          "index": 2,
          "content": "<div class=\"landing-block-card\"><h3 class=\"landing-block-node-title\">Third</h3></div>"
        }
      ]
    }
  }
}
```

## Error response example

400 — `source` contains the index of a card that is not in the current set:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_PARAMS",
    "message": "source card index does not exist."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|-----|----------|
| 400 | `INVALID_PARAMS` | `source card index does not exist.` — `source` contains the index of a card that is not in the current set |
| 400 | `INVALID_PARAMS` | `source preset does not exist in the block manifest.` — the block manifest has no preset with this key |
| 400 | `INVALID_PARAMS` | `Each source needs a card index or a preset key and type card or preset.` — a `source` element is not an object, contains a field other than `type` and `value`, `type` is not `card` or `preset`, or `value` does not match the type |
| 400 | `INVALID_PARAMS` | `selector must address an existing card set.` — the block has no set with this selector or the set is empty |
| 400 | `INVALID_PARAMS` | `selector must omit the card index; DELETE uses the index path parameter.` — `selector` contains `@N` |
| 400 | `INVALID_PARAMS` | `selector has no card parent.` — the cards of the set have no parent element |
| 400 | `INVALID_PARAMS` | `Each values entry must map node selectors with @index to content.` — a group in `values` is not an object or is an empty object |
| 400 | `INVALID_PARAMS` | `values node selectors need a non-negative node index.` — a node selector has no `@N`, or `N` is not a non-negative integer |
| 400 | `INVALID_PARAMS` | `values references a node absent from the rebuilt block.` — the node is not in the block manifest, or after the rebuild there are fewer than `N + 1` nodes with this selector |
| 400 | `INVALID_PARAMS` | `Node content cannot be null: Bitrix24 ignores it.` — the node content is `null` |
| 400 | `INVALID_PARAMS` | `Text nodes require a string, integer, or an object with text.` — a text node received something other than a string or an integer: `true`, `false`, a fractional number, an array, or an object whose `text` is neither a string nor an integer |
| 400 | `MISSING_REQUIRED_FIELDS` | `source must be a non-empty array and values must be an object.` — `source` is missing or empty, or `values` is missing or not an object |
| 400 | `MISSING_REQUIRED_FIELDS` | `selector is required.` — `selector` is missing, empty or whitespace-only |
| 400 | `INVALID_PARAMS` | `pageId and blockId must be positive safe integers.` — `pageId` or `blockId` is not a positive integer |
| 400 | `INVALID_PARAMS` | `Body must be a JSON object.` — the body is not a JSON object |
| 400 | `INVALID_PARAMS` | `Body contains an unsupported field.` — the body contains a field other than `selector`, `source` and `values` |
| 400 | `INVALID_SCOPE` | `scope` is not `KNOWLEDGE`, `GROUP` or `MAINPAGE` |
| 404 | `ENTITY_NOT_FOUND` | `Page, block or card not found.` — the block does not belong to page `pageId` or does not exist |
| 413 | `PAYLOAD_TOO_LARGE` | `Expanded card HTML exceeds 8 MiB.` — the combined markup of the cards from `source` exceeds 8 MiB. The request is rejected before the write |
| 422 | `BITRIX_NO_EFFECT` | `Bitrix24 did not confirm the card action.` — Bitrix24 did not confirm the write |
| 422 | `BITRIX_NO_EFFECT` | `Bitrix24 did not return cards after the action.` — after the write, Bitrix24 did not return the block content |
| 422 | `BITRIX_NO_EFFECT` | `Bitrix24 did not persist the requested card count.` — the card count after the write does not match the length of `source` |
| 422 | `BITRIX_NO_EFFECT` | `Bitrix24 did not persist the rebuilt cards.` — the rebuild was supposed to change the block, but the markup stayed the same |
| 422 | `BITRIX_NO_EFFECT` | `Bitrix24 did not persist the requested node text.` — the node text from `values` was not saved |
| 422 | `BITRIX_ERROR` | Bitrix24 rejected the action. The error text comes from Bitrix24 |
| 502 | `BITRIX_ERROR` | `Bitrix24 returned invalid or oversized card content.` — the block markup cannot be parsed or the cards exceed 8 MiB |
| 403 | `SCOPE_DENIED` | The API key does not have the `landing` scope |
| 403 | `WRITE_BLOCKED_READONLY_KEY` | The key is read-only. The request is rejected before Bitrix24 is called |
| 403 | `BITRIX_ACCESS_DENIED` | The Bitrix24 user the key is issued for has no permission to edit the page |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header is missing |
| 401 | `INVALID_API_KEY` | The key in `X-Api-Key` is not found or has been revoked |
| 401 | `TOKEN_MISSING` | The API key has no configured tokens |
| 409 | `LANDING_MODULE_NOT_ENABLED` | The Sites module is not available on the Bitrix24 account |
| 409 | `PORTAL_ADDRESS_CHANGED` | A self-hosted Bitrix24 moved to a new address, but the key's webhook was issued for the old one. Reissue the key's webhook |
| 429 | `RATE_LIMITED` | The Bitrix24 request limit is exceeded. Retry the request in 1-2 seconds |
| 502 | `BITRIX_UNAVAILABLE` | Bitrix24 did not respond or returned a server error |
| 503 | `BITRIX_TIMEOUT` | Bitrix24 did not respond in time |

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

## Known specifics

- **A rebuild replaces the entire content of the card parent.** Elements next to the cards that are not cards themselves, and other sets inside the same parent, are removed. To change a single card, use [Clone a block card](/docs/entities/pages/cards/clone), [Remove a card by index](/docs/entities/pages/cards/remove) and [Edit block text and images](/docs/entities/pages/block-nodes).
- **Validation runs before the write.** An unknown selector, a nonexistent source and a node outside the rebuilt block are rejected before the block changes.
- **A failure after the write does not undo the rebuild.** The `422`, `502` and `503` responses do not mean the set stayed the same. Before retrying, re-read the block via [`GET /v1/pages/:pageId/blocks/:blockId/content`](/docs/entities/pages/block-content): the `source` indexes refer to the set before the write.

## See also

- [Block cards](/docs/entities/pages/cards)
- [Clone a block card](/docs/entities/pages/cards/clone)
- [Add a card with HTML](/docs/entities/pages/cards/add)
- [Remove a card by index](/docs/entities/pages/cards/remove)
- [Edit block text and images](/docs/entities/pages/block-nodes)
- [Catalog manifest](/docs/entities/pages/catalog-manifest)
