Skip to content

Record identity

Identity is separated from data. The _match block says which record, and the rest of the document says what to save. This is the single most important concept to get right.

{ "_match": { "id": 123 }, "type": "post", "title": "New title" }

Identifier priority inside _match runs id, then url (posts only), then slug. Without _match, identity falls back to the document’s own id, then its slug.

Identifier Hit Miss
_match.id / _match.url update error octa_not_found, never creates a new record
_match.slug (or the document’s slug) update creates a new record (upsert)
none of the above creates a new record

Follow this rule of thumb.

  • To update an existing record, give the existing slug (and parent, for hierarchical types), or _match.id.
  • To create a new record, omit id and _match, and give a new, unique slug.

For hierarchical types such as pages and hierarchical CPTs, the same slug can exist under different parents. So slug identity is the pair (parent, slug).

  • Always include parent (the parent slug) on hierarchical documents, even when updating. Matching only looks among that parent’s children. A missing parent or 0 means top level.
  • If a slug is ambiguous without a fixed parent, the document is rejected with octa_slug_ambiguous. Octa Editor never guesses which record you meant.
  • A document with a different parent and no _match.id is, by definition, a different record. An upsert creates a new one under the new parent.

Moving a page to a different parent requires _match by id (or url).

{ "_match": { "id": 123 }, "type": "post", "post_type": "page", "parent": "new-parent" }

When identity is unclear, guessing would silently overwrite the wrong record, or silently create a duplicate. Octa Editor instead returns a precise error such as octa_not_found or octa_slug_ambiguous, so you can fix the identifier. For automation this is a feature, because a failed match is loud, not silent.