Change feed (CDC)

Change feed (CDC) #

GET /_changes serves a collection’s change log tail from the shard engines’ WALs, so external systems can replicate Pizza data elsewhere — off-site disaster recovery, secondary indexing, audit pipelines — with a standard poll loop:

GET /demo:orders/_changes?since=abc:3,def:1&limit=1000
{
  "results": [
    {"shard":"abc…","rolling_id":0,"epoch_id":4,"seq":0,
     "id":"0,7","key":"u1","op":"create","doc":{"qty":3}},
    {"shard":"abc…","rolling_id":0,"epoch_id":4,"seq":1,
     "id":"0,8","op":"delete"}
  ],
  "cursors":     {"abc…": 4, "def…": 1},
  "purged_below": {"abc…": 3},
  "active":      {"abc…": 5},
  "pending":     true
}

Request #

GET /_changes
GET /<targets>/_changes

Path parameters #

  • targets
    (Optional, string) Comma-separated collection names (wildcard supported); the target-less form feeds every collection.

Query parameters #

  • since
    (Optional, string) Per-shard epoch cursors from a previous response, shard_hex:epoch,shard_hex:epoch. Omit to start from the beginning of the retained tail.
  • limit
    (Optional, integer) Maximum rows to return. Defaults to 1000.

Consuming the feed #

  1. Poll with the cursors of the previous response as the next since (persist the cursors — they are the checkpoint).
  2. pending: true means more rows exist beyond limit; poll again immediately, otherwise poll at your cadence.
  3. Compare each cursor against purged_below: a cursor below that floor means the WAL retention window (wal.local.retention_epoch / retention_bytes) has already purged part of the tail for that shard. The tail is incomplete — run a full resync (search + re-bulk into the DR cluster) and resume from the current cursors.

Every write path (index/replace/update/delete) appends a WAL entry on the primary and every replica, so the feed reads from whichever copy of the shard group is allocated to the node serving the request (primary preferred).

Calendar September 24, 2026
Edit Edit this page