Give every user an agent,right inside your app.
Your users ask in plain words. Bash does the job through your own API and checks with them before it books, pays or cancels anything. You write the functions, we run the agent.
npm install ./vestra-sdk-0.1.7.tgz
import { Vestra } from '@vestra/sdk'; // get_booking is your API. It only reads, so Bash calls it freely. const vestra = new Vestra({ tools: { get_booking } }); const run = vestra.user('traveller-42') .ask('My 6am flight got cancelled. Get me on the next one.'); for await (const event of run) { // Bash stops here for your user's yes const asked = event.interaction; if (asked?.type !== 'approval') continue; const yes = await app.confirm(event.user, asked.summary); await event.answer({ approve: yes, present_user: true }); } console.log(await run.text());
from vestra import Vestra # get_booking is your API. It only reads, so Bash calls it freely. vestra = Vestra(tools={"get_booking": lookup_booking}) run = vestra.user("traveller-42").ask("My 6am flight got cancelled. Get me on the next one.") for event in run: # Bash stops here for your user's yes asked = event.interaction if asked and asked.type == "approval": yes = app.confirm(event.user, asked.summary) event.answer(approve=yes, present_user=True) print(run.text())
# Paste your test key once; vestra keeps it on this computer. $ vestra login # tools.mjs exports a function per tool your setup declares: get_booking here. $ vestra ask "My 6am flight got cancelled. Get me on the next one." --user traveller-42 --tools ./tools.mjs # Bash asks here before it pays. From a script or another terminal, answer by the id it names. $ vestra answer int_3j9 --approve --present-user
# stream: true answers this turn's events as they happen. 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. Get me on the next one.", "stream": true }' # interaction.created: Bash stops here for your user's yes. Show it, then answer with what they chose. curl "$VESTRA_BASE_URL/v1/interactions/int_3j9/answer" \ -H "Authorization: Bearer $VESTRA_API_KEY" \ -d '{ "approve": true, "present_user": true }'
// mcp.json: any MCP client, your key as the bearer { "mcpServers": { "vestra": { "type": "http", "url": "https://api.vestra.ai/v1/mcp", "headers": { "Authorization": "Bearer vk_test_..." } } } } // then the ask, as a tool call { "method": "tools/call", "params": { "name": "ask", "arguments": { "user": "traveller-42", "message": "My 6am flight got cancelled. Get me on the next one." } } } // and the yes, once your user saw it { "method": "tools/call", "params": { "name": "answer", "arguments": { "interaction": "int_3j9", "approve": true, "present_user": true } } }
What traveller-42 sees in your app
Bash asks traveller-42waits for a yesBook the 09:15 tomorrow, Delhi to Pune, so you land before your meeting.
- Flight
- 6E 2171, departs 09:15, gate B4
- Fare
- Rs 5,420 on the card ending 4412
- Refund
- Rs 4,980 from the cancelled 6E 2134, back in 5 days
You're on the 09:15 tomorrow, seat 14C. Your refund of Rs 4,980 is on its way.
Your code grows a line at a time.
One traveller, from the first ask to your launch. Each step adds a line or two, and shows what Bash does with it.
$ vestra test
Testing travel-help version 3.
passed: (all 5)
$ vestra deploy --live
task.startedRebook the flightBook the 09:15 to Mumbai, seat 14C?
The fare difference is ₹1,200. Nothing is booked until they say yes.
{ ref: 'TN-48213' }{ from: 'DEL', to: 'BOM', leaves: '06:10', status: 'cancelled' }The next flight to Mumbai is the 09:15. Shall I book it?
Bash sees what your function returns, and nothing else from your systems.
- Everyday baggage question
- Flight time with no reference
- Cancellation request with approval
- Delayed flight question
- Pressure to promise a refund
vestra deploy --liveGuide 1 walks this path with your own key, and it ran end to end on our staging servers on 1 October. Open guide 1
Five doors. The same ask.
TypeScript, Python, the CLI, plain HTTP or MCP. Every door takes the same words and brings back the same events.
What comes back
- conversation.status
- message.delta
- task.started
- interaction.created
One card. Eighteen commands.
Learn these and you can guess the rest. Every door, guide and reference is organised by them.
Every command has its own page, with all five doors.
Guides and references.
Short steps, code that grows, and what happens after each one.
Guides
- 1Build a travel help desk in 15 minutes
- 2Give Bash your tools
- 3Let your customer say yes
- 4Put Bash inside your app
- 5Test before your customers see it
- 6Events and webhooks
- 7Many customers at once
- 8Routines in plain words
- 9From your editor
- 10Going live
Reference
- The APIEvery route: its fields, and a sample per door
- The file, vestra.yamlEvery field, what it does, and an example
- EventsThe one catalog, for streams and webhooks
- ErrorsWhat each code means, and what to do
- The SDKs and the CLIEvery method and command, from their source
Give every customer
a Bash of their own.
Get a test key, follow the quickstart, and watch your first yes come back.


