# users

> Manage your users: profiles, spending caps, export and erasing.

Manage the people who use your app. Each one is a user, named by your own id, and Vestra creates them the first time you name them. Here you can give a user a name and time zone, cap what they spend, export everything Vestra holds about them, or erase them.

## TypeScript

```ts
// Create a user. Do it before their first ask to set their name and time zone. It is safe to repeat.
await vestra.users.create('traveller-42', { name: 'Priya Sharma', timezone: 'Asia/Kolkata' });

// Read their spend. Their profile shows what they spent this month, and what is left under their cap.
const traveller = vestra.user('traveller-42');
const profile = await traveller.get();
console.log(profile.spend_month_usd, profile.caps_remaining.month_usd);

// Set a monthly cap. Then wake their computer, and export everything Vestra holds about them.
await traveller.update({ monthly_cap_usd: 20 });
await traveller.warm(); // wake their computer before they need it
console.log(await traveller.export());

// Erase a user. It runs as a job: deleted is false and status is deleting until user.deleted says it is done.
const erasing = await traveller.delete();
console.log(erasing.deleted, erasing.status);

// List your users.
const page = await vestra.users.list();
console.log(page.data.length);
```

## Python

```python
# Create a user. Do it before their first ask to set their name and time zone. It is safe to repeat.
vestra.users.create("traveller-42", name="Priya Sharma", timezone="Asia/Kolkata")

# Read their spend. Their profile shows what they spent this month, and what is left under their cap.
traveller = vestra.user("traveller-42")
profile = traveller.get()
print(profile.spend_month_usd, profile.caps_remaining.month_usd)

# Set a monthly cap. Then wake their computer, and export everything Vestra holds about them.
traveller.update(monthly_cap_usd=20)
traveller.warm()  # wake their computer before they need it
print(traveller.export())

# Erase a user. It runs as a job: deleted is False and status is deleting until user.deleted says it is done.
erasing = traveller.delete()
print(erasing.deleted, erasing.status)

# List your users.
print(len(vestra.users.list().data))
```

## CLI

```bash
# List your users.
vestra users

# Read their spend. You see what one user spent, and what is left this month.
vestra users traveller-42

# Set a monthly cap. Then export everything Vestra holds about them, and wake their computer.
vestra users traveller-42 --cap 20
vestra users export traveller-42
vestra users warm traveller-42

# Erase a user. It runs as a job, and user.deleted says when it is done.
vestra users delete traveller-42 --yes
```

## HTTP

