> ## Documentation Index
> Fetch the complete documentation index at: https://hyperbrowser.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Vaults

> Group secrets under one name, or link a 1Password vault, and pass them to sandboxes and browser sessions together.

A vault maps environment variable names to [secrets](/docs/sandboxes/secrets), such as `DB_URL` to `app-db-url`. You pass the vault by name to a sandbox to set all its variables at once, or attach it to a browser session to [fill a login](/docs/sessions/credentials) by its entry names. A vault holds no values itself: each entry points at a stored secret, or, in a [1Password vault](#1password-vaults), at a field in your 1Password account.

<Note>
  Vaults are part of [Secrets](/docs/sandboxes/secrets), which are enabled for teams on request, and use the same scopes: `secrets.manage` to create and change vaults, `secrets.read` to read them, and `secrets.use` to pass them to sandboxes and sessions.
</Note>

## Create a vault

Each entry names a secret, and optionally a version to pin. Without a version, the entry follows the secret's latest version.

<CodeGroup>
  ```typescript Node.js theme={null}
  import { Hyperbrowser } from "@hyperbrowser/sdk";

  const client = new Hyperbrowser({ apiKey: process.env.HYPERBROWSER_API_KEY });

  await client.vaults.create({
    name: "app-env",
    description: "Production app settings",
    entries: {
      DB_URL: { name: "app-db-url" },
      API_KEY: { name: "provider-key", version: 2 },
    },
  });
  ```

  ```python Python theme={null}
  import os
  from hyperbrowser import Hyperbrowser

  client = Hyperbrowser(api_key=os.environ["HYPERBROWSER_API_KEY"])

  client.vaults.create({
      "name": "app-env",
      "description": "Production app settings",
      "entries": {
          "DB_URL": {"name": "app-db-url"},
          "API_KEY": {"name": "provider-key", "version": 2},
      },
  })
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.hyperbrowser.ai/api/vaults \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "app-env",
      "description": "Production app settings",
      "entries": {
        "DB_URL": {"name": "app-db-url"},
        "API_KEY": {"name": "provider-key", "version": 2}
      }
    }'
  ```

  ```bash CLI theme={null}
  hx vaults create app-env --description "Production app settings" \
    --entry DB_URL=app-db-url --entry API_KEY=provider-key@2
  ```
</CodeGroup>

Entry names are environment variable names: letters, digits and `_`, not starting with a digit. Any secret type except `op_token` can be an entry.

## Use a vault

Pass `vault` when you run a command or create a sandbox. The vault's variables come first, and any `secrets` you also pass are merged over them:

<CodeGroup>
  ```typescript Node.js theme={null}
  const sandbox = await client.sandboxes.create({ imageName: "node" });
  const result = await sandbox.exec("node app.js", { vault: "app-env" });
  ```

  ```python Python theme={null}
  sandbox = client.sandboxes.create({"image_name": "node"})
  result = sandbox.exec("node app.js", vault="app-env")
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.hyperbrowser.ai/api/sandbox/SANDBOX_ID/processes \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"command": "node app.js", "vault": "app-env"}'
  ```

  ```bash CLI theme={null}
  hx vm exec <sandbox-id> --vault app-env -- node app.js
  ```
</CodeGroup>

See [Pass a vault](/docs/sandboxes/secrets#pass-a-vault) for the merge rules and what the response reports. To fill a login in a browser session, attach the vault with `credentials: [{ vault: "github-login" }]` and fill by entry name; see [Credential fill](/docs/sessions/credentials).

## Change a vault

An update replaces only the entries you pass; `null` removes one. Vault methods take a name or ID.

<CodeGroup>
  ```typescript Node.js theme={null}
  await client.vaults.update("app-env", {
    entries: {
      API_KEY: { name: "provider-key" }, // follow the latest version again
      DB_URL: null,                      // remove the variable
    },
  });

  const { vaults } = await client.vaults.list();
  const vault = await client.vaults.get("app-env");
  await client.vaults.delete("app-env");
  ```

  ```python Python theme={null}
  client.vaults.update("app-env", {
      "entries": {
          "API_KEY": {"name": "provider-key"},  # follow the latest version again
          "DB_URL": None,                       # remove the variable
      },
  })

  vaults = client.vaults.list().vaults
  vault = client.vaults.get("app-env")
  client.vaults.delete("app-env")
  ```

  ```bash cURL theme={null}
  curl -X PATCH https://api.hyperbrowser.ai/api/vaults/VAULT_ID \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"entries": {"API_KEY": {"name": "provider-key"}, "DB_URL": null}}'
  ```

  ```bash CLI theme={null}
  hx vaults update app-env --entry API_KEY=provider-key --remove DB_URL
  hx vaults ls
  hx vaults get app-env
  hx vaults delete app-env
  ```
</CodeGroup>

The API addresses vaults by ID; find one by name with `GET /api/vaults?search=app-env`. A vault returns its entries with each secret's `name`, `secretId` and pinned `version` (`null` follows the latest). Changing or deleting a vault doesn't affect processes that already started. A browser session keeps the secrets the vault pointed at when the session was created, so an entry changed since then can't be filled in it.

## 1Password vaults

A 1Password vault reads its values from your 1Password account each time a sandbox process starts, so you can keep using 1Password as the source of truth. Hyperbrowser signs in with a [1Password service account](https://developer.1password.com/docs/service-accounts/) token that you store as a secret of type `op_token`. The token is only used to read the vault's fields, and never reaches a process or page.

First store the token, then create the vault with its `source`: the token secret and the 1Password vault's name or ID. Each entry names an item, an optional section, and a field.

<CodeGroup>
  ```typescript Node.js theme={null}
  await client.secrets.create({
    name: "op-token",
    type: "op_token",
    value: process.env.OP_SERVICE_ACCOUNT_TOKEN!,
  });

  await client.vaults.create({
    name: "prod-env",
    source: { type: "1password", tokenSecret: "op-token", vault: "Engineering" },
    entries: {
      DB_PASSWORD: { item: "Postgres", section: "prod", field: "password" },
      DEPLOY_OTP: { item: "Deploy bot", field: "one-time password?attribute=otp" },
    },
  });
  ```

  ```python Python theme={null}
  client.secrets.create({
      "name": "op-token",
      "type": "op_token",
      "value": os.environ["OP_SERVICE_ACCOUNT_TOKEN"],
  })

  client.vaults.create({
      "name": "prod-env",
      "source": {"type": "1password", "token_secret": "op-token", "vault": "Engineering"},
      "entries": {
          "DB_PASSWORD": {"item": "Postgres", "section": "prod", "field": "password"},
          "DEPLOY_OTP": {"item": "Deploy bot", "field": "one-time password?attribute=otp"},
      },
  })
  ```

  ```bash CLI theme={null}
  printf '%s' "$OP_SERVICE_ACCOUNT_TOKEN" | hx secrets create op-token --type op_token --stdin

  hx vaults create prod-env --1password-token op-token --1password-vault Engineering \
    --entry DB_PASSWORD=Postgres/prod/password \
    --entry 'DEPLOY_OTP=Deploy bot/one-time password?attribute=otp'
  ```
</CodeGroup>

Each entry becomes a [secret reference](https://developer.1password.com/docs/cli/secret-reference-syntax/), `op://<vault>/<item>/[<section>/]<field>`, which the vault returns as `reference`. Items, sections and fields are names or IDs without `/` or `?`; use the ID for a name that contains one. A field may end with a query: `?attribute=otp` reads the current one-time password of a TOTP field instead of its seed. A reference can be at most 512 bytes.

Entries are only checked against 1Password when a process starts. To rotate the token, add a version to the `op_token` secret. To point the vault at a different token or 1Password vault, update its source:

<CodeGroup>
  ```typescript Node.js theme={null}
  await client.vaults.update("prod-env", { source: { tokenSecret: "op-token-2025" } });
  ```

  ```python Python theme={null}
  client.vaults.update("prod-env", {"source": {"token_secret": "op-token-2025"}})
  ```

  ```bash cURL theme={null}
  curl -X PATCH https://api.hyperbrowser.ai/api/vaults/VAULT_ID \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"source": {"tokenSecret": "op-token-2025"}}'
  ```

  ```bash CLI theme={null}
  hx vaults update prod-env --1password-token op-token-2025
  ```
</CodeGroup>

A vault's source type is fixed when you create it. 1Password vaults work for sandbox processes and startup commands, not for browser sessions.

### 1Password errors

When 1Password can't provide a value, nothing starts and you get one of these:

| Code | Status | Meaning |
| - | - | - |
| `SECRET_ONEPASSWORD_REFERENCE_FAILED` | 422 | 1Password couldn't resolve an entry; `details` names the variables. Fix the entries. |
| `SECRET_ONEPASSWORD_AUTH_FAILED` | 422 | 1Password rejected the token. Add a new version of the `op_token` secret. |
| `SECRET_ONEPASSWORD_RATE_LIMITED` | 429 | 1Password is rate limiting the service account. Retryable. |
| `SECRET_ONEPASSWORD_FAILED` | 502, 503 | 1Password couldn't be reached. Retryable. |
| `SECRET_ONEPASSWORD_UNSUPPORTED` | 501 | The sandbox's host doesn't support 1Password vaults yet. Retryable on sandbox create only. |

## Limits

* 100 vaults per team and 32 entries per vault.
* Names are 1–128 letters, digits, `_` or `-`, starting with a letter or digit, and unique within your team.

## Errors

| Code | Status | Meaning |
| - | - | - |
| `VAULT_NOT_FOUND` | 404 | No vault with that name or ID. |
| `VAULT_NAME_TAKEN` | 409 | A vault with this name exists. |
| `VAULT_LIMIT_REACHED`, `VAULT_ENTRY_LIMIT_REACHED` | 409 | Your team has 100 vaults, or the vault would have more than 32 entries. |
| `VAULT_ENTRY_INVALID` | 400 | An entry doesn't fit the vault, such as an item field in a stored vault. The message starts with the variable name. |
| `VAULT_SOURCE_INVALID` | 400 | Source settings on a stored vault, or a 1Password vault used in a browser session. |
| `SECRET_NOT_FOUND`, `SECRET_VERSION_NOT_FOUND` | 404 | An entry or the token names a missing secret or version. |
| `SECRET_TYPE_MISMATCH` | 409 | An `op_token` secret as an entry, or a token secret that isn't an `op_token`. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.