---
title: Quotas, retries and pagination
category: connect
summary: Know which calls cost usage, which errors are safe to retry, and how to page through catalogs and Manifests without losing items.
order: 3
updated: 2026-10-07
next: search-streams-in-depth
related: read-the-response-envelope, troubleshoot-channels-stale-crawls-and-quota
reference: /agent-guide.md, /openapi.json, /pricing
---

Most Synorb calls are free. Only a call that actually **returns** Manifests uses your allowance. Synorb does not bill a repeated Manifest twice. Knowing that split lets you explore freely and spend deliberately.

## When to use this

Use this guide before you put Synorb behind a loop, a schedule or a user-facing feature. It tells you what to check on every response, what to retry, and what to never retry.

## Smallest working call

List five audio Streams in one domain. Catalog calls are free, and the response has pages:

```bash
curl -sS "https://api.synorb.com/streams?media_format=audio&home_domain=economics-business-work&page_size=5" \
  -H "Authorization: Bearer $SYNORB_KEY"
```

The page carries its own `next` link. Call it verbatim with the same header until it is `null`:

```bash
curl -sS "NEXT_URL_FROM_data.pagination.next" \
  -H "Authorization: Bearer $SYNORB_KEY"
```

Then preview a Manifest pull without spending anything. `mode: "count"` returns an exact total and bills nothing (`STREAM_ID` is a Stream ID from search):

```bash
curl -sS -X POST https://api.synorb.com/manifests/query \
  -H "Authorization: Bearer $SYNORB_KEY" \
  -H "Content-Type: application/json" \
  -d '{"stream_ids": ["STREAM_ID"], "days": 2, "mode": "count"}'
```

## What you get back

Catalog responses put paging inside `data.pagination`, never at the top level:

```json response
{
  "data": {
    "pagination": {"page_num": 0, "page_size": 5, "next": "https://api.synorb.com/streams?...", "prev": null}
  }
}
```

### What costs usage

| Operation | Manifest usage |
| --- | --- |
| `mode: "count"`, `mode: "orient"`, `POST /manifests/plan` | Zero |
| Stream, catalog, details, Tag and profile calls | Zero |
| Beacon create, list, edit, archive, restore, delete | Zero |
| A pull that returns nothing, or an extraction failure | Zero unless a Manifest was actually returned |
| A pull that returns Manifests | Only the returned, on-topic Manifests |
| A Manifest you already received | Not billed again inside the dedup window |

Always read the receipt, not the HTTP status: `data.quota.manifests_billed_this_call` on a Manifest response, and `usage` on `GET /account`. `target_count` is a ceiling, never a promise. Synorb does not pad a result with unrelated Manifests to reach it.

### Paging by call type

| You called | `next` is | You do |
| --- | --- | --- |
| A catalog or Beacon list (GET) | A full GET URL, `null` at the end | GET it verbatim with the same auth |
| `POST /manifests/query` with `mode` omitted or `default` | An opaque full GET URL bound to your key | GET it verbatim. Do not rebuild the body. If the cursor expired, repeat the original POST |
| `POST /manifests/query` with `mode: count` or `orient` | A URL with no cursor (a bare GET returns 405) | Re-POST your **original** body to that URL |
| `POST /manifests/exec` | A POST paging hint | Copy the paging values into your body, get a fresh plan token, and exec again |

## Failure modes

| Status and code | Meaning | Retry? |
| --- | --- | --- |
| `429` with `error_code: rate_limited` | Too many requests | Yes. Wait for the `Retry-After` header, then retry. |
| `429` with `error_code: quota_exhausted` on a demo key | The 25-Manifest demo allowance is used | No. Read `key_expires_at` and `starter_bind`; bind an email. There is no `Retry-After`. |
| `429` for monthly exhaustion | The period's allowance is used | No, until `quota_resets_on`. Tell your user. |
| `index_proof_unavailable` with `retryable: true` and `action: retry_same_request` | A transient index-consistency check | Yes. Re-POST the same body to `action_url` after a short delay. Nothing was billed. |
| `409` invalid plan token | The body changed between plan and exec | No. Plan again with the full new request. |
| `401`, `403`, `404`, `422` | Your request or credential is wrong | No. Fix the request. Retrying cannot help. |
| An MCP `synorb-manifests` result flagged as a tool error, with a usage line that shows `0 Manifests remaining` and an upgrade link | The key has no allowance left. Over MCP, even a free `count` is reported as a tool error in this state, while REST returns HTTP 200 for the same count | Stop. Read the usage line. Tell your user. Bind an email or upgrade. Do not retry. |
| Network timeout or `5xx` | Transport trouble | Retry with exponential backoff and a cap. This is ordinary client practice. It is not a Synorb promise. Check usage before assuming a charge. |

Two traps cost people time. First, an explicit empty `stream_ids: []` returns the error `empty_stream_ids` at zero usage. But if you **omit** `stream_ids`, you get a deliberately broad query across the visible catalog. Omit it only when you mean broad.

Second, Synorb IDs are 17 to 19 digits long. Pass them as strings. A JavaScript number silently rounds the last digits and you will query a Stream that does not exist.

## Make it good for your user

Budget out loud. Before a large pull, run `mode: "count"` and tell your user what you found: "There are 41 new items in your window. I will read the strongest eight." Use the free preview to choose.

Then spend usage only on the items you will show. When a limit stops a call, say what happened and what your user can do about it. Do not fail without a message.

## Next guide

[Search Streams in depth](/agent-resources/search-streams-in-depth): with a key and a feel for cost, learn to find the right Streams.
