Basker Docs

Edit content blocks

Update, add, remove, and reorder content blocks across collections with safe, ordered operations

Many records are built from content blocks. The standard create and update endpoints cannot change blocks — they reject the blocks, theme, and themeSettings fields with a 422. To edit blocks, use the dedicated endpoint, which applies a list of operations to one record:

PATCH /partners/{version}/{tenant}/{collection}/{id}/blocks

Supported collections: pages, blogs, posts, events, people, works, venues, series, seasons, organizations.

Don't guess — discover

Block types, their fields, and valid select values vary by tenant and theme. Discover fields & options describes the …/schema endpoints that tell you exactly what to send.

Draft-safe by design

Every request must set draft: true and include an ifUpdatedAt timestamp. Changes are written to the record's draft only — published content is never altered until you publish it from the admin panel.

How a block looks

A block is { id, type, value }. The value holds the block's fields in the same flattened shape you receive when reading the record, so what you read back is what you send.

{
  "id": "hero_1",
  "type": "hero",
  "value": {
    "heading": "Spring season",
    "body_html": "<p>Now on sale.</p>"
  }
}

Inside value:

  • Rich text accepts either an <field>_html property (an HTML string) or the field's structured rich-text content. The <field>_html form works at the top level and inside array/group sub-fields, and matches the shape reads return.
  • Links and media are set by id — pass the id of the page, event, image, or file you want to reference.
  • Ambiguous links that could point to more than one kind of record take { "relationTo": "events", "value": "evt_123" }.

Creating records with rich-text titles

The same <field>_html convention applies when you create a record. Rich-text fields like richTitle (required on events/pages) take an HTML string via richTitle_html — e.g. { "title": "Spring Gala", "richTitle_html": "<p>Spring Gala</p>" } — so you never hand-build structured rich text.

Operations

Send an operations array. Operations apply in order, and blocks are always targeted by id — never by position.

OperationWhat it doesRequires
updateMerge new field values into a block, leaving its other fields untouchedblockId, value
insertBeforeInsert a new block before another blockblockId, block
insertAfterInsert a new block after another blockblockId, block
appendAdd a new block to the endblock
prependAdd a new block to the startblock
removeDelete a blockblockId
moveBeforeMove a block before another blockblockId, anchorId
moveAfterMove a block after another blockblockId, anchorId
replaceAllReplace the entire block listblocks

New blocks may include an id; omit it to have one assigned for you.

Avoid overwriting newer changes

ifUpdatedAt guards against overwriting edits made after you last read the record:

Read the draft

Fetch the record with ?draft=true and keep its updatedAt value.

Send it back

Pass that value as ifUpdatedAt. If the draft changed in the meantime, the request is rejected with 409 and nothing is written — refetch and try again.

Operations are all-or-nothing: if any operation is invalid, none are applied.

Example

curl -X PATCH \
  -H "Authorization: users API-Key a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
  -H "Content-Type: application/json" \
  -d '{
    "draft": true,
    "ifUpdatedAt": "2026-06-04T10:12:00.000Z",
    "operations": [
      { "op": "update", "blockId": "hero_1", "value": { "heading": "Updated heading" } },
      { "op": "insertAfter", "blockId": "hero_1", "block": { "type": "rich-text", "value": { "body_html": "<p>New section.</p>" } } }
    ]
  }' \
  "https://api.basker.app/partners/2026-02/royal-opera-house/pages/page_123/blocks"

A successful request returns 200 with a summary of what was applied and the updated record:

{
  "versionTarget": "draft",
  "operations": [
    { "op": "update", "status": "applied", "blockId": "hero_1" },
    { "op": "insertAfter", "status": "applied", "blockId": "hero_1", "insertedBlockId": "9f3a1c2b7e4d5a6c8b0d1e2f" }
  ],
  "document": { "id": "page_123", "slug": "home" }
}

The same request shape works for any supported collection — swap pages for events, people, blogs, and so on.

When a request is rejected

StatusMeaning
400The body is malformed, draft is not true, ifUpdatedAt is missing, or an operation names an unknown action
404The record does not exist for this tenant, or the collection does not support block editing
409The record changed since ifUpdatedAt
422An operation failed — an unknown block type or field, a missing target block, or a duplicate block id

See Status codes and Error responses for the full list and response shape.

Theme settings

Theme settings come in two scopes, both edited with a field model — send set (keys to change) and unset (keys to clear) — and both carry the same draft: true and ifUpdatedAt safety as block editing:

{
  "draft": true,
  "ifUpdatedAt": "2026-06-04T10:12:00.000Z",
  "set": { "primaryColor": "#1d4ed8" },
  "unset": ["legacyBanner"]
}

Site-wide theme settings

The theme's global settings apply across the whole site, independent of any one record:

PATCH /partners/{version}/{tenant}/theme/settings

It always targets the tenant's selected theme — there is no id to pass. See Update Theme Settings.

Per-record theme settings

A single record can also carry its own theme settings (for example, a page rendered with its template). Edit one record with:

PATCH /partners/{version}/{tenant}/{collection}/{id}/theme-settings

The allowed keys come from that record's template — its own selection, or the collection default when none is set. Supported for the same collections as block editing (pages, blogs, posts, events, people, works, venues, series, seasons, organizations). See Update Page Theme Settings (each supported collection has its own "Update … Theme Settings" entry).

Unknown setting keys are rejected with 422 in both scopes.

Next steps

On this page