# Routines API

> Jobs Bash runs on a schedule in plain words, or whenever your system calls.

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

## `POST /v1/routines`

Its own page: [POST /v1/routines](https://vestra.ai/developers/reference/api/routines/post-v1-routines.md)

Create 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.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Every call here is a checked sample.

### Request

Headers:

- `Idempotency-Key` (`string`): Send the same key to retry this call safely for 24 hours.

Body:

- `user_id` (`string`): Whose Bash runs it: your id for the user. Absent: your company's own Bash. Example: `traveller-42`.
- `ask` (`string`, required): What Bash is asked on every run, as a person would ask it, up to 8,000 characters. Limits: 1 to 8000 characters. Example: `Check today's trips for delays and tell me what changed.`.
- `name` (`string`): Its name, up to 200 characters. Absent: the start of `ask`. Limits: 1 to 200 characters.
- `every` (`string`): When it runs, in plain words: `weekday at 08:00`, `mon, wed, fri at 18:30`, `30 minutes`, `month on the 1st at 09:00`. At most once every 15 minutes. Give one of `every`, `schedule` or `on`. Limits: 1 to 100 characters. Example: `weekday at 08:00`.
- `timezone` (`string`): The zone `every` is read in, an IANA name such as `Asia/Kolkata`. Absent: the user's own, then UTC. Limits: 1 to 64 characters. Example: `Asia/Kolkata`.
- `schedule` (`object`): When it runs, as cron, instead of `every`.
  - `cron` (`string`, required): A cron expression of five fields: `0 7 * * *` runs at 7:00 every day. Limits: 1 to 120 characters. Example: `0 7 * * 1-5`.
  - `timezone` (`string`): The zone the cron is read in, an IANA name such as `Asia/Kolkata`. Absent: the user's own, then UTC. Limits: 1 to 64 characters. Example: `Asia/Kolkata`.
- `on` (`"call"`): `call`: it runs whenever your system posts to its `trigger_url`, instead of on a schedule.
- `filters` (`map of any`): With `on: call`, the fields and values a payload must carry for the routine to run; any other payload is `filtered`. Example: `{"event":"flight.delayed"}`.
- `conversation_id` (`string`): An existing conversation of this user that each run posts into. Absent: the routine gets its own. Limits: at least 1 character.
- `deployment` (`string`): For the routine's own conversation, a deployment by its `dep_` id or name. Absent: the user's default, then the company's. Limits: at least 1 character.
- `enabled` (`boolean`): false makes it paused: it keeps its schedule but does not run. Default true. Default: `true`.

### Answers 201

- `id` (`string`): The routine's id. Example: `rtn_8f2k`.
- `object` (`"routine"`): Always `routine`.
- `user_id` (`string | null`): Your id for the user whose Bash runs it; null for your company's own Bash.
- `conversation_id` (`string | null`): The conversation each run posts into, named or made when the routine was; null for a routine not made through the API.
- `name` (`string`): Its name.
- `ask` (`string`): What Bash is asked on every run.
- `kind` (`"schedule" | "trigger" | "app_event"`): `schedule`: it runs on its schedule. `trigger`: it runs when your system posts to `trigger_url`. `app_event`: an event in a connected app runs it.
- `schedule` (`object | null`): When it runs; null for one that runs on a call.
  - `every` (`string | null`): The plain words it was given; null for a cron.
  - `cron` (`string`): The schedule as cron, worked out from `every` when it was given in words.
  - `timezone` (`string`): The zone it runs in, an IANA name.
- `trigger` (`object | null`): For one that runs on a call, what it listens for; null for one on a schedule.
  - `filters` (`map of any | null`): What a payload must carry for it to run; null: any payload.
- `trigger_url` (`string | null`): For one that runs on a call: POST here, with your key and any JSON object, to run it. Null otherwise.
- `enabled` (`boolean`): false while it is paused.
- `status` (`"active" | "completed" | "failed"`): `active`: it runs as it should. `completed`: it has finished and will not run again. `failed`: it stopped on an error.
- `last_run_at` (`string | null`): When it last ran; null when it never has.
- `next_run_at` (`string | null`): When it runs next; null when paused, finished, or run on a call.
- `run_count` (`integer`): How many times it has run.
- `created_at` (`string`): When it was made, as an ISO 8601 date and time in UTC.
- `updated_at` (`string`): When it last changed, as an ISO 8601 date and time in UTC.

### Code

**TypeScript**

```ts
const routine = await vestra.user('traveller-42').routines.create({ ask: 'Check my trips for today.', every: 'weekday at 08:00' });
```

**Python**

```python
routine = vestra.user("traveller-42").routines.create("Check my trips for today.", every="weekday at 08:00")
```

**CLI**

```bash
vestra routines add "Check my trips for today." --every "weekday at 08:00" --user traveller-42
```

**HTTP**

```bash
# 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.
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.
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.
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**

```json
{
  "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"
    }
  }
}
```

## `GET /v1/routines`

Its own page: [GET /v1/routines](https://vestra.ai/developers/reference/api/routines/get-v1-routines.md)

The routines of one user (user_id), or of the company's own Bash.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Every call here is a checked sample.

### Request

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.
- `user_id` (`string`): Whose routines: your id for the user. Absent: your company's own Bash's.

### Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The routine's id. Example: `rtn_8f2k`.
  - `object` (`"routine"`): Always `routine`.
  - `user_id` (`string | null`): Your id for the user whose Bash runs it; null for your company's own Bash.
  - `conversation_id` (`string | null`): The conversation each run posts into, named or made when the routine was; null for a routine not made through the API.
  - `name` (`string`): Its name.
  - `ask` (`string`): What Bash is asked on every run.
  - `kind` (`"schedule" | "trigger" | "app_event"`): `schedule`: it runs on its schedule. `trigger`: it runs when your system posts to `trigger_url`. `app_event`: an event in a connected app runs it.
  - `schedule` (`object | null`): When it runs; null for one that runs on a call.
    - `every` (`string | null`): The plain words it was given; null for a cron.
    - `cron` (`string`): The schedule as cron, worked out from `every` when it was given in words.
    - `timezone` (`string`): The zone it runs in, an IANA name.
  - `trigger` (`object | null`): For one that runs on a call, what it listens for; null for one on a schedule.
    - `filters` (`map of any | null`): What a payload must carry for it to run; null: any payload.
  - `trigger_url` (`string | null`): For one that runs on a call: POST here, with your key and any JSON object, to run it. Null otherwise.
  - `enabled` (`boolean`): false while it is paused.
  - `status` (`"active" | "completed" | "failed"`): `active`: it runs as it should. `completed`: it has finished and will not run again. `failed`: it stopped on an error.
  - `last_run_at` (`string | null`): When it last ran; null when it never has.
  - `next_run_at` (`string | null`): When it runs next; null when paused, finished, or run on a call.
  - `run_count` (`integer`): How many times it has run.
  - `created_at` (`string`): When it was made, as an ISO 8601 date and time in UTC.
  - `updated_at` (`string`): When it last changed, as an ISO 8601 date and time in UTC.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

### Code

**TypeScript**

```ts
const routines = await vestra.routines.list();
```

**Python**

```python
routines = vestra.routines.list()
```

**CLI**

```bash
vestra routines
```

**HTTP**

```bash
# 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.
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.
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.
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**

