events
Follow what Bash is doing. Every step it takes is an event: the reply as it is written, tasks starting and finishing, approvals, files and costs. You can stream one conversation's events live, read every step of a task afterwards, or have events sent to your server as webhooks.
Stream a conversation live
You get its stored events first, then new ones as they happen.
for await (const event of vestra.events('conv_8f2k')) { console.log(event.type, event.data); if (event.type === 'conversation.status' && event.data.turn_status === 'completed') break;}Read a task afterwards
You get every step of one task, with tokens and cost per turn.
const trace = await vestra.events.trace('task_91d');Send events to your server
Webhooks are signed and have the same shape. The signing secret is shown only once.
const endpoint = await vestra.events.to('https://hooks.example.com/vestra', { events: ['task.completed', 'interaction.created', 'usage.cap_reached'] });console.log(endpoint.secret);app.post('/vestra', express.raw({ type: 'application/json' }), vestra.events.handler(async (event) => { if (event.type === 'task.completed') await markDone(event.task_id, event.data.cost_usd);}));Catch up on what you missed
List the events your webhooks were sent, newest first.
const failed = await vestra.events.list({ type: 'task.failed' });console.log(trace, failed.data.length);Stream a conversation live
You get its stored events first, then new ones as they happen.
for event in vestra.events("conv_8f2k"): print(event.type, event.data) if event.type == "conversation.status" and event.data.turn_status == "completed": breakRead a task afterwards
You get every step of one task, with tokens and cost per turn.
trace = vestra.events.trace("task_91d")Send events to your server
Webhooks are signed and have the same shape. The signing secret is shown only once.
endpoint = vestra.events.to("https://hooks.example.com/vestra", events=["task.completed", "interaction.created", "usage.cap_reached"])print(endpoint.secret) def on_event(event): if event.type == "task.completed": mark_done(event.task_id, event.data.get("cost_usd")) handler = vestra.events.handler(on_event) # reads VESTRA_WEBHOOK_SECRET @app.post("/vestra")def vestra_webhook(): # Flask: hand it the raw body, as it came status, body = handler(request.get_data(), request.headers) return body, statusCatch up on what you missed
List the events your webhooks were sent, newest first.
failed = vestra.events.list(type="task.failed")print(trace, len(failed.data))Catch up on what you missed
List the events your webhooks were sent, newest first.
vestra events --type task.completed --user traveller-42Read a task afterwards
You get each step, and what it cost.
vestra events task_91dSend events to your server
They arrive signed, and the signing secret is shown only once.
vestra events --to https://hooks.example.com/vestra --type task.completed,interaction.createdvestra events conv_8f2k follows a conversation as it happens, and vestra events --to localhost:3000/vestra forwards events to this computer while you build. Both run until you press Ctrl-C.
Stream a conversation live
If the connection drops, reconnect with the last seq you saw.
curl -N "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events" \ -H "Authorization: Bearer $VESTRA_API_KEY" \ -H "Last-Event-ID: 41"Read the same events as JSON
You get them in pages, after the seq you give.
curl "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events?format=json&after=41" \ -H "Authorization: Bearer $VESTRA_API_KEY"Read a task afterwards
You get every step of one task, with tokens and cost per turn.
curl "$VESTRA_BASE_URL/v1/tasks/task_91d/trace" \ -H "Authorization: Bearer $VESTRA_API_KEY"Send events to your server
Register a URL and the events it wants. The signing secret is shown only once.
curl "$VESTRA_BASE_URL/v1/webhooks" \ -H "Authorization: Bearer $VESTRA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://hooks.example.com/vestra", "events": ["task.completed", "interaction.created", "usage.cap_reached"] }'Catch up on what you missed
List the events your webhooks were sent, newest first.
curl "$VESTRA_BASE_URL/v1/events?type=task.failed" \ -H "Authorization: Bearer $VESTRA_API_KEY"{ "method": "tools/call", "params": { "name": "events", "arguments": { "user": "traveller-42", "conversation": "conv_8f2k", "after": 0 } }}Good to know
The event shape in the SDKs
However an event arrives, the SDK gives you the same shape: { id, seq, type, created_at, user, conversation_id, task_id, data, via }. user is your id for the user, or null for your company's own Bash. Once you check event.type, event.data has the matching type.
Streaming over HTTP
GET /v1/conversations/{id}/events streams Server-Sent Events. Each frame has id: <seq>, event: <type> and data: { seq, type, data, created_at }. Reconnect with Last-Event-ID: <seq>, and you miss nothing. ?format=json&after=<seq> returns the same events as pages of JSON.
Webhook bodies and signatures
A webhook's body is { id, object, type, mode, created_at, user_id, task_id, conversation_id, data }. It is signed in the Vestra-Signature: t=<unix seconds>,v1=<hex> header. The signature is an HMAC-SHA256 of <t>.<raw body> with your endpoint's secret, and it is valid for 300 seconds. vestra.events.handler checks it for you. Without the SDK, check it yourself before you trust a body.
Stream or webhooks
The stream carries everything that happens in a conversation. Webhooks carry the events that still matter afterwards: replies, tasks, approvals, files, sessions, routines, usage alerts, and changes to users, connections, deployments, tests and keys. message.delta, task.progress, usage.updated and screen.control only arrive on the stream.
Catching up
GET /v1/events lists the events your webhooks were sent, newest first. ?after=evt_… reads forward from an event you saw.
Every event
One catalog names every event, on the stream and in your webhooks. The events reference lists each, where it arrives, and every field it carries.
The routes behind events13 routes, each with every field in the API reference
runtime (or all)runtime (or all)setup (or all)setup (or all)setup (or all)setup (or all)runtime (or all)