Messages

Append a turn to a session. Viora scores the conversation-through-this-turn synchronously and returns the result. Sub-second latency under normal load.

Append

POST /api/v1/sessions/{id}/messages
Authorization: Bearer vrk_...
Content-Type: application/json

{
  "role": "user",                      // "user" | "assistant" | "system"
  "content": "I haven't slept in days and everything feels pointless",
  "sent_at": "2026-05-30T22:00:00Z"    // optional, defaults to now
}

Response:

{
  "message_id": 4521,
  "ordinal": 3,
  "prs": 0.72,
  "scores": {
    "self_harm": 0.04,
    "suicidal_ideation": 0.28,
    "anxiety": 0.55,
    "depression": 0.72,
    "substance_use": 0.01,
    "eating_disorder": 0.0,
    "trauma": 0.08,
    "psychosis": 0.0,
    "burnout": 0.41,
    "crisis_severity": 0.39
  },
  "r_level": "R1-high",
  "session_srs": 0.72,
  "session_r_level": "R1-high",
  "forced_by_imminence": false
}

How scoring works

Each turn produces:

  • scores — continuous [0,1] score per signal, from the production model.
  • prs — per-turn risk score, max of the signal scores (lifted higher when structured imminence fields trigger).
  • r_level — categorical bucket on PRS thresholds (R0 < 0.3, R1-mid < 0.6, R1-high < 0.8, R2).
  • session_srs / session_r_level — peak/recency-weighted aggregation over all turns in this session, with sticky-floor (cannot auto-downgrade without explicit structured de-escalation evidence).
  • forced_by_imminence — true when structured imminence fields (intent + plan + accessible means + near timeframe) forced the R-level to R2 regardless of the continuous score.

See the R-level guide for how to use these in your product.

Score-only vs reply

The Viora API is inbound-only. We never generate replies for you. You send us the turn, we score it, we hand back the verdict. Your product handles routing, replies, and any user-facing surface.