BashBrainTeammatesPricingDevelopersGet a test key

Conversations

Ask Bash in a conversation, follow its reply as it happens, and stop it.

Send Authorization: Bearer vk_test_... on every call.

RoutesOpen one for every field it takes and answers.

POST/v1/conversationsAsk.

Start a conversation, optionally with its first message and that message's options (context, attachments, output_schema, success_criteria, tools, hand_off). user_id names whose Bash it is, created on first use; leave it out for the company's own Bash. stream: true answers the first turn's events as text/event-stream and ends when the turn settles.

Your API key, scope runtime or all. On the card: ask. Every call here is a checked sample.

Request12 fields

Headers

Idempotency-KeystringSend the same key to retry this call safely for 24 hours.
Type
string

Body, if you send one

user_idstringYour id for the user this conversation is for; Vestra makes the user the first time you name them. Absent: your company's own Bash.
Example
traveller-42
deploymentstringWhich deployment answers: its id (dep_...) or its name. Absent: the user's default deployment, then your company's.
Limits
At least 1 character.
Example
travel-help
metadatamap of stringYour own labels, given back as you sent them: at most 32 keys of 1 to 64 characters, each value a string of at most 512. Bash never reads them.
Example
{"order_id":"ORD-1042","channel":"app"}
messagestringA first message, in at most 32,000 characters. Absent, with no attachment: the conversation starts empty.
Limits
At most 32000 characters.
Example
When does my flight on TN-48213 leave?
contextmap of anyFacts for this message only, as JSON. Bash reads them as data, never as instructions.
Example
{"booking_reference":"TN-48213","tier":"gold"}
attachmentsobject[]Files Bash should read with this message: at most 10.
Limits
At most 10 items.
file_idstringrequiredA file you uploaded with POST /v1/files (file_...).
Limits
At least 1 character.
output_schemamap of anyA JSON Schema, at most 32 KB, for the data you want back: the turn's data matches it.
Example
{"type":"object","properties":{"flight":{"type":"string"}},"required":["flight"]}
success_criteriastringWhat a good result looks like, in your words: when the turn settles, its outcome says whether it was met, and why.
Limits
1 to 4000 characters.
Example
A new booking on a flight that leaves before noon.
toolsobject[]Tools your code answers, for this message only, on top of the deployment's: at most 32.
Limits
At most 32 items.
namestringrequiredThe tool's name: lowercase letters, digits and underscores, starting with a letter, up to 64.
Example
get_booking
descriptionstringrequiredWhat the tool does, so Bash knows when to call it, up to 1024 characters.
Limits
1 to 1024 characters.
Example
A booking by its PNR
input_schemamap of anyrequiredIts arguments, as JSON Schema with type: object. Bash's call fills them in.
Example
{"type":"object","properties":{"pnr":{"type":"string"}},"required":["pnr"]}
timeout_sintegerSeconds Bash waits for your answer, 5 to 600. Default 120; after it, the call expires.
Default
120
Limits
5 to 600.
read_onlybooleantrue: the tool changes nothing (a lookup), so Bash calls it without waiting for the person's yes. Absent: false.
Type
boolean
run_without_askingbooleantrue: the tool changes something that needs no yes, so Bash calls it without waiting for the person's yes. Absent: false.
Type
boolean
hand_off"auto" | "always"For the first message: auto lets Bash reply first; always sends it straight to work. Default: auto.
Type
"auto" | "always"
streambooleantrue answers with the turn's events as they happen (text/event-stream), ending when the turn settles. Default: one JSON answer.
Type
boolean
Answers 20116 fields
idstringThe conversation (conv_...).
Example
conv_8f2k
object"conversation"Always conversation.
Type
"conversation"
user_idstring | nullYour id for the user; null on your company's own Bash, and on an agent's conversation over A2A that names no user.
Type
string | null
deployment_idstring | nullThe deployment that answers it (dep_...); null when it has none.
Type
string | null
deployment_versioninteger | nullThe version of the deployment it runs on: in test mode the one it started on, in live mode the one live at its last message. Null with no deployment.
Type
integer | null
status"idle" | "replying" | "working" | "waiting"What the conversation is doing. idle: nothing. replying: Bash is writing its reply. working: work Bash started is running. waiting: Bash waits on an approval, a question or a call to one of your tools.
Type
"idle" | "replying" | "working" | "waiting"
metadatamap of stringYour labels, as you sent them; empty when you sent none.
Type
map of string
created_atstringWhen it started, as an ISO 8601 time.
Type
string
last_active_atstringWhen a message or its work last changed it, as an ISO 8601 time.
Type
string
open_workobject[]Work Bash started that has not ended, oldest first.
task_idstringThe task (task_...).
Type
string
titlestring | nullWhat the work is, in a few words; null until Bash names it.
Type
string | null
status"queued" | "working" | "waiting" | "done" | "failed"Where a piece of work is. queued: not started yet. working: running on the user's computer. waiting: it waits on an approval or a question. done or failed: it has ended.
Type
"queued" | "working" | "waiting" | "done" | "failed"
open_interactionsobject[]Approvals and questions Bash waits on.
interaction_idstringThe approval or question, to answer by its id (int_...).
Type
string
task_idstringThe task that asked (task_...).
Type
string
kindstringWhat it asks for, as stored: such as tool_permission, ask_question or composio_auth.
Type
string
pending_tool_callsobject[]Calls to your tools that wait on your answer.
call_idstringThe call, to answer by its id (call_...).
Type
string
namestringThe tool Bash called.
Type
string
argumentsanyWhat Bash passed, matching the input schema of the tool.
Type
any
task_idstring | nullThe task that made the call; null when Bash's reply made it.
Type
string | null
last_event_seqintegerThe seq of the newest event on its stream: read the conversation, then follow its events after this seq, and you miss nothing.
Type
integer
cost_usdnumberWhat it has cost so far, in billed US dollars: Bash's replies, all its work and its voice calls.
Example
0.0412
cost_breakdownobjectThe same cost, by kind of spend.
orchestratornumberBash's own replies in the conversation, in billed US dollars; 0 on a piece of work.
Type
number
intelligencenumberThe thinking Bash did while it worked, in billed US dollars.
Type
number
toolsnumberThe tools and apps Bash used, in billed US dollars.
Type
number
computenumberTime on Bash's computer, in billed US dollars.
Type
number
backgroundnumberWork Bash did in the background, such as remembering and tidying, in billed US dollars.
Type
number
voicenumberVoice call time, in billed US dollars.
Type
number
turn_idstringmay be absentThe turn of the first message, when you sent one (turn_...).
Type
string
TypeScript
const reply = await vestra.user('traveller-42').ask('My 6am flight got cancelled. Get me on the next one.').text();
Python
reply = vestra.user("traveller-42").ask("My 6am flight got cancelled. Get me on the next one.").text()
CLI
vestra ask "My 6am flight got cancelled. Get me on the next one." --user traveller-42
HTTP
# Ask for one of your users. Their Bash is created the first time you name them. With stream: true, the# response streams this turn's events as they happen, and ends when the turn is over.curl -N "$VESTRA_BASE_URL/v1/conversations" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "user_id": "traveller-42",    "message": "My 6am flight got cancelled. What should I do?",    "stream": true  }' # Ask a follow-up. It goes to the same conversation.curl -N "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/messages" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{ "message": "Can I get a refund for it?", "stream": true }' # Stop a reply and its work. This stops the reply and every task the conversation started.curl -X POST "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/stop" \  -H "Authorization: Bearer $VESTRA_API_KEY" # Ask for your company. Leave user_id out, and the job goes to your company's own Bash.curl "$VESTRA_BASE_URL/v1/conversations" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{ "message": "Write a two-line notice for our travellers about storm delays at Mumbai airport today." }' # Ask for many users at once. Each user gets their own conversation. If Bash asks one of them a question,# that item waits for the answer.curl "$VESTRA_BASE_URL/v1/batches" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "items": [      { "user_id": "traveller-42", "message": "A storm may delay flights from Mumbai today. What should I do before I leave for the airport? Two lines, in general: no need to look up my booking." },      { "user_id": "traveller-77", "message": "A storm may delay flights from Pune today. What should I do before I leave for the airport? Two lines, in general: no need to look up my booking." }    ]  }'
MCP
{  "method": "tools/call",  "params": {    "name": "ask",    "arguments": {      "user": "traveller-42",      "message": "My 6am flight got cancelled. Get me on the next one."    }  }}
GET/v1/conversationsConversations, newest first: one user's with user_id, or every one of the company's without it (the company's own Bash shows user_id null).

Your API key, scope runtime or all. On the card: ask. Over HTTP it is made from the contract: fill in every value.

GET/v1/conversations/{conversation_id}One conversation: status (idle, replying, working, waiting), its open work, its open approvals.

Your API key, or a session's token, scope runtime or all. On the card: ask. Every call here is a checked sample.

POST/v1/conversations/{conversation_id}/messagesSend a message.

Options: context (data for this turn only), attachments, output_schema, success_criteria, tools, hand_off (auto or always). Answers the turn at once; Prefer: wait=N holds for the final answer; stream: true answers this turn's events as text/event-stream and ends when the turn settles.

Your API key, or a session's token, scope runtime or all. On the card: ask. Every call here is a checked sample.

GET/v1/conversations/{conversation_id}/messagesThe conversation, paged: your messages, Bash's replies, and summaries of the work it did.

Your API key, or a session's token, scope runtime or all. On the card: ask. Over HTTP it is made from the contract: fill in each {…} and every value.

GET/v1/conversations/{conversation_id}/eventsThe one stream (SSE): replies as they are typed, work started and finished, progress, approvals, tool calls, files.

Resume with Last-Event-ID. Filter to one task's events with task_id.

Your API key, or a session's token, scope runtime or all. On the card: events. Every call here is a checked sample.

POST/v1/conversations/{conversation_id}/stopStop the reply and every piece of work the conversation started.

Your API key, or a session's token, scope runtime or all. On the card: ask. Every call here is a checked sample.