Skip to main content

Change Feed

GET /api/v1/changes is a monotonic, cursor-addressable feed of every create/update across every resource type. Each event embeds the full resulting record — there is never a follow-up fetch needed to see what changed.

GET /api/v1/changes?since=<sequence>&limit=<n>[&org=<slug>]
  • since — resume from this sequence number. Defaults to 0 (the beginning of the feed) for an initial backfill.
  • limit — page size. Defaults to 100, capped at 500.
  • org — optional; scopes the feed to one organization by slug. Omit it to see every organization your token has access to. A well-formed but unrecognized slug returns 400 { "code": "unknown-org" }.

The response shape is:

{ "events": [/* ChangeEvent[] */], "nextSince": 123 }

Persist nextSince as your cursor and pass it back as since on your next call. If there are no new events since your last request, the response is { "events": [], "nextSince": <unchanged> } — a stable resume point you can poll against safely.

Ordering and idempotency​

  • Events are strictly ordered by sequence; apply them in the order returned.
  • Applying the same event more than once is safe: key your own storage on (canonicalId, version) and treat an already-applied version as a no-op. This makes retries, re-polls, and (for webhook consumers) redelivered events all safe to process without special-casing.

Event shape​

Every event carries sequence, resourceType, canonicalId, operation ("create" or "update"), version, occurredAt, orgSlug, and record — the full resource payload for that resource type (see Data types for every resource type's field reference, and this site's API reference for the generated schema). Events also carry sourceSystem, an internal code identifying which upstream system produced the change; it's most useful for filtering webhook deliveries (see Webhooks) and can otherwise be ignored.

Worked example​

  1. Poll a page of the change feed, containing one patient creation:
    curl -H "Authorization: Bearer $ROSETTA_SYNC_TOKEN" \
    "https://sync.example.com/api/v1/changes?since=0&limit=100"
    {
    "events": [
    {
    "sequence": 1,
    "resourceType": "patient",
    "canonicalId": "f3024f2e-0583-4759-a9b8-c534e6763391",
    "operation": "create",
    "version": 1,
    "occurredAt": "2026-07-14T04:32:56.082Z",
    "orgSlug": "default",
    "record": {
    "identifiers": [{ "system": "urn:michels:pid", "value": "1234567" }],
    "familyName": "Mueller",
    "givenNames": ["Anna"],
    "birthDate": "1980-05-01",
    "gender": "female"
    }
    }
    ],
    "nextSince": 1
    }
  2. Project the event into your own storage: upsert a patient row keyed by canonicalId with this record payload, keyed additionally on version so a redelivery of sequence: 1 is a no-op.
  3. Advance your cursor: store nextSince (here, 1) and pass it back as since on your next poll.