Errors

Errors return a non-2xx status with a JSON body shaped like:

{
  "detail": "session not found"
}

Status codes

CodeMeaning
400Bad request (e.g. unknown r_level filter, malformed JSON)
401Auth missing or invalid
403Auth valid but you don't own this resource
404Resource doesn't exist
409Conflict (e.g. creating a client slug that already exists — admin-only)
422Validation error from Pydantic (body shape doesn't match)
500Internal — please tell us

Idempotency

POST /v1/sessions with the same (your client, external_id) returns the existing session — safe to retry.

POST /v1/sessions/{id}/messages is not idempotent on retry. If you retry a 5xx, you may end up with a duplicate turn. Use sequence numbers in your own system if duplicates would be a problem.

Scoring failures

If our scoring model is briefly unavailable, message append still succeeds but returns:

{
  ...
  "scores": {},
  "prs": 0.0,
  "r_level": "R0",
  "score_error": "no loadable completed checkpoint for prod model 'tfidf-lgbm-v2'"
}

In this case the turn is persisted but un-scored — we'll backfill later. Treat score_error as a signal to retry or escalate if it persists.