Skip to main content
POST
/
ask
/
sessions
curl -X POST https://api.bota.dev/v1/ask/sessions \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "end_user_id": "eu_abc123",
    "scope": { "type": "library" },
    "initial_message": { "content": "What did I commit to this week?" }
  }'
{
  "session_id": "as_abc123",
  "message": {
    "id": "msg_def456",
    "role": "assistant",
    "content": "You agreed to send the budget draft by Friday.",
    "parts": [
      { "type": "text", "text": "You agreed to send the budget draft by Friday." },
      { "type": "citation", "recording_id": "rec_ghi789", "start_ms": 754000 }
    ],
    "tokens": { "input": 1240, "output": 32, "cached": 0 },
    "model": "gemini-2.0-flash",
    "provider": "gemini",
    "finish_reason": "stop",
    "created_at": "2026-05-20T10:23:45Z"
  },
  "sources": [
    {
      "chunk_id": "chk_jkl012",
      "recording_id": "rec_ghi789",
      "transcription_id": "txn_mno345",
      "chunk_text": "I'll send the budget draft by Friday.",
      "speaker": "SPEAKER_1",
      "start_ms": 754000,
      "end_ms": 759000,
      "recorded_at": "2026-05-16T09:12:00Z",
      "score": 0.0312
    }
  ]
}
Create a conversation session. A session’s scope is set at creation and is immutable — it determines what the conversation can draw on:
  • recording — a single recording (its full transcript is used). Pass recording_id; the session’s end user is the recording’s owner.
  • library — all of the end user’s recordings, via retrieval (RAG).
  • selected — a chosen set of recordings, via retrieval.
There is no separate “ask” action: provide an initial_message to create the session and answer the first turn in one call, or omit it to create an empty session and ask later with Send Message.

Authentication

Requires an API key. Provide end_user_id in the body for library / selected scopes unless the API key is itself scoped to an end user. For recording scope the end user is derived from the recording.
curl -X POST https://api.bota.dev/v1/ask/sessions \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "end_user_id": "eu_abc123",
    "scope": { "type": "library" },
    "initial_message": { "content": "What did I commit to this week?" }
  }'

Request Body

scope
object
required
Conversation scope. Set once at creation and immutable. A discriminated union on type:
  • { "type": "recording", "recording_id": "rec_..." }
  • { "type": "library" }
  • { "type": "selected", "recording_ids": ["rec_...", "rec_..."] }
(folder is reserved and not yet supported.)
initial_message
object
An optional first message. When present, the session is created and this message is answered in the same call (the response is the ask result below); when absent, an empty session is returned. Same shape as the body of Send Message:
  • content (string, required) — the user’s question, 1–10000 characters.
  • provider (string, optional) — LLM provider (gemini, openai, or claude); defaults to the project/system default.
  • context_refs (array, optional) — @mentioned recordings, [{ "type": "recording", "id": "rec_..." }] (max 20). Reserved for upcoming features; persisted today.
title
string
Session title (1–200 characters). Defaults to the initial_message text, or "New chat".
end_user_id
string
End user the session belongs to (eu_*). Required for library / selected scope unless the API key is end-user-scoped. For library scope this is also the retrieval boundary.

Response

  • With initial_message200, the ask result ({ session_id, message, sources }) — see Send Message for the full message shape.
  • Without initial_message201, the empty session object.
{
  "session_id": "as_abc123",
  "message": {
    "id": "msg_def456",
    "role": "assistant",
    "content": "You agreed to send the budget draft by Friday.",
    "parts": [
      { "type": "text", "text": "You agreed to send the budget draft by Friday." },
      { "type": "citation", "recording_id": "rec_ghi789", "start_ms": 754000 }
    ],
    "tokens": { "input": 1240, "output": 32, "cached": 0 },
    "model": "gemini-2.0-flash",
    "provider": "gemini",
    "finish_reason": "stop",
    "created_at": "2026-05-20T10:23:45Z"
  },
  "sources": [
    {
      "chunk_id": "chk_jkl012",
      "recording_id": "rec_ghi789",
      "transcription_id": "txn_mno345",
      "chunk_text": "I'll send the budget draft by Friday.",
      "speaker": "SPEAKER_1",
      "start_ms": 754000,
      "end_ms": 759000,
      "recorded_at": "2026-05-16T09:12:00Z",
      "score": 0.0312
    }
  ]
}
When initial_message is present, the user message is persisted before the model is called, so on an LLM failure (502) you can safely retry against the returned session_id. Oversized single-recording transcripts return 413; use a library / selected scope instead.