```bash
# Create a user. Do it before their first ask to set their name and time zone. It is safe to repeat with the
# same user_id.
curl "$VESTRA_BASE_URL/v1/users" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "user_id": "traveller-42", "name": "Priya Sharma", "timezone": "Asia/Kolkata" }'

# Read their spend. Their profile shows what they spent today and this month, against their caps.
curl "$VESTRA_BASE_URL/v1/users/traveller-42" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Set a monthly cap. This one is 20 US dollars.
curl -X PATCH "$VESTRA_BASE_URL/v1/users/traveller-42" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "monthly_cap_usd": 20 }'

# Wake their computer. Do it before they need it.
curl -X POST "$VESTRA_BASE_URL/v1/users/traveller-42/warm" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Open a page in their browser with no model, and keep the page's own data calls. The site must be in their
# deployment's browser.allowed_domains.
curl -X POST "$VESTRA_BASE_URL/v1/users/traveller-42/browser/fetch" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://www.ixigo.com/search/result/flight?from=DEL&to=GOI&date=06112026&adults=2&class=e", "capture": [{ "match": "/flights/v2/search/stream" }] }'

# Erase a user. It runs as a job: the response is 202 with deleted false and status deleting, and then
# user.deleted says it is done.
curl -X DELETE "$VESTRA_BASE_URL/v1/users/traveller-42" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

## MCP

```json
{
  "method": "tools/call",
  "params": {
    "name": "users_get",
    "arguments": { "user": "traveller-42" }
  }
}
```

## Good to know

### User ids

Your id for a user is 1 to 128 characters and starts with a letter or digit. Reading a user never creates one. An unknown id on a read returns 404.

### Erasing a user

`DELETE /v1/users/{id}` returns 202 with `deleted: false` and `status: deleting`. Vestra erases their computer, files and memory in the background, and the `user.deleted` event says when it is done.

### Spending

A user's record shows what they spent today and this month, and how much they can still spend under their caps.

### The key you need

Exporting or erasing a user needs a key with the `admin` scope, or `all`.

### A page's own data, with no model

`POST /v1/users/{id}/browser/fetch` opens one page in a tab of the user's browser, with their sign-ins, and gives back the bodies of the page's own data calls that match `capture`. It can click, type, scroll and wait first (`steps`), and call the deployment's sites from inside the page (`page_fetch`). `keep_open_ms` keeps the tab, so the next fetch sends no `url` and runs there at once. It opens only sites in `browser.allowed_domains`, never a page in `browser.blocked_paths` such as a payment page (403 `page_blocked`), yields to a person with 409 `browser_in_use`, and answers a slow page with 504 `timeout` and what came in `partial`. `POST /v1/users/{id}/warm` with `keep_ms` keeps the computer awake for the next one.

## The routes behind users

- `POST` [/v1/users](https://vestra.ai/developers/reference/api/users/post-v1-users.md): Create one of your users, or return the existing one. Safe to repeat with the same user_id. Key scope: `admin` (or `all`).
- `GET` [/v1/users](https://vestra.ai/developers/reference/api/users/get-v1-users.md): List your users. Key scope: `runtime` (or `all`).
- `GET` [/v1/users/{user_id}](https://vestra.ai/developers/reference/api/users/get-v1-users-user-id.md): One user: status, profile, memory mode, default deployment, and what they spent today and this month against their caps. Key scope: `runtime` (or `all`).
- `PATCH` [/v1/users/{user_id}](https://vestra.ai/developers/reference/api/users/patch-v1-users-user-id.md): Change name, language, time zone, metadata, day or month spend cap, default deployment, or status (active or disabled). Key scope: `admin` (or `all`).
- `DELETE` [/v1/users/{user_id}](https://vestra.ai/developers/reference/api/users/delete-v1-users-user-id.md): Erase the user and everything Bash holds for them: computer, files, memory. Runs as a job; a webhook says when it is done. Key scope: `admin` (or `all`).
- `POST` [/v1/users/{user_id}/export](https://vestra.ai/developers/reference/api/users/post-v1-users-user-id-export.md): Package everything held for the user into one download, for data-rights requests. Key scope: `admin` (or `all`).
- `POST` [/v1/users/{user_id}/warm](https://vestra.ai/developers/reference/api/computer-setup/post-v1-users-user-id-warm.md): Wake the user's computer now (for example when they open your app), so their next task starts without waiting. Answers 200 when it is already up and 202 while it wakes. At most 10 computers wake at once per company (429 warm_limit), and a second call for one user within a minute rides the first. keep_ms keeps it awake that long once it is up, up to two minutes; calling again extends it. Key scope: `runtime` (or `all`).
- `POST` [/v1/users/{user_id}/browser/fetch](https://vestra.ai/developers/reference/api/computer-setup/post-v1-users-user-id-browser-fetch.md): Open one page in a background tab of the user's own browser, with no model, and get back the bodies of the page's own data calls that match capture. Only on sites the user's deployment lists in browser.allowed_domains (403 domain_not_allowed), and never on a page in its browser.blocked_paths, such as a payment page (403 page_blocked). Wakes the computer when it sleeps. Answers as soon as every required capture has its responses, with timings; 409 browser_in_use while a person drives the browser, 409 browser_busy past four at once; 504 timeout carries what came back in partial. frames returns small pictures of the tab at each milestone. A page_fetch step calls one of the deployment's sites from inside the page, as the page's own script would; keep_open_ms keeps the tab for the next fetch, which sends no url (409 no_open_tab when none is kept). Key scope: `runtime` (or `all`).
- `GET` [/v1/users/{user_id}/browser/cookies](https://vestra.ai/developers/reference/api/computer-setup/get-v1-users-user-id-browser-cookies.md): Which cookies of some names the user's browser holds for one site, and until when: names, sites and expiry only, never a value. Only a site on the deployment's browser.allowed_domains (403 domain_not_allowed). Opens no page and acts on nothing, so it never disturbs a person using the browser: read it every few seconds to see a person finish signing in on a page you handed them (front), as the site's session cookie appears or its expiry moves on. Wakes the computer when it sleeps. Key scope: `runtime` (or `all`).

Next: [`usage`](https://vestra.ai/developers/usage.md)
