# POST /v1/keys/{key_id}/roll

> Replace a key.

In [Account API](https://vestra.ai/developers/reference/api/account.md): Your company's account: who is calling, its keys, its caps, what it spent and the models it may use.

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

Replace a key. The old one keeps working for a grace period you choose, then stops.

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

## Request

Path:

- `key_id` (`string`, required): The API key's id (`key_...`).

Body, if you send one:

- `grace_seconds` (`integer`): How long the old key keeps working, in seconds, up to 7 days. Default 86400 (a day); 0 stops it at once. Default: `86400`. Limits: 0 to 604800.

## Answers 201

- `object` (`"api_key_roll"`): Always `api_key_roll`.
- `key` (`object`): The new key, with its secret, shown once.
  - `id` (`string`): The key's id. Example: `key_8f2k`.
  - `object` (`"api_key"`): Always `api_key`.
  - `mode` (`"live" | "test"`): `live` or `test`: what the key reaches. A test key sees only test users, test deployments and test money.
  - `name` (`string | null`): The name you gave it; null when it has none.
  - `prefix` (`string`): The start of the secret, to tell keys apart: `vk_live_` or `vk_test_` and a few characters. Example: `vk_test_8f2k`.
  - `last4` (`string`): The last four characters of the secret.
  - `scopes` (`("all" | "runtime" | "setup" | "admin")[]`): What the key may call: `all`, or any of `runtime` (conversations, work, routines, connected apps, files, memory, usage), `setup` (deployments, tests, secrets) and `admin` (users and keys).
  - `status` (`"active" | "expiring" | "expired" | "revoked"`): `active`: works, with no end. `expiring`: works until `expires_at` (a rolled key in its grace period, or one made to expire). `expired` or `revoked`: refused.
  - `created_at` (`string`): When it was made, as an ISO 8601 date and time in UTC.
  - `last_used_at` (`string | null`): When it last made a call; null when it never has.
  - `expires_at` (`string | null`): When it stops working; null when it never does.
  - `revoked_at` (`string | null`): When it was revoked; null while it is not.
  - `secret` (`string`): The whole key. It is shown this once: store it now, as Vestra keeps only its hash. Example: `vk_test_...`.
- `previous` (`object`): The old key: it works until its `expires_at`, then stops.
  - `id` (`string`): The key's id. Example: `key_8f2k`.
  - `object` (`"api_key"`): Always `api_key`.
  - `mode` (`"live" | "test"`): `live` or `test`: what the key reaches. A test key sees only test users, test deployments and test money.
  - `name` (`string | null`): The name you gave it; null when it has none.
  - `prefix` (`string`): The start of the secret, to tell keys apart: `vk_live_` or `vk_test_` and a few characters. Example: `vk_test_8f2k`.
  - `last4` (`string`): The last four characters of the secret.
  - `scopes` (`("all" | "runtime" | "setup" | "admin")[]`): What the key may call: `all`, or any of `runtime` (conversations, work, routines, connected apps, files, memory, usage), `setup` (deployments, tests, secrets) and `admin` (users and keys).
  - `status` (`"active" | "expiring" | "expired" | "revoked"`): `active`: works, with no end. `expiring`: works until `expires_at` (a rolled key in its grace period, or one made to expire). `expired` or `revoked`: refused.
  - `created_at` (`string`): When it was made, as an ISO 8601 date and time in UTC.
  - `last_used_at` (`string | null`): When it last made a call; null when it never has.
  - `expires_at` (`string | null`): When it stops working; null when it never does.
  - `revoked_at` (`string | null`): When it was revoked; null while it is not.

## Code

**TypeScript**

```ts
const rolled = await vestra.keys.roll('key_8sd');
```

**Python**

```python
rolled = vestra.keys.roll("key_8sd")
```

**CLI**

```bash
vestra keys roll key_8sd
```

**HTTP**

```bash
# Check your key. See your company, this key, and whether it is test or live.
curl "$VESTRA_BASE_URL/v1/me" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Create a key for CI. This one can only set things up. Its secret is shown only once.
curl "$VESTRA_BASE_URL/v1/keys" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "ci", "scopes": ["setup"] }'

# Roll a key. You get a new secret, and the old one keeps working for an hour.
curl "$VESTRA_BASE_URL/v1/keys/key_3vd/roll" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "grace_seconds": 3600 }'

# Revoke a key. It stops working at once.
curl -X DELETE "$VESTRA_BASE_URL/v1/keys/key_3vd" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

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