```json
{
  "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"
    }
  }
}
```

## `GET /v1/routines/{routine_id}`

Its own page: [GET /v1/routines/{routine_id}](https://vestra.ai/developers/reference/api/routines/get-v1-routines-routine-id.md)

One routine.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `routine_id` (`string`, required): The routine's id (`rtn_...`).

### Answers 200

- `id` (`string`): The routine's id. Example: `rtn_8f2k`.
- `object` (`"routine"`): Always `routine`.
- `user_id` (`string | null`): Your id for the user whose Bash runs it; null for your company's own Bash.
- `conversation_id` (`string | null`): The conversation each run posts into, named or made when the routine was; null for a routine not made through the API.
- `name` (`string`): Its name.
- `ask` (`string`): What Bash is asked on every run.
- `kind` (`"schedule" | "trigger" | "app_event"`): `schedule`: it runs on its schedule. `trigger`: it runs when your system posts to `trigger_url`. `app_event`: an event in a connected app runs it.
- `schedule` (`object | null`): When it runs; null for one that runs on a call.
  - `every` (`string | null`): The plain words it was given; null for a cron.
  - `cron` (`string`): The schedule as cron, worked out from `every` when it was given in words.
  - `timezone` (`string`): The zone it runs in, an IANA name.
- `trigger` (`object | null`): For one that runs on a call, what it listens for; null for one on a schedule.
  - `filters` (`map of any | null`): What a payload must carry for it to run; null: any payload.
- `trigger_url` (`string | null`): For one that runs on a call: POST here, with your key and any JSON object, to run it. Null otherwise.
- `enabled` (`boolean`): false while it is paused.
- `status` (`"active" | "completed" | "failed"`): `active`: it runs as it should. `completed`: it has finished and will not run again. `failed`: it stopped on an error.
- `last_run_at` (`string | null`): When it last ran; null when it never has.
- `next_run_at` (`string | null`): When it runs next; null when paused, finished, or run on a call.
- `run_count` (`integer`): How many times it has run.
- `created_at` (`string`): When it was made, as an ISO 8601 date and time in UTC.
- `updated_at` (`string`): When it last changed, as an ISO 8601 date and time in UTC.

### Code

**TypeScript**

```ts
const routine = await vestra.routines.get('rtn_5kd');
```

**Python**

```python
routine = vestra.routines.get("rtn_5kd")
```

**CLI**

```bash
vestra routines get rtn_5kd
```

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/routines/{routine_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**MCP**: No sample in your language for this route, so here it is over HTTP.

## `PATCH /v1/routines/{routine_id}`

Its own page: [PATCH /v1/routines/{routine_id}](https://vestra.ai/developers/reference/api/routines/patch-v1-routines-routine-id.md)

Change what it asks, when it runs (every, schedule or timezone), its filters, or pause and resume it.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Every call here is a checked sample.

### Request

Path:

- `routine_id` (`string`, required): The routine's id (`rtn_...`).

Body:

- `name` (`string`): A new name, up to 200 characters. Limits: 1 to 200 characters.
- `ask` (`string`): What Bash is asked on every run from now on, up to 8,000 characters. Limits: 1 to 8000 characters.
- `every` (`string`): A new schedule. When it runs, in plain words: `weekday at 08:00`, `mon, wed, fri at 18:30`, `30 minutes`, `month on the 1st at 09:00`. At most once every 15 minutes. Limits: 1 to 100 characters.
- `timezone` (`string`): A new zone, an IANA name, for the schedule it already has or for new plain words. Limits: 1 to 64 characters.
- `schedule` (`object`): A new schedule as cron, instead of `every`.
  - `cron` (`string`, required): A cron expression of five fields: `0 7 * * *` runs at 7:00 every day. Limits: 1 to 120 characters. Example: `0 7 * * 1-5`.
  - `timezone` (`string`): The zone the cron is read in, an IANA name such as `Asia/Kolkata`. Absent: the user's own, then UTC. Limits: 1 to 64 characters. Example: `Asia/Kolkata`.
- `filters` (`map of any`): New filters, for a routine that runs on a call.
- `enabled` (`boolean`): false pauses it; true resumes it.

### Answers 200

- `id` (`string`): The routine's id. Example: `rtn_8f2k`.
- `object` (`"routine"`): Always `routine`.
- `user_id` (`string | null`): Your id for the user whose Bash runs it; null for your company's own Bash.
- `conversation_id` (`string | null`): The conversation each run posts into, named or made when the routine was; null for a routine not made through the API.
- `name` (`string`): Its name.
- `ask` (`string`): What Bash is asked on every run.
- `kind` (`"schedule" | "trigger" | "app_event"`): `schedule`: it runs on its schedule. `trigger`: it runs when your system posts to `trigger_url`. `app_event`: an event in a connected app runs it.
- `schedule` (`object | null`): When it runs; null for one that runs on a call.
  - `every` (`string | null`): The plain words it was given; null for a cron.
  - `cron` (`string`): The schedule as cron, worked out from `every` when it was given in words.
  - `timezone` (`string`): The zone it runs in, an IANA name.
- `trigger` (`object | null`): For one that runs on a call, what it listens for; null for one on a schedule.
  - `filters` (`map of any | null`): What a payload must carry for it to run; null: any payload.
- `trigger_url` (`string | null`): For one that runs on a call: POST here, with your key and any JSON object, to run it. Null otherwise.
- `enabled` (`boolean`): false while it is paused.
- `status` (`"active" | "completed" | "failed"`): `active`: it runs as it should. `completed`: it has finished and will not run again. `failed`: it stopped on an error.
- `last_run_at` (`string | null`): When it last ran; null when it never has.
- `next_run_at` (`string | null`): When it runs next; null when paused, finished, or run on a call.
- `run_count` (`integer`): How many times it has run.
- `created_at` (`string`): When it was made, as an ISO 8601 date and time in UTC.
- `updated_at` (`string`): When it last changed, as an ISO 8601 date and time in UTC.

### Code

**TypeScript**

```ts
await vestra.routines.pause('rtn_5kd');
```

**Python**

```python
vestra.routines.pause("rtn_5kd")
```

**CLI**

```bash
vestra routines pause rtn_5kd
```

**HTTP**

```bash
# 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.
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.
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.
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**

```json
{
  "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"
    }
  }
}
```

## `DELETE /v1/routines/{routine_id}`

Its own page: [DELETE /v1/routines/{routine_id}](https://vestra.ai/developers/reference/api/routines/delete-v1-routines-routine-id.md)

Delete it.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `routine_id` (`string`, required): The routine's id (`rtn_...`).

### Answers 200

- `id` (`string`): The deleted routine's id.
- `object` (`"routine"`): Always `routine`.
- `deleted` (`true`): Always true: it is gone and never runs again.

### Code

**TypeScript**

```ts
await vestra.routines.delete('rtn_5kd');
```

**Python**

```python
vestra.routines.delete("rtn_5kd")
```

**CLI**

```bash
vestra routines delete rtn_5kd
```

**HTTP**

```bash
curl -X DELETE "$VESTRA_BASE_URL/v1/routines/{routine_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**MCP**: No sample in your language for this route, so here it is over HTTP.

## `POST /v1/routines/{routine_id}/run`

Its own page: [POST /v1/routines/{routine_id}/run](https://vestra.ai/developers/reference/api/routines/post-v1-routines-routine-id-run.md)

Run it now.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Every call here is a checked sample.

### Request

Path:

- `routine_id` (`string`, required): The routine's id (`rtn_...`).

Headers:

- `Idempotency-Key` (`string`): Send the same key to retry this call safely for 24 hours.

### Answers 202

- `object` (`"routine_fire"`): Always `routine_fire`.
- `routine_id` (`string`): The routine it runs.
- `status` (`"queued" | "duplicate" | "filtered"`): `queued`: it runs now. `duplicate`: the same run was already asked for, so it runs once. `filtered`: the payload did not match its `filters`, so it does not run.

### Code

**TypeScript**

```ts
await vestra.routines.run('rtn_5kd');
```

**Python**

```python
vestra.routines.run("rtn_5kd")
```

**CLI**

```bash
vestra routines run rtn_5kd
```

**HTTP**

```bash
# 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.
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.
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.
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**

```json
{
  "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"
    }
  }
}
```

## `POST /v1/routines/{routine_id}/trigger`

Its own page: [POST /v1/routines/{routine_id}/trigger](https://vestra.ai/developers/reference/api/routines/post-v1-routines-routine-id-trigger.md)

Fire it with a payload from your system: a train delayed, a refund posted.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Every call here is a checked sample.

### Request

Path:

- `routine_id` (`string`, required): The routine's id (`rtn_...`).

Headers:

- `Idempotency-Key` (`string`): Send the same key to retry this call safely for 24 hours.

Body, if you send one:

`map of any`

### Answers 200 or 202

- `object` (`"routine_fire"`): Always `routine_fire`.
- `routine_id` (`string`): The routine it runs.
- `status` (`"queued" | "duplicate" | "filtered"`): `queued`: it runs now. `duplicate`: the same run was already asked for, so it runs once. `filtered`: the payload did not match its `filters`, so it does not run.

### Code

**TypeScript**

```ts
await vestra.routines.trigger('rtn_7qp');
```

**Python**

```python
vestra.routines.trigger("rtn_7qp")
```

**HTTP**

```bash
# 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.
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.
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.
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**

