Skip to main content
Every edit to a page document is expressed as a JSON Patch — an array of operations following RFC 6902. Each operation names an op, a path into the document, and a value or from. You send the array to (or call gv.pages.patch(...) from the SDK). By the end of this page you will know how to replace a headline, insert a block, remove a section, and guard against concurrent edits.

A working patch

Replacing the headline on the first child of the page’s NavShell:
patch.sh
curl -X PATCH https://api.gavai.app/v1/workspaces/acme/pages/page_01JABCDEFGHIJKLMNOPQRSTUV \
  -H "Authorization: Bearer gak_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      {
        "op": "replace",
        "path": "/tree/children/0/props/headline",
        "value": "Welcome to Acme"
      }
    ]
  }'
That is the whole edit. The patch is applied to the draft — the live page does not change until you call POST /v1/workspaces/{slug}/pages-publish. You can chain a series of patches, preview the draft in the Builder, and publish only when satisfied.

Reading a path

The path field is an RFC 6901 JSON Pointer into the document tree. It is a slash-separated string. Each segment is either a JSON object key or an array index.
path-anatomy.txt
/tree/children/0/props/headline
│    │        │ │     │
│    │        │ │     └── property name on the block's props object
│    │        │ └──────── the props key
│    │        └────────── array index of the first child
│    └──────────────────── children array on the root block
└───────────────────────── the document's tree key
So /tree/children/0/props/headline reads as “the headline property of the props of the first child of the page tree.” Indexing starts at zero. One special token: - as the final array segment means “append.” Use it with add to push a new element to the end of an array without computing its index.

Operations

Common patches

Replace a headline

Target the props of the block you want to update. The path mirrors the document tree.
replace-headline.json
[
  {
    "op": "replace",
    "path": "/tree/children/0/props/headline",
    "value": "Welcome to Acme"
  }
]
/tree/children/0 addresses the first child of the NavShell — typically the Hero. Adjust the index for whichever block you are targeting.

Append a block

Use add with "-" to append to the children array without computing the next index.
append-cta.json
[
  {
    "op": "add",
    "path": "/tree/children/-",
    "value": {
      "block": "Cta",
      "props": {
        "headline": "Ready to start?",
        "cta_label": "Get started",
        "cta_href": "/signup",
        "variant": "centered"
      }
    }
  }
]
To insert at a specific position instead of appending, use a numeric index — "/tree/children/2" inserts at position 2 and shifts existing siblings right.

Remove a block

remove deletes the value at the path. For a block, it deletes the entire subtree.
remove-block.json
[
  {
    "op": "remove",
    "path": "/tree/children/1"
  }
]
After a remove, the remaining siblings shift down to fill the gap. If your next operation targets a sibling by index, recalculate the index — what was at /tree/children/2 is now at /tree/children/1.

Guard against concurrent edits

Lead with a test operation that asserts the current value. If another writer has changed the document since you fetched it, your test fails and the entire patch is rejected — the document stays unchanged.
guarded-patch.json
[
  { "op": "test",    "path": "/tree/children/0/props/headline", "value": "Welcome to Acme" },
  { "op": "replace", "path": "/tree/children/0/props/headline", "value": "Welcome back" }
]
This is the safest way to apply an edit when multiple agents or humans may be patching the same page.

Applying patches

curl -X PATCH https://api.gavai.app/v1/workspaces/acme/pages/page_01JABCDEFGHIJKLMNOPQRSTUV \
  -H "Authorization: Bearer gak_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "operations": [
      {
        "op": "replace",
        "path": "/tree/children/0/props/headline",
        "value": "Welcome to Acme"
      }
    ]
  }'

Draft vs. live

PATCH writes to the draft. Live visitors do not see the change until you publish. This is deliberate — it lets you batch edits, preview in the Builder, and publish atomically. The publish call creates a version snapshot, so any prior live version remains reachable for rollback.

Where to go next