synorb
Official Python client for the Synorb REST API — source-grounded, cited context for AI agents.
pip install synorb
Zero dependencies. Everything is standard library. An agent installs this into an environment it does not control, so a client that cannot drag in a transitive supply chain or fight an existing requests/httpx pin is worth more than a few convenience methods.
Quick start
from synorb import SynorbClient, connect
# Free 24-hour demo key — no email, no card, no sales contact.
key = connect()["credentials"]["synorb_key"]
client = SynorbClient(token=key)
client.account()
client.streams(page_size=5)
client.stream_search("central bank policy")
Or read the credential from the environment:
export SYNORB_TOKEN="synorb_..."
SynorbClient().account()
Two credentials, one header
| Synorb Key | OAuth 2.0 access token | |
|---|---|---|
| Lifetime | Long-lived | Short-lived |
| Scopes | None — full plan access | Scoped, and enforced per endpoint |
| Revocable | Regenerate the key | Yes, RFC 7009 |
| Get one | synorb.com/connect | synorb.oauth |
Both go in Authorization: Bearer. The client does not try to tell them apart — the server does. The Synorb Key is the default and is not deprecated; most integrations should just use it.
OAuth 2.0
Authorization code + PKCE (S256 only). Public clients, no client secret, and no dynamic client registration — client_id values are issued by Synorb.
from synorb import SynorbClient, oauth
pkce = oauth.generate_pkce()
state = oauth.generate_state()
url = oauth.build_authorize_url(
client_id="synorb-cli",
redirect_uri="http://127.0.0.1:8765/callback",
code_challenge=pkce.challenge,
scope="read:api read:mcp", # ask for only what you need
state=state,
)
# open `url`, sign in, catch the redirect on your loopback listener
tokens = oauth.exchange_code(
code=code_from_redirect,
redirect_uri="http://127.0.0.1:8765/callback",
client_id="synorb-cli",
code_verifier=pkce.verifier,
)
client = SynorbClient(token=tokens["access_token"])
Two things to know before building against it:
scopeis honoured exactly. Omit it and you get the full default read-only grant. Ask for something that cannot be granted — awrite:scope, or anything outside that default — and the request is refused withinvalid_scoperather than quietly trimmed, so a token never claims a permission it does not hold.- Refresh tokens rotate, and reuse is treated as theft. Presenting a refresh token twice revokes the entire family. Store the newest one you were handed; never retry with an old one.
Discovery, if you would rather read it off the wire:
oauth.discover() # https://api.synorb.com/.well-known/oauth-authorization-server
Errors you can actually act on
Synorb's error envelopes are actionable, so they are not collapsed into a bare HTTPError:
from synorb import SynorbAuthError, SynorbInsufficientScope, SynorbRateLimited
try:
client.account()
except SynorbInsufficientScope as exc:
exc.required_scope # "read:webhooks" — the scope the token lacked
except SynorbRateLimited as exc:
exc.retry_after # seconds, from Retry-After
except SynorbAuthError as exc:
exc.resource_metadata # RFC 9728 pointer to the authorization server
SynorbInsufficientScope can only come from an OAuth token. A Synorb Key has no scope concept and is never scope-checked.
Quota
manifests_query() bills only the Manifests it returns. mode="count", "orient" and "plan" are zero-quota previews — plan first, then replay the exact body with the returned plan_token:
plan = client.manifests_query(mode="plan", stream_ids=["..."], lookback_hours=24)
rows = client.manifests_query(stream_ids=["..."], lookback_hours=24, plan_token=plan["data"]["plan_token"])
Discovery calls (streams, stream_search, ask, ontology_tags) do not consume Manifest quota.
No billing methods, on purpose
The @synorb/cli package has synorb billing checkout, which opens a hosted Stripe page for a human to complete. That is a sensible thing to type and a bad thing for a library to expose — an agent calling client.checkout() in a retry loop is a failure mode worth designing out rather than documenting around. Billing stays a deliberate, human, command-line act.
Links
- Docs — https://synorb.com/docs
- Authentication — https://synorb.com/auth
- OpenAPI — https://synorb.com/openapi.json
- MCP server — https://synorb.com/docs/mcp
- CLI — https://www.npmjs.com/package/@synorb/cli
Security
Keep the credential in a server-side secret store. It never belongs in browser code, a repository, logs, or a prompt. Report issues to team@synorb.com.
MIT licensed.
Metadata
Release files for synorb 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| synorb-0.1.0.tar.gz | 15.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| synorb-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 26.5 kB
Release files / synorb-0.1.0.tar.gz
| Download URL | synorb-0.1.0.tar.gz |
|---|---|
| Size | 15.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
713a67058207ad52b7a700b76a24ca19f9c374e967b9628048cedb1d3f1e31f4
|
|
BLAKE2b-256 checksum How to use checksums |
486bb33d8fd2ba047304c4085ac545fbe589cbfff60ef9aa283d767a5e872fa2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.7
|
Release files / synorb-0.1.0-py3-none-any.whl
| Download URL | synorb-0.1.0-py3-none-any.whl |
|---|---|
| Size | 11.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c939d593f9b03b8fff615ddfb26e571016e2515d8af8fc0c6e69b243738b7543
|
|
BLAKE2b-256 checksum How to use checksums |
6ac0a564a2b371bf6fddac33c958573cb7121cceafe2faee3fc204599affbc01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.7
|