BashBrainTeammatesPricingDevelopersGet a test key

routines

Run a job on a schedule, or each time your system calls a URL. A routine is a saved job that runs on a schedule written in plain words, such as weekday at 08:00, or when your system posts to its trigger URL. Each run appears in the routine's conversation like any other ask, so its replies, approvals and files are where you already look.

Run on a schedule

Write it in plain words, read in the traveller's own time zone. The response gives the cron expression and the next run.

TypeScript
const traveller = vestra.user('traveller-42'); const daily = await traveller.routines.create({  ask: 'Check my trips for today and tell me about any delay.',  every: 'weekday at 08:00',});console.log(daily.schedule?.cron, daily.next_run_at);

Run when your system calls

Post a payload to the routine's trigger_url.

TypeScript
const onDelay = await traveller.routines.create({ ask: 'A train of mine is late. Find me another way.', on: 'call' });await traveller.routines.trigger(onDelay.id, { train: '12127', delay_minutes: 45 });

Manage a routine

Pause it, resume it, run it once now, and read its runs.

TypeScript
await traveller.routines.pause(daily.id);await traveller.routines.resume(daily.id);await traveller.routines.run(daily.id);const runs = await traveller.routines.runs(daily.id);console.log(runs.data.length);

Run on a schedule

Write it in plain words, read in the traveller's own time zone. The response gives the cron expression and the next run.

Python
traveller = vestra.user("traveller-42") daily = traveller.routines.create("Check my trips for today and tell me about any delay.", every="weekday at 08:00")print(daily.schedule.cron, daily.next_run_at)

Run when your system calls

Post a payload to the routine's trigger_url.

Python
on_delay = traveller.routines.create("A train of mine is late. Find me another way.", on="call")traveller.routines.trigger(on_delay.id, {"train": "12127", "delay_minutes": 45})

Manage a routine

Pause it, resume it, run it once now, and read its runs.

Python
traveller.routines.pause(daily.id)traveller.routines.resume(daily.id)traveller.routines.run(daily.id)print(len(traveller.routines.runs(daily.id).data))

Run on a schedule

Write it in plain words, read in the traveller's own time zone.

CLI
vestra routines add "Check my trips for today and tell me about any delay." \  --every "weekday at 08:00" --user traveller-42

Run when your system calls

Your system posts to the routine's trigger_url.

CLI
vestra routines add "A train of mine is late. Find me another way." --on call --user traveller-42

Manage a routine

List the user's routines, then run one now, pause it, resume it, and read its runs.

CLI
vestra routines --user traveller-42vestra routines run rtn_5kdvestra routines pause rtn_5kdvestra routines resume rtn_5kdvestra routines runs rtn_5kd

Run on a schedule

Write it in plain words, read in the user's own time zone. The response gives the cron expression and the next run.

HTTP
curl "$VESTRA_BASE_URL/v1/routines" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{    "user_id": "traveller-42",    "ask": "Check my trips for today and tell me about any delay.",    "every": "weekday at 08:00"  }'

Run when your system calls

Post a payload to the routine's trigger_url.

HTTP
curl "$VESTRA_BASE_URL/v1/routines" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{ "user_id": "traveller-42", "ask": "A train of mine is late. Find me another way.", "on": "call" }' curl "$VESTRA_BASE_URL/v1/routines/rtn_7qp/trigger" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{ "train": "12127", "delay_minutes": 45 }'

Manage a routine

Pause it (enabled: true resumes it), run it once now, and list the user's routines.

HTTP
curl -X PATCH "$VESTRA_BASE_URL/v1/routines/rtn_5kd" \  -H "Authorization: Bearer $VESTRA_API_KEY" \  -H "Content-Type: application/json" \  -d '{ "enabled": false }' curl -X POST "$VESTRA_BASE_URL/v1/routines/rtn_5kd/run" \  -H "Authorization: Bearer $VESTRA_API_KEY" curl "$VESTRA_BASE_URL/v1/routines?user_id=traveller-42" \  -H "Authorization: Bearer $VESTRA_API_KEY"
MCP
{  "method": "tools/call",  "params": {    "name": "routines_add",    "arguments": {      "user": "traveller-42",      "ask": "Check my trips for today and tell me about any delay.",      "every": "weekday at 08:00",      "timezone": "Asia/Kolkata"    }  }}

Good to know

Writing a schedule

every understands day at 09:00, weekday at 08:00 (or weekdays), weekend at 10:30, days such as mon, wed, fri at 18:30, 30 minutes (15, 20 or 30), 2 hours (1, 2, 3, 4, 6, 8 or 12) and month on the 1st at 09:00 (the 1st to the 28th). Times use the 24-hour clock. A phrase it cannot read fails with 400 schedule_unreadable, along with examples that work. You can also pass a cron expression as schedule.

Time zones

A schedule is read in the timezone you give. Without one, it uses the user's own time zone, and then UTC. The response includes the cron expression and the next run time.

Routines Bash creates

If you ask Bash in a conversation to check your trips every weekday at 8, it creates the routine itself. It appears in the list like any other routine.

Routine limits

Your company can have up to 200 routines in each mode (test or live), paused ones included. One more fails with 409 org_routine_limit_reached. Running routines yourself with run and trigger is limited to 12 times an hour for one routine, and 240 times an hour for your company.

A copy for each user

A routine your file declares with for: each customer gets one copy per user, made the first time that user talks to that deployment's Bash. Copies count toward the same limit, 200 per mode. A copy past the limit is skipped with org_routine_limit_reached and never retried.

When a routine runs

Each run sends a routine.fired event that names the run and its conversation, on the stream and to your webhooks.

The routes behind routines8 routes, each with every field in the API reference
POST/v1/routinesCreate one: what to ask, and when: every (plain words such as "weekday at 08:00", read in the user's time zone), a cron schedule, or on "call" (your system posts to its trigger_url). For a user, or with no user_id for the company's own Bash. Each run is a message in the routine's conversation.Key scope: runtime (or all)
GET/v1/routinesThe routines of one user (user_id), or of the company's own Bash.Key scope: runtime (or all)
GET/v1/routines/{routine_id}One routine.Key scope: runtime (or all)
PATCH/v1/routines/{routine_id}Change what it asks, when it runs (every, schedule or timezone), its filters, or pause and resume it.Key scope: runtime (or all)
DELETE/v1/routines/{routine_id}Delete it.Key scope: runtime (or all)
POST/v1/routines/{routine_id}/runRun it now.Key scope: runtime (or all)
POST/v1/routines/{routine_id}/triggerFire it with a payload from your system: a train delayed, a refund posted.Key scope: runtime (or all)
GET/v1/routines/{routine_id}/runsPast runs and the tasks they started.Key scope: runtime (or all)