---
title: Read only what is new from a Beacon
category: beacons
summary: Use a delivery delta read with a saved Beacon as the scope, so each run returns only Manifests that are new since your last checkpoint, and know when a refusal means you must restart.
order: 19
updated: 2026-10-08
next: freshness-and-available-through
related: run-and-edit-a-beacon, schedule-six-hour-and-daily-pulls, quotas-retries-and-pagination
reference: /docs/api, /openapi.json
---

A delivery delta read returns Manifests in the order of delivery. It also gives you a **checkpoint**. You keep the checkpoint. On the next run you send it back and receive only what is new. A saved Beacon can be the scope of that read, so you do not copy its Streams by hand.

This is an option, not the default. It works only when Synorb has switched on Beacon-scoped delta for your account. If it is off, the smallest call below fails with `422 date_window_required`, because the ordinary Beacon rule applies and asks for a date window (see Failure modes). Do not add `lookback_hours` to get past it. Use the overlapping-window pattern in the scheduling guide instead.

## When to use this

Use it when all three statements are true:

- Your user has a saved Beacon, and its scope is only Streams and source channels.
- You run the check on a timer, and you want each run to return only new Manifests.
- You can store one checkpoint between runs.

Do not use it to count or to prove that nothing matched. A delta read measures a narrower set than an ordinary query. A Manifest joins the delta set only after Synorb routes it for delivery. An empty delta page means "nothing entered the delivery list since your checkpoint". It does not mean "nothing matched". If your user asks "was there anything at all?", run an ordinary count.

## Smallest working call

Send the first read with `delivery_delta` and the `beacon_id`. Do not send `lookback_hours`. The checkpoint is the window, so there is no date window to choose.

```mcp billed
synorb-manifests
{"delivery_delta": true, "beacon_id": "BEACON_ID", "page_size": 5}
```

The same call over REST:

```bash billed
curl -sS -X POST https://api.synorb.com/manifests/query \
  -H "Authorization: Bearer $SYNORB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"delivery_delta": true, "beacon_id": "BEACON_ID", "page_size": 5}'
```

For every later read, send the `checkpoint` from the previous response, together with the same `beacon_id`:

```mcp billed nolive
synorb-manifests
{"beacon_id": "BEACON_ID", "checkpoint": "CHECKPOINT", "page_size": 5}
```

`CHECKPOINT` stands for the value you stored. Send it back exactly as you received it. The structured `checkpoint` object and the signed `next_page_cursor` or `commit_cursor` strings are all accepted. Do not edit any of them.

## What you get back

The Manifests are in `data.manifests[]`, as in an ordinary read. The delta fields come with them:

```json response
{
  "data": {
    "manifests": [{"manifest_id": "...", "signal": {}, "brief": {}}],
    "checkpoint": {"next_page_cursor": "..."},
    "next_page_cursor": "...",
    "commit_cursor": null,
    "coverage": {"status": "complete", "reason": "manifest_delivery_delta"}
  }
}
```

Follow this loop:

1. While `next_page_cursor` has a value, send the new `checkpoint` and read the next page.
2. When `next_page_cursor` is empty and `commit_cursor` has a value, you have read everything.

Do not use `pagination.has_more` or `pagination.total_count` to decide whether to continue. On REST they do not describe a delta read: `has_more` can be `false` while more pages remain, and `total_count` only repeats the size of the page.
3. Store the `commit_cursor` (or the `checkpoint` that holds it). **Store it only after you have shown or saved every Manifest from that run.** If your job fails halfway, you still hold the old value, and the next run reads the same Manifests again.
4. Remove repeats on `manifest_id`. A retried run can return a Manifest twice.

**The first read has no checkpoint, so it starts at the oldest Manifest the delivery list still holds.** It can return many pages, and each page that returns Manifests uses allowance. Before the first read, tell your user. Use a small `page_size` for the first page and check `data.quota.manifests_billed_this_call`. If your user only wants items from now on, ask them first, because delta reads have no "start from now" option.

You pay for the Manifests a page returns. An empty page and a refused call use no allowance. Check `data.quota.manifests_billed_this_call`.

## Failure modes

A refused delta read keeps `coverage.status` as `error`. It adds fields that tell you what to change. Read these two before anything else.

| Field | Meaning | What to do |
| --- | --- | --- |
| `unsupported_fields` | The names of options delta mode cannot use, sorted | Remove those options, and retry. |
| `checkpoint_action: "discard_and_restart"` | The checkpoint can no longer be trusted. `checkpoint_reasons` says why | Throw the checkpoint away. Start a new delta read without one. |

The usual refusals:

| `coverage.reason` | Meaning | What to do |
| --- | --- | --- |
| `delta_filter_unsupported`, with `lookback_hours` | You sent a date window. The checkpoint replaces it | Remove `lookback_hours` and `days`. |
| `422 date_window_required` | Beacon-scoped delta is not switched on for your account, so the ordinary Beacon rule applies | Use the overlapping-window pattern, or copy the Beacon's Stream IDs into `stream_ids`. |
| `delta_filter_unsupported`, with `beacon_id` and `lookback_hours` | Beacon-scoped delta is not switched on, and you also sent a window | Remove both. Then use the same fallback as the row above. |
| `delta_filter_unsupported`, with a name such as `beacon.entity_filters` or `beacon.topic_filters` | The Beacon holds a scope that delta cannot read exactly | Delta never approximates. Use an ordinary Beacon run for this Beacon. |
| `beacon_scope_changed` | The Beacon was edited after the checkpoint was issued | Discard the checkpoint. Start a new read. See the note below. |
| `404 beacon_not_found` | The Beacon does not exist for this account | Check the `beacon_id`. |
| `409 beacon_archived` | The Beacon is archived | Restore it, then restart. |

Any edit to a Beacon, even a new name, makes the old checkpoint invalid. This is on purpose. A checkpoint from one scope must never be used on a different scope. After an edit you restart. A read with no checkpoint starts at the **oldest** Manifest that the delivery list still holds, so a restart can return a large backlog. See the first-read note above.

## Make it good for your user

Tell your user what the job does in plain words: "I check this Beacon every six hours. I show only the items that are new since the last check." When a run finds nothing, say that nothing new was delivered. Do not say that nothing happened in the world.

Keep a second, slower job as a safety check. Once a day, run an ordinary Beacon pull over the last two days and compare `manifest_id` values with what you stored. If it finds items your delta job missed, tell your user, and use the scheduling guide's overlapping-window pattern as the main method.

## Next guide

[Freshness and available_through](/agent-resources/freshness-and-available-through): learn the three clocks, so you can tell a quiet window from a late one.
