nexbasira (Python)
Server-side Python SDK. Same resource surface as the Node SDK, requests-backed for transparent retries, mockable Session for tests.
Install
pip install nexbasira Requires Python 3.10+.
Initialise
from nexbasira import NexBasira
nb = NexBasira(
api_key=os.environ["NB_PUBLIC_KEY"],
api_secret=os.environ["NB_SECRET_KEY"],
# base_url="https://app.nexbasira.com/api/v1/public", # default
# timeout=30, # default
) Resources
nb.sessions # create / list / retrieve / end / invite
nb.evidence # list / retrieve / signed download URL
nb.whiteboards # list per session
nb.webhooks # register / rotate_secret / test_fire / construct_event
nb.branding # read-only
nb.org # read-only Common patterns
Create + invite
session = nb.sessions.create(
notes="Vehicle damage claim CL-2026-0042",
scheduled_for="2026-05-23T10:00:00Z",
locale="fr",
)
invite = nb.sessions.invite(
session.id,
recipient_email="alex@policyholder.com",
send_email=True,
)
print(invite.url) # shown ONCE Iterator pagination
# Auto-pages through all sessions:
for session in nb.sessions.iter(limit=50):
print(session.id, session.status)
# Or one page at a time if you want pagination control:
page = nb.sessions.list_page(limit=25)
# page.data, page.has_more, page.next_cursor Idempotent POST
import uuid
session = nb.sessions.create(
notes="...",
idempotency_key=str(uuid.uuid4()),
) Verifying a webhook (Flask)
from flask import Flask, request, abort
from nexbasira import NexBasira, InvalidSignatureError
app = Flask(__name__)
nb = NexBasira(api_key="...", api_secret="...")
@app.post("/nb-webhook")
def webhook():
sig = request.headers.get("NB-Signature", "")
secret = os.environ["NB_WEBHOOK_SECRET"]
try:
# IMPORTANT: pass request.data (raw bytes), NOT request.get_json()
event = nb.webhooks.construct_event(request.data, sig, secret)
except InvalidSignatureError:
abort(401, "bad signature")
if event.type == "session.completed":
on_completed(event.data)
elif event.type == "audit.anchored":
on_anchored(event.data)
return "", 204 FastAPI / async
The SDK is sync by design (no async def on the resource
methods). In FastAPI handlers, call it from a run_in_threadpool
or use anyio.to_thread.run_sync():
from fastapi import FastAPI, Request, HTTPException
from anyio.to_thread import run_sync
from nexbasira import InvalidSignatureError
app = FastAPI()
@app.post("/nb-webhook")
async def webhook(req: Request):
body = await req.body()
sig = req.headers.get("nb-signature", "")
try:
event = await run_sync(
nb.webhooks.construct_event, body, sig, WEBHOOK_SECRET,
)
except InvalidSignatureError:
raise HTTPException(401, "bad signature")
return {"ok": True} Typed errors
from nexbasira import (
AuthenticationError,
PermissionError,
NotFoundError,
RateLimitError,
InvalidSignatureError,
NexBasiraError,
)
try:
nb.sessions.create(...)
except RateLimitError as e:
time.sleep(e.retry_after_seconds)
# retry
except NexBasiraError as e:
log.warning("nb error: %s (status=%d)", e.code, e.status)
raise Testing — mockable Session
The SDK uses a requests.Session under the hood. Pass your
own (or a mock) via the http_session kwarg to intercept
in tests:
from unittest.mock import MagicMock
from nexbasira import NexBasira
def test_my_handler():
session = MagicMock()
session.request.return_value.status_code = 201
session.request.return_value.json.return_value = {"id": "sess-1", "status": "created", ...}
nb = NexBasira(api_key="x", api_secret="y", http_session=session)
s = nb.sessions.create(notes="test")
assert s.id == "sess-1"
session.request.assert_called_once() Typed models
Generated from the OpenAPI spec via datamodel-code-generator;
importable as dataclasses:
from nexbasira import Session, Evidence, WebhookEvent
def on_completed(session: Session) -> None:
...