nexbasira (Python)
SDK Python côté serveur. Même surface de ressources que le SDK Node, basé sur requests pour des nouvelles tentatives transparentes, Session mockable pour les tests.
Installation
pip install nexbasira Nécessite Python 3.10+.
Initialisation
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
) Ressources
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 Patterns courants
Créer + inviter
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 Pagination par itérateur
# 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 idempotent
import uuid
session = nb.sessions.create(
notes="...",
idempotency_key=str(uuid.uuid4()),
) Vérifier 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
Le SDK est synchrone par conception (pas d'async def sur les méthodes de ressource). Dans les handlers FastAPI, appelez-le depuis un run_in_threadpool ou utilisez 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} Erreurs typées
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 Tests — Session mockable
Le SDK utilise une requests.Session en interne. Passez la vôtre (ou un mock) via le kwarg http_session pour intercepter dans les 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() Modèles typés
Générés depuis la spécification OpenAPI via datamodel-code-generator ; importables comme dataclasses :
from nexbasira import Session, Evidence, WebhookEvent
def on_completed(session: Session) -> None:
...