LIVE · CATENA D'AUDIT · UE
SISTEMA · 99,99% UPTIME
v 1.0 ↗ FATTO IN UE

API Sessioni

Una Session è una singola ispezione. Creane una, genera un invito per l'utente sul campo, cattura le prove, terminala. Tutto il resto dipende da questa risorsa.

L'oggetto Session

{
  "id": "0c8f4d2e-1a3b-4c5d-9e7f-1234567890ab",
  "status": "open",
  "operator_email": "ops@yourco.com",
  "scheduled_for": "2026-05-23T10:00:00Z",
  "started_at": "2026-05-23T10:00:14Z",
  "ended_at": null,
  "notes": "Vehicle damage — claim CL-2026-0042",
  "locale": "fr",
  "consent_state": { "camera": "granted", "gps": "granted" },
  "campaign": null,
  "created_at": "2026-05-21T14:21:00Z",
  "updated_at": "2026-05-23T10:00:14Z"
}
StatoSignificato
createdLa riga Session esiste; nessuno si è ancora unito.
openL'utente sul campo si è unito; la sessione è live.
recordingRegistrazione in corso (opzionale, attivata dall'operatore).
closedSessione terminata. Testa della catena ancorata alla TSA; report disponibili.
expiredSessione programmata a cui nessuno si è unito entro il TTL.

Crea una sessione

POST /api/v1/public/sessions — scope sessions:write

curl -X POST https://app.nexbasira.com/api/v1/public/sessions \
  -H "Authorization: Bearer nb_sec_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "notes": "Vehicle damage — claim CL-2026-0042",
    "scheduled_for": "2026-05-23T10:00:00Z",
    "locale": "fr"
  }'

Restituisce l'oggetto Session appena creato (HTTP 201).

Campi del body

CampoTipoObbligatorioNote
notesstringnoVisibile all'operatore. Mostrato nelle email di invito.
scheduled_forISO 8601noUna data futura attiva le email di promemoria 24h + 1h prima. Ometti per "inizia ora".
localestringnoUna delle 14 lingue supportate. Determina la lingua della SPA + del report PDF. Il default è la preferenza dell'org.
campaignUUIDnoFK opzionale a una Campaign per il reporting in batch.

Elenca le sessioni

GET /api/v1/public/sessions — scope sessions:read

curl https://app.nexbasira.com/api/v1/public/sessions?limit=25 \
  -H "Authorization: Bearer nb_sec_..."

Paginata a cursore. Passa cursor dalla risposta precedente next_cursor per paginare.

{
  "data": [{ /* Session, Session, ... */ }],
  "has_more": true,
  "next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAy..."
}

Recupera una sessione

GET /api/v1/public/sessions/{session_id} — scope sessions:read

Termina una sessione

POST /api/v1/public/sessions/{session_id}/end — scope sessions:write

Chiude la sessione, attiva l'ancoraggio della testa della catena su tutte le TSA configurate e avvia il post-processing della registrazione se ne era in corso una. Idempotente — chiamarla su una sessione già chiusa restituisce l'oggetto Session chiuso senza ri-ancorare.

Genera un invito per l'utente sul campo

POST /api/v1/public/sessions/{session_id}/participants — scope participants:write

curl -X POST https://app.nexbasira.com/api/v1/public/sessions/0c8f.../participants \
  -H "Authorization: Bearer nb_sec_..." \
  -H "Content-Type: application/json" \
  -d '{
    "recipient_first_name": "Alex",
    "recipient_last_name": "Garcia",
    "recipient_email": "alex@policyholder.com",
    "send_email": true,
    "ttl_minutes": 1440
  }'
{
  "id": "i-1",
  "session": "0c8f...",
  "role": "field",
  "expires_at": "2026-05-24T10:00:00Z",
  "recipient_first_name": "Alex",
  "recipient_last_name": "Garcia",
  "recipient_email": "alex@policyholder.com",
  "recipient_phone": "",
  "join_url": "https://app.nexbasira.com/join/0c8f.../?t=tok_PLAINTEXT_ONCE",
  "otp_code": "487192",
  "otp_required": true,
  "otp_expires_at": "2026-05-23T10:10:00Z",
  "created_at": "2026-05-23T10:00:00Z"
}

Il join_url e otp_code sono mostrati esattamente una volta nella risposta. I token sono vincolati a IP/UA, monouso e a tempo limitato.

Join a due fattori (OTP)

Quando fornisci almeno uno tra recipient_email o recipient_phone, la piattaforma genera automaticamente un OTP numerico a 6 cifre e lo invia sui canali corrispondenti in un messaggio separato dalla URL di join — difesa in profondità così un'email o un SMS inoltrato non fa trapelare entrambi i fattori in una volta. Il codice in chiaro è restituito anche nella risposta ( otp_code) così puoi ricondividerlo manualmente se il recapito fallisce.

Lato campo, la SPA mostra il prompt dell'OTP alla prima redenzione. Invia il codice tramite l'header X-Join-OTP in un retry di GET /v1/sessions/{id}/join/{token} — l'header (non la URL) tiene il codice fuori dalla cronologia del browser e dai log di accesso.

Regole OTP:

  • Numerico a 6 cifre, hashato con SHA-256 + pepper a riposo.
  • TTL di 10 minuti dall'emissione.
  • 5 tentativi errati bloccano l'invito (HTTP 423) — l'operatore deve riemetterlo.
  • Verificato una sola volta alla prima redenzione; la ri-redenzione dalla stessa coppia IP / UA salta il gate (il token è già vincolato).
  • Il passaggio della URL faccia a faccia (nessun recipient_email + nessun recipient_phone) salta la generazione dell'OTP — la URL da sola è il fattore di autenticazione. Usalo solo per i passaggi di persona.

Codici di risposta su GET /v1/sessions/{id}/join/{token}:

StatoBodySignificato
200{field_session_token, livekit, ...}OTP superato (o non richiesto); la sessione sul campo è live.
401{detail:"otp_required", channels:[...], channel_hint_email, channel_hint_phone}La SPA dovrebbe mostrare il form di inserimento dell'OTP.
401{detail:"otp_invalid", attempts_remaining}Codice errato; mostra i tentativi rimanenti.
401{detail:"otp_expired"}Finestra di 10 min trascorsa; l'operatore deve riemettere.
423{detail:"otp_locked"}5 tentativi errati; l'invito è morto fino alla riemissione.

Errori comuni

StatoCodiceQuando
402billing.subscription_past_dueL'abbonamento Stripe dell'org è scaduto.
402billing.free_plan_minutes_exhaustedIl piano Free / Pilot ha esaurito le sue 5 ispezioni.
403permission_deniedLa credenziale non ha sessions:write scope.
409session.already_endedTentativo di terminare una sessione già chiusa (raro — `end` è normalmente idempotente).
429rate_limitedThrottle di 60-rpm per-credenziale o 600-rpm per-org raggiunto. Vedi l'header X-RateLimit-Reset header.

Vedi Errori + rate limit per la forma completa dell'envelope di errore e le indicazioni sui retry.