EN VIVO · CON AUDITORÍA · UE
SISTEMA · 99,99% UPTIME
v 1.0 ↗ HECHO EN UE

nexbasira (Python)

SDK de Python del lado del servidor. Misma superficie de recursos que el SDK de Node, basado en requests para reintentos transparentes, con Session mockeable para las pruebas.

Instalar

pip install nexbasira

Requiere Python 3.10+.

Inicializar

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
)

Recursos

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

Patrones comunes

Crear e invitar

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

Paginación con iterador

# 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()),
)

Verificar 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

El SDK es síncrono por diseño (sin async def en los métodos de recurso). En los manejadores de FastAPI, llámelo desde un run_in_threadpool o utilice 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}

Errores tipados

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

Pruebas — Session mockeable

El SDK utiliza una requests.Session internamente. Pase la suya propia (o un mock) mediante el argumento http_session para interceptarla en las pruebas:

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()

Modelos tipados

Generados a partir de la especificación OpenAPI mediante datamodel-code-generator; importables como dataclasses:

from nexbasira import Session, Evidence, WebhookEvent

def on_completed(session: Session) -> None:
    ...

Qué sigue