EN DIRECT · AUDIT CHAÎNÉ · ÉDR UE
SYSTÈME · 99,99% DISPONIBILITÉ
v 1.0 ↗ FAIT EN UE

API Sessions

Une Session correspond à une inspection. Créez-en une, émettez une invitation d'utilisateur terrain, capturez des preuves, terminez-la. Tout le reste se rattache à cette ressource.

L'objet 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"
}
StatutSignification
createdLa ligne de session existe ; personne n'a encore rejoint.
openL'utilisateur terrain a rejoint ; la session est en direct.
recordingEnregistrement en cours (optionnel, déclenché par l'opérateur).
closedSession terminée. Tête de chaîne ancrée à la TSA ; rapports disponibles.
expiredSession planifiée que personne n'a rejointe dans le délai (TTL).

Créer une session

POST /api/v1/public/sessions — Portée 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"
  }'

Renvoie l'objet Session fraîchement créé (HTTP 201).

Champs du corps

ChampTypeRequisNotes
notesstringnonVisible par l'opérateur. Affiché dans les e-mails d'invitation.
scheduled_forISO 8601nonUne date future déclenche des e-mails de rappel 24 h + 1 h avant. Omettez pour « démarrer maintenant ».
localestringnonL'une des 14 locales prises en charge. Détermine la langue de la SPA + du rapport PDF. Par défaut, la préférence de l'organisation.
campaignUUIDnonFK optionnelle vers une Campaign pour un reporting groupé.

Lister les sessions

GET /api/v1/public/sessions — Portée sessions:read

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

Paginé par curseur. Passez le paramètre cursor en reprenant le next_cursor de la réponse précédente pour paginer.

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

Récupérer une session

GET /api/v1/public/sessions/{session_id} — Portée sessions:read

Terminer une session

POST /api/v1/public/sessions/{session_id}/end — Portée sessions:write

Ferme la session, déclenche l'ancrage de la tête de chaîne auprès de toutes les TSA configurées, et lance le post-traitement de l'enregistrement si un enregistrement était en cours. Idempotent — un appel sur une session déjà fermée renvoie l'objet Session fermé sans réancrage.

Émettre une invitation d'utilisateur terrain

POST /api/v1/public/sessions/{session_id}/participants — Portée 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"
}

Le join_url et le otp_code sont affichés une seule fois dans la réponse. Les tokens sont liés à l'IP/UA, à usage unique et limités dans le temps.

Connexion à deux facteurs (OTP)

Lorsque vous fournissez au moins l'un de recipient_email ou recipient_phone, la plateforme émet automatiquement un OTP numérique à 6 chiffres et l'envoie sur le ou les canaux correspondants dans un message distinct de l'URL de connexion — défense en profondeur pour qu'un e-mail ou un SMS transféré ne divulgue pas les deux facteurs à la fois. Le code en clair est aussi renvoyé dans la réponse ( otp_code) afin que vous puissiez le repartager manuellement en cas d'échec de distribution.

Côté terrain, la SPA affiche l'invite OTP à la première utilisation. Soumettez le code via l'en-tête X-Join-OTP lors d'une nouvelle tentative de GET /v1/sessions/{id}/join/{token} — l'en-tête (et non l'URL) garde le code hors de l'historique du navigateur et des logs d'accès.

Règles OTP :

  • Numérique à 6 chiffres, haché avec SHA-256 + pepper au repos.
  • TTL de 10 minutes à compter de l'émission.
  • 5 tentatives erronées verrouillent l'invitation (HTTP 423) — l'opérateur doit la réémettre.
  • Vérifié une fois à la première utilisation ; une réutilisation depuis la même paire IP / UA saute le contrôle (le token est déjà épinglé).
  • Remise de l'URL en face à face (pas de recipient_email + pas de recipient_phone) saute l'émission d'OTP — l'URL seule est le facteur d'authentification. À réserver aux remises en personne.

Codes de réponse sur GET /v1/sessions/{id}/join/{token}:

StatutCorpsSignification
200{field_session_token, livekit, ...}OTP validé (ou non requis) ; la session terrain est en direct.
401{detail:"otp_required", channels:[...], channel_hint_email, channel_hint_phone}La SPA doit afficher le formulaire de saisie de l'OTP.
401{detail:"otp_invalid", attempts_remaining}Code erroné ; affichez les tentatives restantes.
401{detail:"otp_expired"}Fenêtre de 10 min écoulée ; l'opérateur doit réémettre.
423{detail:"otp_locked"}5 tentatives erronées ; l'invitation est morte jusqu'à réémission.

Erreurs courantes

StatutCodeQuand
402billing.subscription_past_dueL'abonnement Stripe de l'organisation est en retard de paiement.
402billing.free_plan_minutes_exhaustedLa formule gratuite / pilote a utilisé ses 5 inspections.
403permission_deniedL'identifiant ne dispose pas du scope sessions:write Portée.
409session.already_endedTentative de terminer une session déjà fermée (rare — `end` est normalement idempotent).
429rate_limitedLimite de débit de 60 rpm par identifiant ou 600 rpm par organisation atteinte. Voir l'en-tête X-RateLimit-Reset .

Voir Erreurs + limites de débit pour la forme complète de l'enveloppe d'erreur et les conseils de nouvelle tentative.