norbix-python
Official Python SDK for Norbix. Use split clients with flat module access:
NorbixApifor API scope (client.database,client.membership, ...)NorbixHubfor Hub scope (client.database,client.account, ...)
Install
uv add norbix
Optional: load .env in apps with python-dotenv (load_dotenv() before constructing Norbix()).
Quickstart
from norbix_python import NorbixApi
# Service mode
norbix = NorbixApi(api_key="<api_key>", project_id="proj_123")
norbix.database.find("orders", take=20, skip=0, orderBy=[{"field": "createdAt", "direction": "desc"}])
# User mode
from norbix_python import LoginCredentials, NorbixApi
norbix = NorbixApi(project_id="proj_123")
norbix.login(LoginCredentials(user_name="alice@team.io", password="secret"))
norbix.database.find("orders", take=10)
Async client
from norbix_python import AsyncNorbix
async def main() -> None:
async with AsyncNorbix(api_key="...", project_id="proj_123") as client:
await client.api.echo.echo()
# asyncio.run(main())
Real-world examples
1) List recent orders (API scope)
from norbix_python import DatabaseFindResult, NorbixApi, NorbixError
norbix = NorbixApi(api_key="sk_live_xxx", project_id="proj_123")
try:
raw = norbix.database.find("orders", take=20, skip=0, orderBy=[{"field": "createdAt", "direction": "desc"}])
typed = DatabaseFindResult.model_validate(raw) if isinstance(raw, dict) else DatabaseFindResult()
items = typed.results
print(f"Fetched {len(items)} orders")
except NorbixError as exc:
print(exc.code, exc.status, exc.message)
2) Login as user and load profile
from norbix_python import LoginCredentials, NorbixApi
norbix = NorbixApi(project_id="proj_123")
auth = norbix.login(LoginCredentials(user_name="alice@team.io", password="secret"))
print("Logged in, token prefix:", str(auth.get("bearerToken", ""))[:16])
users = norbix.membership.get_users()
print("Users response:", users)
3) Account-scoped Hub call (requires account_id)
from norbix_python import NorbixHub
norbix = NorbixHub(
api_key="sk_live_xxx",
project_id="proj_123",
account_id="acc_456", # required for account-scoped endpoints
)
account = norbix.account.get_account_profile()
print(account)
4) Preview a notification with its signed link (no sign-in)
A preview link carries a signed hash. The hash alone is the key: no API key
and no login are needed. If the client does have a key or a token, it is still
sent.
from norbix_python import NorbixHub
norbix = NorbixHub(project_id="proj_123") # no api_key, no bearer_token
preview = norbix.notifications.preview_push_notification(hash=signed_link)
preview_email_notification and preview_sms_notification work the same way.
A signed-in member can pass projectId + notificationId instead of hash.
The gateway answers 401 for a bad or expired link, 403 for a missing
permission and 400 for a malformed request.
End-user AI chat and project AI settings
A signed-in project user (bearer token from login) talks to the project's AI
assistant through norbix.api.ai. start_end_user_chat_turn answers at once
with a turnId; the answer streams over the gateway's SSE endpoint on the
user's own channel ai-chat:{projectId}:{authId} (events ai.chat.turn.*,
ai.chat.session.*). A subscription to another user's channel is refused with
403 and responseStatus.errorCode = "AiChatChannelRefused" — do not retry it.
avail = norbix.api.ai.get_end_user_chat_availability()
session = norbix.api.ai.create_end_user_chat_session(title="Help")
turn = norbix.api.ai.start_end_user_chat_turn(sessionId=session["id"], message="What can you do?")
entries = norbix.api.ai.get_end_user_chat_entries(session_id=session["id"])
Project owners configure the assistant on the Hub: norbix.hub.account
(get_project_ai_settings, update_project_ai_settings,
create_project_ai_assistant, update_project_ai_assistant,
delete_project_ai_assistant, get_project_ai_usage, set_admin_portal_enabled)
and norbix.hub.ai (get_embedding_integrations, save_embedding_integration,
get_embedding_integration, delete_embedding_integration,
test_embedding_integration, set_llm_integration_as_default). Full tables:
docs/api/ai.md, docs/hub/ai.md,
docs/hub/account.md.
Errors
from norbix_python import NorbixError
try:
norbix.files.get_file_info(integration_id, path="a/b.txt")
except NorbixError as exc:
# http_status / error_code are the names every Norbix SDK uses.
# status / code are the same values, kept for older code.
print(exc.http_status, exc.error_code, exc.message)
for item in exc.errors:
print(item.error_code, item.field_name, item.message)
print(exc.body) # the answer exactly as it arrived
message and error_code are the gateway's own. The gateway puts them inside
responseStatus.errors[], so the SDK reads that list first, takes the first
entry for the message and the code, and keeps every entry in errors. Only
when the body has no responseStatus are the top-level message and
errorCode read. Request failed (HTTP <status>) with the code
HTTP_<status> is the last fallback, used when the body says nothing — a 500
page that is not JSON, say.
Breaking change — a refused call now raises
The gateway answers a business refusal (an unknown id, a rule that says no)
with HTTP 200 and responseStatus.isSuccess = False. The SDK used to hand
that answer back as a normal value, so code carried on as if the call had
worked. It now raises a NorbixError with http_status 200 and the gateway's
message and error code.
If your code checked result["responseStatus"]["isSuccess"] itself, move that
check into a try / except. Endpoints that answer with raw bytes rather than a
document (file download, the public file link) are not JSON and are unchanged.
Both the sync and the async client follow the same rule.
Breaking changes (recent major-style refresh)
- Methods use snake_case (
find_one,get_database_schemas) instead of camelCase. - Path parameters are positional or keyword arguments (for example
find("orders", ...),find_one("orders", id)). Remaining query/body fields are passed as keyword args. - Use typed errors where helpful:
AuthenticationError,NotFoundError,RateLimitError,ValidationError(all subclassNorbixError).
Authentication
- API key: set
api_keyorNORBIX_API_KEY - JWT bearer: set
bearer_token,NORBIX_BEARER_TOKEN, or callnorbix.login(...) - If both are configured, bearer token wins
- If neither is configured, SDK raises
NORBIX_NOT_AUTHENTICATED
API keys and JWTs are sent as Authorization: Bearer ... (document your backend expectations).
Configuration from environment
NORBIX_API_KEY=sk_live_...
NORBIX_PROJECT_ID=proj_123
NORBIX_ACCOUNT_ID=acc_456
NORBIX_API_URL=https://api.norbix.ai
NORBIX_HUB_URL=https://hub.norbix.ai
NORBIX_REGION=nb-eu-germany
norbix = NorbixApi() # reads from environment when values omitted
Multi-region support
Norbix can run a project in one or more regions (region codes like
nb-eu-germany). The SDK has no default region: when no region is
configured, no region header is sent and the standard base URLs are used.
Selecting a region
Resolution order: explicit region= on the client → NORBIX_REGION
environment variable → unset (no header).
from norbix_python import Norbix
norbix = Norbix(api_key="sk_live_xxx", project_id="proj_123", region="nb-eu-germany")
region= is accepted by all clients: Norbix, NorbixApi, NorbixHub,
and AsyncNorbix. Every request then carries the nb-region header.
Switching at runtime
norbix.set_region("nb-eu-germany") # subsequent requests target this region
norbix.get_region() # "nb-eu-germany"
norbix.set_region(None) # clear — no nb-region header is sent
Available on the sync clients and AsyncNorbix alike.
Per-call override (header only)
The client.hub.regions methods accept a per-call region= that overrides
the client default for that request's nb-region header only — the
request URL is never changed by a per-call region:
norbix.hub.regions.list(region="nb-us-east")
Regional base URLs
When a region is set and you are using the SDK-default base URLs
(https://api.norbix.ai / https://hub.norbix.ai), the SDK prefixes the
region as a subdomain:
region="nb-eu-germany" → https://nb-eu-germany.api.norbix.ai
https://nb-eu-germany.hub.norbix.ai
Custom base URLs (base_url_api=, base_url_hub=, NORBIX_API_URL,
NORBIX_HUB_URL) are never rewritten — self-hosted and custom
deployments are unaffected; the nb-region header is still sent when a
region is configured.
Managing regions (Hub, account scope)
These endpoints require account_id (see
Project vs account scope).
from norbix_python import NorbixHub
norbix = NorbixHub(api_key="sk_live_xxx", project_id="proj_123", account_id="acc_456")
# Regions available to the account.
# Response shape: {"items": [{"id": ..., "continent": ..., "name": ...}, ...]}
# where "id" is the region code (e.g. "nb-eu-germany").
regions = norbix.regions.list()
# Update the regions a project runs in (omitted fields are left unchanged)
norbix.regions.update_project_regions(
"proj_123",
primary_region="nb-eu-germany",
additional_regions=["nb-us-east"],
)
# Pin a new project to regions at creation time
norbix.account.create_project(
name="my-project",
primary_region="nb-eu-germany",
additional_regions=["nb-us-east"],
)
With the combined client the same modules live under client.hub
(norbix.hub.regions.list(), norbix.hub.account.create_project(...)).
Async
from norbix_python import AsyncNorbix
async def main() -> None:
async with AsyncNorbix(
api_key="sk_live_xxx",
project_id="proj_123",
account_id="acc_456",
region="nb-eu-germany",
) as client:
regions = await client.hub.regions.list()
await client.hub.regions.update_project_regions(
"proj_123",
primary_region="nb-eu-germany",
region="nb-us-east", # per-call header override
)
client.set_region(None) # clear at runtime
Project vs account scope
project_idis required (set explicitly or via env).account_idis optional- Account-scoped Hub methods raise
NORBIX_ACCOUNT_SCOPE_REQUIREDifaccount_idis not configured - Optional-scope methods (the signed notification preview links) send auth when the client has a token and never require one
SDK maintenance
Regenerate API and Hub modules from DTO stubs:
uv run python scripts/generate_endpoints.py
This refreshes src/norbix_python/api/, hub/, matching tests under tests/api and tests/hub, and docs under docs/.
Development
uv sync
uv run ruff check .
uv run mypy src
uv run pytest
Versioning
The major version is frozen at v3 until the public launch.
- A breaking change is released as a minor (for example v3.2.0 → v3.3.0), never as a new major.
- Write it as
feat(<scope>): <what>and add a lineBreaking: <what changed and what callers must do>in plain words, in the pull-request body and in the commit message. - Never mark it the conventional-commits way: no
!in the title (feat!:), no BREAKING CHANGE footer. ThePR titlecheck fails a pull request that does. - As a safety net, the release config (
pyproject.toml→commit_parser, seescripts/release_parser.py) maps breaking commits to a minor, so one that slips through still does not bump the major.
Releases
Pushes to main, next, and beta run
python-semantic-release
and publish to PyPI.
License
MIT
Metadata
Release files for norbix 3.2.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 | Provenance | |
|---|---|---|---|---|
| norbix-3.2.0.tar.gz | 332.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| norbix-3.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 389.2 kB
Release files / norbix-3.2.0.tar.gz
| Download URL | norbix-3.2.0.tar.gz |
|---|---|
| Size | 332.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ff1fd68547629719bd13fae474c3592e2ec15764fe798623a3685bbf3fc34615
|
|
BLAKE2b-256 checksum How to use checksums |
cf65ac9ee53bba6934265f612b84548db146954e4e226a19eaeb45f77333d1ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / norbix-3.2.0-py3-none-any.whl
| Download URL | norbix-3.2.0-py3-none-any.whl |
|---|---|
| Size | 56.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
68d162ee17ff0ce13907491c000636d7e73048a589752af242866711f5d34a8b
|
|
BLAKE2b-256 checksum How to use checksums |
f5825c61689685ce27d8bdc4ef44cd27c5c553672189ab71805e6abc37fbad87
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.12.22 {"installer":{"name":"uv","version":"0.12.22","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for norbix 3.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.