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?" }
}'
const response = await fetch('https://api.bota.dev/v1/ask/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
end_user_id: 'eu_abc123',
scope: { type: 'library' },
initial_message: { content: 'What did I commit to this week?' },
}),
});
const { session_id, message, sources } = await response.json();
import requests
response = requests.post(
'https://api.bota.dev/v1/ask/sessions',
headers={
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
},
json={
'end_user_id': 'eu_abc123',
'scope': {'type': 'library'},
'initial_message': {'content': 'What did I commit to this week?'},
},
)
result = response.json()
{
"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
}
]
}
{
"id": "as_abc123",
"scope": { "type": "library", "recording_ids": [], "recording_title": null },
"title": "New chat",
"message_count": 0,
"last_message_at": "2026-05-20T10:20:00Z",
"last_model": null,
"last_provider": null,
"created_at": "2026-05-20T10:20:00Z",
"updated_at": "2026-05-20T10:20:00Z"
}
AI Ask
Create Session
Create an AI Ask session, optionally answering a first message
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?" }
}'
const response = await fetch('https://api.bota.dev/v1/ask/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
end_user_id: 'eu_abc123',
scope: { type: 'library' },
initial_message: { content: 'What did I commit to this week?' },
}),
});
const { session_id, message, sources } = await response.json();
import requests
response = requests.post(
'https://api.bota.dev/v1/ask/sessions',
headers={
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
},
json={
'end_user_id': 'eu_abc123',
'scope': {'type': 'library'},
'initial_message': {'content': 'What did I commit to this week?'},
},
)
result = response.json()
{
"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
}
]
}
{
"id": "as_abc123",
"scope": { "type": "library", "recording_ids": [], "recording_title": null },
"title": "New chat",
"message_count": 0,
"last_message_at": "2026-05-20T10:20:00Z",
"last_model": null,
"last_provider": null,
"created_at": "2026-05-20T10:20:00Z",
"updated_at": "2026-05-20T10:20:00Z"
}
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). Passrecording_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.
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. Provideend_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?" }
}'
const response = await fetch('https://api.bota.dev/v1/ask/sessions', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
end_user_id: 'eu_abc123',
scope: { type: 'library' },
initial_message: { content: 'What did I commit to this week?' },
}),
});
const { session_id, message, sources } = await response.json();
import requests
response = requests.post(
'https://api.bota.dev/v1/ask/sessions',
headers={
'Authorization': 'Bearer sk_live_...',
'Content-Type': 'application/json',
},
json={
'end_user_id': 'eu_abc123',
'scope': {'type': 'library'},
'initial_message': {'content': 'What did I commit to this week?'},
},
)
result = response.json()
Request Body
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.)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, orclaude); defaults to the project/system default.context_refs(array, optional) — @mentioned recordings,[{ "type": "recording", "id": "rec_..." }](max 20). Reserved for upcoming features; persisted today.
string
Session title (1–200 characters). Defaults to the
initial_message text, or "New chat".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_message→200, the ask result ({ session_id, message, sources }) — see Send Message for the full message shape. - Without
initial_message→201, 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
}
]
}
{
"id": "as_abc123",
"scope": { "type": "library", "recording_ids": [], "recording_title": null },
"title": "New chat",
"message_count": 0,
"last_message_at": "2026-05-20T10:20:00Z",
"last_model": null,
"last_provider": null,
"created_at": "2026-05-20T10:20:00Z",
"updated_at": "2026-05-20T10:20:00Z"
}
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.Was this page helpful?

