LIVE · AUDIT-KETTE · EU-ANSÄSSIG
SYSTEM · 99,99 % VERFÜGBARKEIT
v 1.0 ↗ HERGESTELLT IN DER EU

Sessions-API

Eine Session ist eine Inspektion. Erstellen Sie eine, prägen Sie eine Feldbenutzer-Einladung, erfassen Sie Beweise, beenden Sie sie. Alles andere hängt an dieser Ressource.

Das Session-Objekt

{
  "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"
}
StatusBedeutung
createdSession-Zeile existiert; noch niemand ist beigetreten.
openFeldbenutzer ist beigetreten; die Sitzung ist live.
recordingAufzeichnung läuft (optional, operator-ausgelöst).
closedSitzung beendet. Kettenkopf an der TSA verankert; Berichte verfügbar.
expiredGeplante Sitzung, der niemand innerhalb der TTL beigetreten ist.

Eine Session erstellen

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"
  }'

Gibt das frisch erstellte Session-Objekt zurück (HTTP 201).

Body-Felder

FeldTypErforderlichAnmerkungen
notesstringneinFür den Operator sichtbar. In Einladungs-E-Mails angezeigt.
scheduled_forISO 8601neinEin zukünftiges Datum löst Erinnerungs-E-Mails 24 h + 1 h vorher aus. Für „jetzt starten“ weglassen.
localestringneinEine der 14 unterstützten Locales. Steuert die Sprache von SPA + PDF-Bericht. Standardmäßig die Präferenz der Org.
campaignUUIDneinOptionaler FK auf eine Campaign für gebündeltes Reporting.

Sessions auflisten

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

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

Cursor-paginiert. Übergeben Sie cursor aus dem next_cursor der vorherigen Response, um zu paginieren.

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

Eine Session abrufen

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

Eine Session beenden

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

Schließt die Sitzung, löst den Kettenkopf-Anker an allen konfigurierten TSAs aus und stößt die Aufzeichnungs-Nachbearbeitung an, falls eine Aufzeichnung lief. Idempotent — ein Aufruf auf einer bereits geschlossenen Sitzung gibt das geschlossene Session-Objekt zurück, ohne neu zu verankern.

Eine Feldbenutzer-Einladung prägen

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"
}

Die join_url und otp_code werden in der Response genau einmal angezeigt. Tokens sind IP/UA-gebunden, einmalig nutzbar und zeitlich begrenzt.

Zwei-Faktor-Beitritt (OTP)

Wenn Sie mindestens eines von recipient_email oder recipient_phoneangeben, prägt die Plattform automatisch ein 6-stelliges numerisches OTP und sendet es auf dem/den passenden Kanal/Kanälen in einer separaten Nachricht getrennt von der Beitritts-URL — Defense-in-Depth, damit eine weitergeleitete E-Mail oder SMS nicht beide Faktoren auf einmal preisgibt. Der Klartext-Code wird außerdem in der Response zurückgegeben ( otp_code), sodass Sie ihn manuell erneut teilen können, falls die Zustellung fehlschlägt.

Feldseitig blendet die SPA bei der ersten Einlösung die OTP-Abfrage ein. Übermitteln Sie den Code über den X-Join-OTP -Header bei einem Retry von GET /v1/sessions/{id}/join/{token} — der Header (nicht die URL) hält den Code aus dem Browser-Verlauf und den Zugriffslogs heraus.

OTP-Regeln:

  • 6-stellig numerisch, im Ruhezustand mit SHA-256 + Pepper gehasht.
  • 10-Minuten-TTL ab Ausstellung.
  • 5 falsche Versuche sperren die Einladung (HTTP 423) — der Operator muss sie neu ausstellen.
  • Einmal bei der ersten Einlösung verifiziert; eine erneute Einlösung vom selben IP- / UA-Paar überspringt das Gate (das Token ist bereits gebunden).
  • Ein Face-to-Face-URL-Handoff (kein recipient_email + kein recipient_phone) überspringt das OTP-Prägen — die URL allein ist der Auth-Faktor. Nutzen Sie dies nur für persönliche Übergaben.

Response-Codes bei GET /v1/sessions/{id}/join/{token}:

StatusBodyBedeutung
200{field_session_token, livekit, ...}OTP bestanden (oder nicht erforderlich); die Feldsitzung ist live.
401{detail:"otp_required", channels:[...], channel_hint_email, channel_hint_phone}Die SPA sollte das OTP-Eingabeformular rendern.
401{detail:"otp_invalid", attempts_remaining}Falscher Code; verbleibende Versuche anzeigen.
401{detail:"otp_expired"}10-Minuten-Fenster verstrichen; der Operator muss neu ausstellen.
423{detail:"otp_locked"}5 falsche Versuche; die Einladung ist tot bis zur Neuausstellung.

Häufige Fehler

StatusCodeWann
402billing.subscription_past_dueDas Stripe-Abonnement der Org ist überfällig.
402billing.free_plan_minutes_exhaustedDie Free- / Pilot-Stufe hat ihre 5 Inspektionen aufgebraucht.
403permission_deniedDem Credential fehlt sessions:write Scope.
409session.already_endedVersuch, eine bereits geschlossene Sitzung zu beenden (selten — `end` ist normalerweise idempotent).
429rate_limited60-rpm-Per-Credential- oder 600-rpm-Per-Org-Throttle erreicht. Siehe X-RateLimit-Reset -Header.

Siehe Fehler + Rate-Limits für die vollständige Fehler-Envelope-Form und Retry-Hinweise.