Skip to main content

norbix-python

CI PyPI Python License

Official Python SDK for Norbix. Use split clients with flat module access:

  • NorbixApi for API scope (client.database, client.membership, client.public, ...)
  • NorbixHub for 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)

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.

Project settings, public pages, MCP and AI service users

Project owners manage the Admin Portal and legal pages on the Hub, norbix.hub.account: update_project_admin_url, update_project_legal_documents, update_project_expose_legal, get_admin_portal_structure, assign_admin_portal_service_user. Two switches choose what the public Admin Portal config shows: update_project_expose_brand (brand, on by default) and update_project_expose_auth (sign-in methods and password policy, off by default).

Once the legal pages are exposed, anyone can read them — and the project's public config — from the API host with no sign-in, norbix.api.public:

norbix.hub.account.update_project_legal_documents("proj_123", termsMarkdown="# Terms", privacyMarkdown="# Privacy")
norbix.hub.account.update_project_expose_legal("proj_123", exposed=True)
norbix.api.public.get_public_project_legal("proj_123", "terms")  # {"kind", "title", "body", "available"}
norbix.api.public.get_public_project_config("proj_123")

AI agents reach Norbix through the developer MCP endpoint with an AI service user key: create_ai_service_user, list_ai_service_users, rotate_ai_service_user_key, revoke_ai_service_user_key, delete_ai_service_user, then mcp / mcp_stream / mcp_end_session. Full tables and an MCP example: docs/hub/account.md, docs/api/public.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 subclass NorbixError).

Authentication

  • API key: set api_key or NORBIX_API_KEY
  • JWT bearer: set bearer_token, NORBIX_BEARER_TOKEN, or call norbix.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_id is required (set explicitly or via env).
  • account_id is optional
  • Account-scoped Hub methods raise NORBIX_ACCOUNT_SCOPE_REQUIRED if account_id is 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 line Breaking: <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. The PR title check fails a pull request that does.
  • As a safety net, the release config (pyproject.toml → commit_parser, see scripts/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.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for norbix 3.6.0
File Size Uploaded Provenance
norbix-3.6.0.tar.gz 357.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for norbix 3.6.0
File Interpreter ABI Platform
norbix-3.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 423.4 kB

Release files / norbix-3.6.0.tar.gz

Download URL norbix-3.6.0.tar.gz
Size 357.6 kB
Tags Source
SHA-256 checksum
How to use checksums
b34e89bb16924ed5146e3dac405c2c5177c5b771fb5fc6074b3f681c73ec8e6a
BLAKE2b-256 checksum
How to use checksums
a4f9211edd125b6cbe7419bf3cdf553d054f6b9b318bff2906f0e4e6f4deafaa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","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.6.0-py3-none-any.whl

Download URL norbix-3.6.0-py3-none-any.whl
Size 65.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d7e19199cbec5557092acf29534c13aeb7a65973641f34382c3b8929e8631c92
BLAKE2b-256 checksum
How to use checksums
1f294b1f6fd367dd79305b28be6215c5c2392257aea75aff9bbfc24b43673f3d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","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.6.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.

Release history Release notifications | RSS feed

This release

3.6.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page