Sessions-API
En Session är en inspektion. Skapa en, utfärda en inbjudan till fältanvändare, fånga bevis, avsluta den. Allt annat hänger på denna resurs.
Session-objektet
{
"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"
} | Status | Betydelse |
|---|---|
created | Sessionsraden finns; ingen har anslutit ännu. |
open | Fältanvändaren har anslutit; sessionen är live. |
recording | Inspelning pågår (valfritt, utlöst av operatören). |
closed | Sessionen avslutad. Kedjehuvudet förankrat hos TSA; rapporter tillgängliga. |
expired | Schemalagd session som ingen anslöt till inom TTL:en. |
Skapa en session
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"
}' Returnerar det nyss skapade Session-objektet (HTTP 201).
Body-fält
| Fält | Typ | Obligatoriskt | Anteckningar |
|---|---|---|---|
notes | string | nej | Synligt för operatören. Visas i inbjudningsmejl. |
scheduled_for | ISO 8601 | nej | Ett framtida datum utlöser påminnelsemejl 24h + 1h innan. Utelämna för "starta nu". |
locale | string | nej | En av de 14 språk som stöds. Styr språket i SPA:n + PDF-rapporten. Faller tillbaka på organisationens inställning. |
campaign | UUID | nej | Valfri FK till en Campaign för batchad rapportering. |
Lista sessioner
GET /api/v1/public/sessions — scope sessions:read
curl https://app.nexbasira.com/api/v1/public/sessions?limit=25 \
-H "Authorization: Bearer nb_sec_..." Markörpaginerat. Skicka cursor från föregående svars next_cursor för att bläddra.
{
"data": [{ /* Session, Session, ... */ }],
"has_more": true,
"next_cursor": "eyJjcmVhdGVkX2F0IjoiMjAy..."
} Hämta en session
GET /api/v1/public/sessions/{session_id} — scope sessions:read
Avsluta en session
POST /api/v1/public/sessions/{session_id}/end — scope sessions:write
Stänger sessionen, utlöser förankringen av kedjehuvudet hos alla konfigurerade TSA:er och startar efterbearbetningen av inspelningen om en inspelning kördes. Idempotent — anrop på en redan stängd session returnerar det stängda Session-objektet utan att förankra på nytt.
Skapa en fältanvändarinbjudan
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"
} Fälten join_url och otp_code visas exakt en gång i svaret. Tokens är IP/UA-bundna, engångsbruk och tidsbegränsade.
Tvåfaktorsanslutning (OTP)
När du anger minst en av recipient_email eller recipient_phone skapar plattformen automatiskt en 6-siffrig numerisk OTP och skickar den på matchande kanal(er) i ett separat meddelande från anslutnings-URL:en — försvar på djupet, så att ett vidarebefordrat mejl eller SMS inte läcker båda faktorerna samtidigt. Den klartextkoden returneras också i svaret ( otp_code) så att du kan dela den manuellt igen om leveransen misslyckas.
På fältsidan visar SPA:n OTP-prompten vid första inlösen. Skicka koden via X-Join-OTP -headern i ett nytt försök av GET /v1/sessions/{id}/join/{token} — headern (inte URL:en) håller koden utanför webbläsarhistorik och åtkomstloggar.
OTP-regler:
- 6-siffrig numerisk, hashad med SHA-256 + pepper i vila.
- 10-minuters TTL från utfärdande.
- 5 felaktiga försök låser inbjudan (HTTP 423) — operatören måste utfärda den på nytt.
- Verifieras en gång vid första inlösen; ny inlösen från samma IP-/UA-par hoppar över spärren (token är redan bunden).
- Överlämning av URL ansikte mot ansikte (ingen
recipient_email+ ingenrecipient_phone) hoppar över OTP-skapandet — URL:en ensam är autentiseringsfaktorn. Använd detta enbart för överlämningar på plats.
Svarskoder på GET /v1/sessions/{id}/join/{token}:
| Status | Body | Betydelse |
|---|---|---|
| 200 | {field_session_token, livekit, ...} | OTP godkänd (eller krävs inte); fältsessionen är live. |
| 401 | {detail:"otp_required", channels:[...], channel_hint_email, channel_hint_phone} | SPA:n bör visa OTP-inmatningsformuläret. |
| 401 | {detail:"otp_invalid", attempts_remaining} | Fel kod; visa återstående försök. |
| 401 | {detail:"otp_expired"} | 10-minutersfönstret har löpt ut; operatören måste utfärda på nytt. |
| 423 | {detail:"otp_locked"} | 5 felaktiga försök; inbjudan är död tills den utfärdas på nytt. |
Vanliga fel
| Status | Kod | När |
|---|---|---|
| 402 | billing.subscription_past_due | Organisationens Stripe-prenumeration är förfallen. |
| 402 | billing.free_plan_minutes_exhausted | Free-/Pilot-nivån har förbrukat sina 5 inspektioner. |
| 403 | permission_denied | Behörigheten saknar sessions:write scope. |
| 409 | session.already_ended | Försök att avsluta en session som redan är stängd (ovanligt — `end` är normalt idempotent). |
| 429 | rate_limited | Begränsningen 60 rpm per behörighet eller 600 rpm per organisation nåddes. Se X-RateLimit-Reset -headern. |
Se Fel + hastighetsgränser för hela felkuvertets form och riktlinjer för återförsök.