```json
{
  "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"
    }
  }
}
```

**CLI**: No sample in your language for this route, so here it is over HTTP.

## `GET /v1/routines/{routine_id}/runs`

Its own page: [GET /v1/routines/{routine_id}/runs](https://vestra.ai/developers/reference/api/routines/get-v1-routines-routine-id-runs.md)

Past runs and the tasks they started.

Your API key, scope `runtime` or `all`. On the card: [`routines`](https://vestra.ai/developers/routines.md). Every call here is a checked sample.

### Request

Path:

- `routine_id` (`string`, required): The routine's id (`rtn_...`).

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.

### Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The run's id.
  - `object` (`"routine_run"`): Always `routine_run`.
  - `routine_id` (`string`): The routine it is a run of.
  - `conversation_id` (`string | null`): The conversation the run's message landed in; null when it never got that far.
  - `status` (`"pending" | "running" | "completed" | "failed" | "skipped"`): `pending` or `running` while it goes. `completed`: Bash took the ask (the work it started is in `task_ids`). `failed`: it could not post the ask. `skipped`: it did not run, as `error` says.
  - `trigger_payload` (`map of any | null`): The payload your system sent, for a run on a call; null for a scheduled run.
  - `task_ids` (`string[]`): The pieces of work the run started.
  - `error` (`string | null`): Why it failed or was skipped; null otherwise.
  - `started_at` (`string`): When it began, as an ISO 8601 date and time in UTC.
  - `completed_at` (`string | null`): When it ended; null while it goes.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

### Code

**TypeScript**

```ts
const runs = await vestra.routines.runs('rtn_5kd');
```

**Python**

```python
runs = vestra.routines.runs("rtn_5kd")
```

**CLI**

```bash
vestra routines runs rtn_5kd
```

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/routines/rtn_5kd/runs" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**MCP**: No sample in your language for this route, so here it is over HTTP.
