Intake State API (LiveKit-first)
This API is a lightweight state/persistence surface for intake sessions when conversational orchestration runs outside domain-chatbot (for example, in LiveKit).
Base prefix: /query/intake/session
Authentication and domain
- Uses existing
get_current_user_or_api_key_via_request. - Domain resolution uses the same
resolve_intake_domain_for_request(...)behavior as existing intake endpoints. - A valid user JWT or domain API key is required.
Endpoints
POST /query/intake/session/init
Creates or loads a session for a known form_id.
Request:
{
"form_id": "assessment_intake",
"language": "en",
"intake_domain": "llhuk",
"session_start_timestamp": "20260602_103000",
"form_state": {}
}
Response (success):
{
"ok": true,
"session": {
"form_id": "assessment_intake",
"session_start_timestamp": "20260602_103000",
"form_state": {},
"missing_required": ["full_name"],
"progress": {
"total_required": 8,
"missing_required": 8,
"completed_required": 0
},
"form_submitted": false,
"language": "en"
},
"form_schema": { "...": "schema" }
}
PATCH /query/intake/session/{session_id}/fields
Applies one or more field updates to session state.
Request:
{
"form_id": "assessment_intake",
"language": "en",
"intake_domain": "llhuk",
"updates": [
{ "field_id": "full_name", "value": "John Smith" },
{ "field_id": "email", "value": "john@example.com" }
]
}
Repeatable group updates:
- Add item:
{ "op": "add_repeatable_item", "group_id": "work_experiences" } - Update item subfield:
{ "group_id": "work_experiences", "item_index": 0, "field_id": "company", "value": "Aventora" }
Response includes recorded, errors, and normalized session snapshot.
POST /query/intake/session/{session_id}/validate
Runs required-field validation against current state (or supplied form_state).
Request:
{
"form_id": "assessment_intake",
"language": "en",
"intake_domain": "llhuk"
}
Response:
{
"ok": false,
"missing_required": ["phone"],
"session": { "...": "snapshot" }
}
POST /query/intake/session/{session_id}/submit
Runs final intake submit path using existing semantic validation + integration submit logic.
Request:
{
"form_id": "assessment_intake",
"language": "en",
"intake_domain": "llhuk",
"form_state": { "...": "optional override" },
"intake_review_token": null
}
Response:
{
"ok": true,
"form_submitted": true,
"message": "Your assessment has been submitted successfully.",
"errors": [],
"missing_required": [],
"session": { "...": "snapshot" }
}
GET /query/intake/session/{session_id}?form_id=...&language=en
Loads persisted session snapshot and schema.
Response:
{
"ok": true,
"session": { "...": "snapshot" },
"form_schema": { "...": "schema" }
}
POST /query/intake/session/{session_id}/reset
Deletes persisted runtime intake answers for the session so a voice interview can start clean (same session_id, empty form_state on next bootstrap).
Request:
{
"form_id": "criminal_law_intake",
"intake_domain": "llhuk"
}
POST /query/intake/session/{session_id}/voice-turn
Runs one deterministic voice interview turn (same warm intro, acknowledgements, and field prompts as POST /query/intake/continue with lock_turn_language: true). Use this from LiveKit/BackendLK instead of hand-rolling field labels.
Request:
{
"form_id": "real_estate_intake",
"language": "en",
"intake_domain": "llhuk",
"bootstrap_only": true,
"user_message": null,
"voice_confirm_submit": false,
"is_anonymous": false,
"user_profile": { "id": 1, "first_name": "Jane", "last_name": "Doe", "email": "jane@example.com" }
}
Response (success):
{
"ok": true,
"answer": "Hi — I'm your intake assistant. ... Whenever you're ready, What is your first and last name?",
"form_submitted": false,
"review_pending": false,
"pending_field_id": "first_name",
"session": { "...": "snapshot" },
"form_schema": { "...": "schema" }
}
Notes
- Existing
/query/intakeand/query/intake/continueremain available for backward compatibility. init,patch,validate, andsubmitare state-only; usevoice-turnfor conversational copy.