Start in this order
POST https://api.synorb.com/api/connect/demo-key with the body {"client": "<your agent name>"}. The answer holds a Synorb Key that works for both MCP and REST. A person can press Generate Free Agent Key on /connect. Store it only in the host or server secret store. Agent clients that should not hold a long-lived key can use OAuth 2.0 instead.GET /ontology/tags, choose explicit stream_ids, then use MCP or REST.Authorization: Bearer YOUR_SYNORB_KEY
Authenticate
Both credentials are sent the same way — Authorization: Bearer <value> — and both work on MCP and REST. The Synorb Key is the default and is not deprecated.
Choose the transport
Personal agents start with Beacons. Personal agents work in three modes (Watch, Answer, Pull): propose one to three Beacons from what you already know about your user (offering the starter Beacons if you know little), offer to save a Beacon after answering a specific question, and pull Manifests for one-off asks. Save a Beacon only after the user says yes. Beacons are available on every plan, with a per-plan count cap.
For a live website or app, a coding agent may use MCP to understand coverage while building, but the deployed product should call REST from a server-side route. Never put a Synorb Key in browser code. Preserve source citation URLs in the rendered interface.
Non-negotiable query rules
- Ontology first. Never guess a tag name. Resolve it through
/ontology/tags. An unknown tag can return an empty result without an error. - Scope with
stream_ids. Select them from catalog/details first. An explicit emptystream_idslist is rejected withempty_stream_idsat zero usage; omitted scope is deliberately broad.required_surfacesis not reliable execution scope. - Plan before REST execution. Call
POST /manifests/plan, retain the request exactly, then callPOST /manifests/execwith the identical fields plusplan_token. - Honor the fingerprint. Adding or changing any field, including
target_count, invalidates the plan token. A409 invalid_plan_tokenrequires a free re-plan, not a modified retry.
/manifests/query response diagnostics
These additive fields are part of the public response contract. Treat them as machine-readable routing signals before interpreting an empty page, retrying, or presenting a claim.
| Field | How agents should use it |
|---|---|
coverage | Authoritative status and reason for the query outcome. Do not call a zero exact unless coverage is authorized and not an error. |
candidate_projection | Only with include_diagnostics=true. Pre-execution candidate-set proof, including truncation or authorization reasons when Synorb declines to execute a scope. |
final_scope_authorization | Proof that the final scope matches the authorized request. If authorized is false, correct the scope instead of broadening silently. |
citation_contract | Always present in successful query and exec data. status=required means preserve each returned citations/source_url; status=none means the page returned no Manifests. |
did_you_mean | Machine-readable canonical suggestions for unresolved tags or source-channel names. Ask or retry with the suggested canonical field, not the failed text. |
result_fingerprint | Stable identity for the returned result page after scope, authorization, and pagination are applied. Use it for cache/audit comparisons. |
Slim responses
diagnostics, coverage_outcome, candidate_projection and manifest_index are operator/proof blocks that can run tens of KB each, even for a single Manifest — all are dropped by default now, regardless of response_profile. Pass include_diagnostics=true on POST /manifests/query (and its MCP twin synorb-manifests) only if you need the underlying coverage/absence proof; most callers never need this. response_profile="slim" is a separate, additive lever that further drops other operator-only blocks, and trims each Manifest's Brief/Record to citation-grade fields, keeping the usage receipt — tens of KB instead of hundreds for the same page. Neither flag changes which Manifests are returned or billed: quota_charged and the billed count are identical across every combination for the same request.
Billing at a glance
| Action | Manifest usage allowance |
|---|---|
| Catalog, details, ontology, account, count/orient, and plan | Zero |
| Beacon create, list, archive, restore, and delete | Zero |
| Topic-filtered REST execute or Beacon poll | Only returned on-topic Manifests |
| Previously billed repeated Manifest | Not billed again in the same billing period (a repeat in a later period is billed) |
| Invalid request, planning failure, invalid token, or clean empty result | Zero unless a Manifest was returned |
Inspect each response's usage and usage receipt. A target count is a ceiling, not permission to fill results with unrelated content.
Pagination
For GET /streams, GET /streams/{id}/manifests, and other GET lists, fetch a non-null next or prev URL verbatim with the same authentication. null means there is no page in that direction.
POST /manifests/query returns opaque, fully-qualified GET next/prev URLs. Follow them verbatim with the same Authorization header; the server-held cursor carries the original scope and is short-lived. If it expires, repeat the original POST. POST /manifests/exec remains POST-only because execution can bill; its page values are hints to copy into the original body and re-plan.
For /manifests/exec, the plan token signs the exact body: remove the previous plan_token, apply the paging values, POST that body to /manifests/plan for a fresh zero-usage token, then POST the exact newly planned body to /manifests/exec with only the new token added. Reusing the old token after changing paging fields returns 409.
When present, data.pagination.count_as_of is an exact count within the published snapshot identified by count_generation; count_basis is published_snapshot. Later writes appear on a later refresh. Keep the same authentication while following query cursors. Independent requests may receive different generations.
Pages are zero-based: page=0 (or page_num=0) is the first page, and starting at 1 skips it. Follow data.pagination.next and prev instead of counting pages yourself.
data.pagination.next and data.pagination.prev apply to Streams and Manifest queries; GET /v3/beacons uses top-level next/prev. Legacy query fields page, page_num, page_size, has_more, and next_page, plus Beacon limit, offset, and total, remain supported.
Quota and actionable errors
usage.quota_limit, usage.quota_used, and usage.quota_remaining are the response balance snapshot. usage.manifests_billed_this_call and data.quota.manifests_billed_this_call are the call receipt; Manifest-query responses also expose settled data.quota.quota_used and data.quota.quota_remaining. Planning responses can additionally include estimated_max_billed_on_execution and remaining_hard_cap.
For 401 synorb_key_invalid or synorb_key_expired, send POST https://api.synorb.com/api/connect/demo-key for a fresh key, or create an account at /signup. For 404, correct the request from this documentation and openapi.json. For 409, re-plan; for 422, correct the named field; for 429, honor Retry-After; and never call 503 or coverage.status=error an empty result.
Demo-key data freshness
Daily-delivery plans (including the 72 Hour Agent Demo) have an available_through/latest_allowed ceiling that normally trails the wall-clock date by one day (lag_days=1 is normal, not a fault), so relative days and lookback_hours values default to that ceiling: days=1 means the latest available day, not necessarily today.
Inspect GET /account temporal diagnostics and the query response's temporal object (refresh_tier, available_through, lag_days, and effective window) before interpreting an empty recent result.
Beacons: watch vs. pull
Use a Beacon for a reusable watch. Propose it from what you know about your user (or the starter Beacons, tag starter, when you know little) and save it only after a yes. Pull directly for a one-off answer, then offer to save it. Synorb does not run Beacon schedules or push: your runtime pulls on its own cadence with an explicit lookback window and dedupes by Manifest id. A Beacon's natural_language_intent is descriptive only. Convert intent to selected stream_ids and canonical topic_filters first.
[{"tag_id":"tag_123","tag_name":"Payment Systems","tag_type":"topic"}]
Run a saved Beacon through GET /streams/{id}/manifests?beacon_id=... with a time window. Do not use POST /manifests/query to execute it. The full create, poll, archive, restore, and delete lifecycle is in the agent guide.
Machine-readable entry points
billing opens a hosted Stripe handoff.
Public CLI repository Source, plus the agent configs an AI coding agent reads: AGENTS.md, .cursorrules, and an agent-plugins.org plugin.json.
Coding agents
Give the build agent the guide before it writes an integration. It will learn the two-key boundary: MCP for the agent's exploratory session and server-side REST for the shipped user experience, with citations preserved.