# Freeze and unfreeze

The freeze mechanism is the Crypto Vault's kill switch. A frozen key or wallet cannot produce signatures until it is unfrozen. You can freeze at any scope: individual [keys](/api-reference#tag/keys), all keys belonging to a venue, individual [wallets](/api-reference#tag/wallets), or an entire [vault](/api-reference#tag/vaults). To create and manage the vault and wallet resources themselves, see [Vaults and wallets](/develop/vaults-wallets).

## Freeze keys

[Freeze keys](/api-reference#tag/keys) to halt all signing for those key IDs or venue immediately.

```
POST /v1/keys/freeze
```

Requires all four authentication headers. The caller's user must have the `freeze_assets` capability granted in the [Administrative Policy](/api-reference#tag/adminpolicies).

At least one of the query parameters (`key_ids` or `venue_id`) is required. The request body must include a `reason`.

**Query parameters:**

| Parameter | Type | Description |
|---|---|---|
| `key_ids` | string | Comma-separated list of key IDs to freeze |
| `venue_id` | string | Venue ID: freezes all keys belonging to this venue |

**Request body:**

```json
{ "reason": "Suspicious activity detected on exchange account" }
```

**Example: freeze two keys by ID**

```bash
curl -s -X POST \
  "$CV_BASE/v1/keys/freeze?key_ids=eth-signer,btc-signer" \
  -H "Authorization: ApiKey $API_KEY_UUID" \
  -H "X-Request-Timestamp: $TS_HEX" \
  -H "X-Request-Nonce: $NONCE_HEX" \
  -H "X-Request-Assertion: $ASSERTION" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Suspicious activity detected on exchange account"}'
```

**Example: freeze all keys at a venue**

```bash
curl -s -X POST \
  "$CV_BASE/v1/keys/freeze?venue_id=binance" \
  -H "Authorization: ApiKey $API_KEY_UUID" \
  -H "X-Request-Timestamp: $TS_HEX" \
  -H "X-Request-Nonce: $NONCE_HEX" \
  -H "X-Request-Assertion: $ASSERTION" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Precautionary freeze while investigating alert"}'
```

This endpoint is asynchronous. If the response is `202`, [poll the request](/api-reference#tag/requests) via `GET /v1/requests/{request_id}` until the status is no longer `"processing"`.

## Unfreeze keys

```
POST /v1/keys/unfreeze
```

Same query parameter options as freeze (`key_ids` or `venue_id`). No request body is required. The caller must have the `unfreeze_assets` capability.

**Example: unfreeze by key IDs**

```bash
curl -s -X POST \
  "$CV_BASE/v1/keys/unfreeze?key_ids=eth-signer,btc-signer" \
  -H "Authorization: ApiKey $API_KEY_UUID" \
  -H "X-Request-Timestamp: $TS_HEX" \
  -H "X-Request-Nonce: $NONCE_HEX" \
  -H "X-Request-Assertion: $ASSERTION" \
  -H "Content-Type: application/json" \
  -d '{}'
```

:::note
The freeze and unfreeze endpoints accept both query parameters and a JSON body. Send an empty JSON object (`{}`) as the body on unfreeze to satisfy the `Content-Type: application/json` requirement.
:::

## Freeze and unfreeze vaults

```
POST /v1/vaults/freeze
POST /v1/vaults/unfreeze
```

Freeze one or more [vaults](/api-reference#tag/vaults) to halt signing across everything they contain. A frozen vault blocks signing with every wallet in it: both wallet signing endpoints (`sign` and `raw-sign`) return `403` until the vault is unfrozen.

**Query parameters:**

| Parameter | Type | Description |
|---|---|---|
| `vault_ids` | string | Comma-separated list of vault IDs to freeze or unfreeze |

The freeze request body must include a `reason`. Unfreeze takes the same query parameter and no request body.

**Example: freeze a vault**

```bash
curl -s -X POST \
  "$CV_BASE/v1/vaults/freeze?vault_ids=my-treasury-vault" \
  -H "Authorization: ApiKey $API_KEY_UUID" \
  -H "X-Request-Timestamp: $TS_HEX" \
  -H "X-Request-Nonce: $NONCE_HEX" \
  -H "X-Request-Assertion: $ASSERTION" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Compromised agent credential"}'
```

This endpoint is asynchronous. If the response is `202`, [poll the request](/api-reference#tag/requests) via `GET /v1/requests/{request_id}` until the status is no longer `"processing"`.

## Freeze and unfreeze wallets

```
POST /v1/vaults/{vault_id}/wallets/freeze
POST /v1/vaults/{vault_id}/wallets/unfreeze
```

Freeze individual [wallets](/api-reference#tag/wallets) inside a vault without freezing the vault itself. A frozen wallet returns `403` from both signing endpoints (`sign` and `raw-sign`) until it is unfrozen.

**Query parameters:**

| Parameter | Type | Description |
|---|---|---|
| `addresses` | string | Comma-separated list of wallet addresses to freeze or unfreeze |

The freeze request body must include a `reason`, exactly as for vaults. Unfreeze takes the same query parameter and no request body.

**Example: freeze a wallet**

```bash
curl -s -X POST \
  "$CV_BASE/v1/vaults/my-treasury-vault/wallets/freeze?addresses=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0" \
  -H "Authorization: ApiKey $API_KEY_UUID" \
  -H "X-Request-Timestamp: $TS_HEX" \
  -H "X-Request-Nonce: $NONCE_HEX" \
  -H "X-Request-Assertion: $ASSERTION" \
  -H "Content-Type: application/json" \
  -d '{"reason": "Wallet flagged by transaction monitoring"}'
```

This endpoint is asynchronous. If the response is `202`, [poll the request](/api-reference#tag/requests) via `GET /v1/requests/{request_id}` until the status is no longer `"processing"`.

## How freezes interact with in-flight signing requests

A freeze takes effect immediately. Any signing request that arrives after the freeze is in place receives a `403` response with `err_type: "forbidden"` and a message indicating the resource is frozen.

Signing requests that were already in progress at the moment of freeze complete normally if they passed policy evaluation before the freeze landed. There is no retroactive cancellation of requests that are mid-flight.

## Checking freeze state

The key object returned by `GET /v1/keys/{key_id}` includes:

```json
{
  "is_frozen": true,
  "freeze_reason": "Precautionary freeze while investigating alert"
}
```

You can also filter the key list to frozen keys only:

```bash
curl -s "$CV_BASE/v1/keys?is_frozen=true" \
  -H "Authorization: ApiKey $API_KEY_UUID"
```

Vault and wallet objects carry the same `is_frozen` and `freeze_reason` fields, and both list endpoints accept the same filter:

```bash
curl -s "$CV_BASE/v1/vaults?is_frozen=true" \
  -H "Authorization: ApiKey $API_KEY_UUID"

curl -s "$CV_BASE/v1/vaults/my-treasury-vault/wallets?is_frozen=true" \
  -H "Authorization: ApiKey $API_KEY_UUID"
```

## Audit events

Every freeze and unfreeze operation produces audit events:

* `key_frozen` when a key freeze completes.
* `key_unfrozen` when a key unfreeze completes.
* `vaults_frozen` and `vaults_unfrozen` for vault operations.
* `wallets_frozen` and `wallets_unfrozen` for wallet operations.

Each event records the actor, the affected resources, the reason (for freezes), and the timestamp. The audit log also accepts `vault_ids` and `wallet_addresses` filters to isolate these events. See [Export the audit log](/develop/audit-export) to query them.

## Required permissions

| Action | Required capability |
|---|---|
| Freeze (keys, wallets, or vaults) | `freeze_assets` |
| Unfreeze (keys, wallets, or vaults) | `unfreeze_assets` |

These capabilities are granted in the Administrative Policy, and each one covers keys, wallets, and entire vaults; they are not scoped to individual vaults. The caller must be in a group whose policy rule allows the action.
