nexbasira (Python)
SDK Python lato server. Stessa superficie di risorse dell'SDK Node, basato su requests per retry trasparenti, Session mockabile per i test.
Installazione
pip install nexbasira Richiede Python 3.10+.
Inizializzazione
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
) Risorse
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 Pattern comuni
Crea + invita
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 Paginazione con iterator
# 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 POST idempotente
import uuid
session = nb.sessions.create(
notes="...",
idempotency_key=str(uuid.uuid4()),
) Verificare un 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
L'SDK è sync per design (nessun async def sui metodi delle risorse). Negli handler FastAPI, chiamalo da un run_in_threadpool o usa 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} Errori tipizzati
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 — Session mockabile
L'SDK usa una requests.Session sotto il cofano. Passa la tua (o un mock) tramite il kwarg http_session per intercettare nei test:
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() Modelli tipizzati
Generati dalla spec OpenAPI con datamodel-code-generator; importabili come dataclass:
from nexbasira import Session, Evidence, WebhookEvent
def on_completed(session: Session) -> None:
...