Published Page Design
A published board is a public web page. Its design — which elements sit in which region of the page, their content, and the page's background colour and typography — can be created and edited over the API, the same way the Publish editor does it.
Prerequisites
writescope and permission to modify the board.- Page layout API writes enabled for your workspace. Reads work everywhere; every write below answers
403 page_layout_api_disableduntil Playbook support enables it.
1. Discover the vocabulary
curl "https://api.playbook.com/v1/page_layout_elements" \
-H "Authorization: Bearer YOUR_TOKEN"
One global response (no workspace slug) describing everything you can write:
| Key | What it holds |
|---|---|
templates | Valid template ids — the keys — each with display_name, default background colour and typography, and the slots (page regions) it mounts itself. |
elements | Every element type (note, button, banner, section, …) and the camelCase props it accepts. Flags mark props that are HTML, URLs, asset tokens, or dead (stored but no longer rendered). |
background_colors, typographies | The values page settings accept. |
operations | The argument map for batch edits. |
limits | Hard payload caps, e.g. max_batch_operations. |
2. Publish with a template
curl -X POST "https://api.playbook.com/v1/my-org/boards/portfolio/publish" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template": "standard"}'
A publish with a template creates the page design that the layout endpoints read and edit. A board published without one, and never saved in the Publish editor, is still public, but has no design: the layout endpoints answer 404 page_layout_not_found until you publish it with a template.
| Response | Meaning |
|---|---|
422 unknown_template | The id is not a template; the message lists the valid ids. |
409 page_design_exists | The page has stored element edits. They are never overwritten — publish without template to keep them, and edit the design instead. This does not protect a design that is only page settings (background colour, typography): a template publish replaces those. A page still following its template, never edited, simply switches to the new one. |
409 publication_conflict / page_layout_conflict | Someone else changed the publication at the same moment. retryable: true — send the request again. |
503 template_catalogue_unavailable | Templates are temporarily unavailable. Retry later, or publish without a template. |
Every board response (GET /boards/{token}, lists, children) carries the page state:
"published_page": { "active": true, "template": "standard", "url": "https://playbook.com/s/my-org/portfolio" }
url is null unless the page is live, and template can be set on a page that is not.
3. Read the page layout
curl "https://api.playbook.com/v1/my-org/boards/portfolio/page_layout" \
-H "Authorization: Bearer YOUR_TOKEN"
{
"data": {
"uuid": "<uuid>",
"template": "standard",
"background_color": null,
"typography": null,
"slots": null,
"subboards_settings": [],
"version_token": "<opaque version token>"
}
}
slots: nullis normal. A page nobody has edited stores no document and renders its template's defaults. Address such a page by slot name ("slot_id": "description", fromtemplates[...].slots): the first write saves the defaults and its response contains real ids for everything.slotsandsubboards_settingsare returned verbatim. Their ids and camelCase keys are exactly what the write endpoints take back.background_color/typographynullmeans the page inherits them.subboards_settingsholds one full second document per nested board shown on the page. Edit one by sending itscollectionTokenassubboard_tokenon any write.
4. Edit elements
All paths below are under /v1/{slug}/boards/{token}/page_layout.
| Operation | Request |
|---|---|
| Add | POST /elements — slot_id, at_index, element; optional parent_element_id + column_id/column_index/create_new_column to insert into a section |
| Replace | PATCH /elements/{element_id} — slot_id, element |
| Move | POST /elements/{element_id}/move — from_slot_id, to_slot_id, at_index |
| Delete | DELETE /elements/{element_id}?slot_id=… — addressing in the query string |
| Reorder | POST /slots/{slot_id}/reorder — ordered_ids |
| Batch | POST /operations — up to 50 of the above, atomically |
curl -X POST "https://api.playbook.com/v1/my-org/boards/portfolio/page_layout/elements" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"slot_id": "description",
"at_index": 0,
"element": { "id": "intro-note", "elementType": "note", "props": { "text": "<p>Spring collection</p>" } },
"expected_version_token": "<version_token from the read>"
}'
Rules that matter:
- Supply your own
element.idon an add. Re-sending an identical add then succeeds without inserting twice; the same id with different content is409 element_exists. PATCHreplaces the element, not a field. Every top-level key you send replaces the stored one wholesale, so{"props": {"text": "…"}}drops every other prop. Read the element, change it, send the wholepropsback.- Reorder takes the exact set.
ordered_idsmust be the slot's current top-level ids — none missing, repeated or extra — or422 reorder_id_mismatchnames the offenders. - Batches are all-or-nothing. The first failing operation rolls the batch back; the error carries
operation_index. Ids the server mints inside a batch cannot be addressed later in the same batch, so give new elements your own ids. One batch edits one document (the page, or onesubboard_token). - Props flagged as HTML or URLs must be strings. HTML is sanitized and unsafe URL schemes are dropped on write. An asset-token prop takes an asset token from your workspace; Playbook copies the asset into the page's library.
5. Page settings
curl -X PATCH "https://api.playbook.com/v1/my-org/boards/portfolio/page_layout" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"settings": {"backgroundColor": "dark", "typography": null}}'
A partial update: an omitted setting is untouched, null clears it so the page inherits again. Values outside background_colors / typographies are 422 invalid_page_setting. A board following a workspace template stops following it after a real change, so a later template roll-out does not revert your edit.
Working alongside people
- Compare-and-swap. Send the read's
version_tokenasexpected_version_tokenon any write. If the page changed in between you get409 stale_documentand nothing is applied — read again, re-decide, re-send. Responses to a write that sent a token include the newversion_token. - Did anything change?
converged: truemeans the goal already held (deleting an id that is not there, an identical add, a no-op move).materialized: truemeans the call saved the template defaults for a page that had no document. Both are absent when false.PATCHon an element never reportsconverged. - Freshness. The API reflects a write immediately; the public page can serve the previous version for up to an hour.
Errors
Errors use the standard envelope; key on extensions.code, and use retryable to decide whether to repeat the same request.
| Status | Codes |
|---|---|
| 403 | page_layout_api_disabled, board_not_authorized (you cannot modify the board that governs this design), board_read_only |
| 404 | page_layout_not_found, slot_not_found, element_not_found, subboard_not_configured |
| 409 | stale_document (re-read), element_exists (new id or PATCH), lock_wait_timeout and page_layout_library_locked (retry as-is) |
| 422 | invalid_parameter, invalid_prop_type, invalid_element_shape, ambiguous_slot_name, reorder_id_mismatch, invalid_page_setting, forbidden_prop, asset_not_found, element_too_large |
Over MCP
The MCP server exposes the same surface: publish_board (with template), get_page_elements_catalog, get_page_layout, add_page_element, update_page_element, move_page_element, delete_page_element, reorder_page_slot, apply_page_operations and update_page_settings.
One difference: publish_board called without template on a board that is not live and has no page design yet applies standard (or your workspace's own version of it), so the page is editable immediately. A live page and a board that already has a design are republished unchanged. The tool response's template_applied names the template applied, if any.