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

# Vaults

> Let an agent sign in to the sites and services it works on, without passing secrets through the API.

export const Vaults = () => {
  const Label = ({left, top, width, children, strong}) => <div className={`absolute text-center text-[11px] ${strong ? "text-zinc-500 dark:text-zinc-400" : "text-zinc-400 dark:text-zinc-500"}`} style={{
    left,
    top,
    width
  }}>{children}</div>;
  return <div className="not-prose my-6 overflow-x-auto">
      <div className="relative mx-auto" style={{
    width: 720,
    height: 288
  }}>
        <svg className="absolute inset-0 text-zinc-300 dark:text-zinc-600" width="720" height="288" viewBox="0 0 720 288" fill="none" stroke="currentColor" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round">
          <path d="M210 12 V278" strokeDasharray="4 6" />
          <path d="M162 88 H258" /><path d="M253 83 L258 88 L253 93" />
          <path d="M258 112 H162" /><path d="M167 107 L162 112 L167 117" />
          <path d="M428 88 H520" /><path d="M515 83 L520 88 L515 93" />
          <path d="M520 112 H428" /><path d="M433 107 L428 112 L433 117" />
          <path d="M343 154 V190" /><path d="M338 185 L343 190 L348 185" />
        </svg>

        <Label left={12} top={22} width={150}>value-free side</Label>
        <Label left={360} top={22} width={200}>plaintext side</Label>

        <div className="absolute rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950" style={{
    left: 12,
    top: 46,
    width: 150,
    height: 108
  }}>
          <div className="flex items-center gap-2 text-[13.5px] font-medium text-zinc-900 dark:text-zinc-100">
            <span className="text-zinc-500 dark:text-zinc-400">
              <svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M12 8V4H8" /><rect width="16" height="12" x="4" y="8" rx="2" /><path d="M2 14h2" /><path d="M20 14h2" /><path d="M15 13v2" /><path d="M9 13v2" /></svg>
            </span>
            <span>Agent</span>
          </div>
          <div className="mt-2.5">
            <span className="rounded-md bg-zinc-100 px-2 py-0.5 font-mono text-[10.5px] text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300">field: password</span>
          </div>
          <div className="mt-2 text-[10.5px] text-zinc-400 dark:text-zinc-500">no value sent</div>
        </div>

        <div className="absolute rounded-xl border border-transparent bg-zinc-900 p-4 dark:bg-zinc-100" style={{
    left: 258,
    top: 46,
    width: 170,
    height: 108
  }}>
          <div className="flex items-center gap-2 text-[13.5px] font-semibold text-white dark:text-zinc-900">
            <svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></svg>
            <span>Secret broker</span>
          </div>
          <div className="mt-2.5 text-[11.5px] leading-4 text-zinc-400 dark:text-zinc-500">resolves the secret by the page URL</div>
        </div>

        <div className="absolute rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950" style={{
    left: 520,
    top: 46,
    width: 184,
    height: 108
  }}>
          <div className="flex items-center gap-2 text-[13.5px] font-medium text-zinc-900 dark:text-zinc-100">
            <span className="text-zinc-500 dark:text-zinc-400">
              <svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m7.5 4.27 9 5.15" /><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" /><path d="m3.3 7 8.7 5 8.7-5" /><path d="M12 22V12" /></svg>
            </span>
            <span>Your vault</span>
          </div>
          <div className="mt-2.5 text-[11.5px] leading-4 text-zinc-400 dark:text-zinc-500">1Password, org-scoped</div>
        </div>

        <div className="absolute flex items-center gap-3 rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950" style={{
    left: 258,
    top: 190,
    width: 300,
    height: 84
  }}>
          <div className="flex items-center gap-2 text-[13px] font-medium text-zinc-900 dark:text-zinc-100">
            <span className="text-zinc-500 dark:text-zinc-400">
              <svg className="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20" /><path d="M2 12h20" /></svg>
            </span>
            <span className="whitespace-nowrap">Login form</span>
          </div>
          <div className="flex flex-1 flex-col gap-1.5">
            <div className="h-5 rounded-md bg-zinc-100 dark:bg-zinc-800" />
            <div className="flex h-5 items-center rounded-md bg-zinc-100 px-2 font-mono text-[11px] tracking-[0.2em] text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400">••••••••</div>
          </div>
          <div className="rounded-md bg-zinc-900 px-2.5 py-1 text-[11px] font-medium text-white dark:bg-zinc-100 dark:text-zinc-900">Sign in</div>
        </div>

        <Label left={162} top={64} width={96} strong>fill_secret_at</Label>
        <Label left={180} top={116} width={60}>done</Label>
        <Label left={430} top={64} width={88} strong>match by URL</Label>
        <Label left={444} top={116} width={60}>secret</Label>
        <Label left={350} top={158} width={180}>enter_secret — types, then submits</Label>
      </div>
    </div>;
};

<Vaults />

When an agent needs to sign in to a site or service, you don't pass the credentials through the API. Instead you register a vault (a link between your organization and an external secrets provider), and the agent pulls the right secret at the moment it needs it. Secrets never travel through your API requests and are never returned by any endpoint.

Today the only provider is [1Password](https://developer.1password.com/).

## What a vault stores

A vault config records two things:

* `op_vault_id`: which 1Password vault to read credentials from.
* A [service account token](https://www.1password.dev/service-accounts) authorizing access to that vault.

Manage vault configs through the [Vaults](/computer-use-agents/vaults/create) endpoints: create, list, retrieve, update, rotate the token, delete, and health-check.

## Set up a vault

Creating a vault is not enough on its own: nothing uses it until you bind it to a [Browser](/computer-use-agents/browser/configuration) environment.

<Steps titleSize="h3">
  <Step id="create-vault" title="Create a vault">
    Register the 1Password vault and a [service account token](https://www.1password.dev/service-accounts) that grants access to it. The token is validated against the provider, kept write-only, and never returned. See [Create a vault](/computer-use-agents/vaults/create) for the full field list.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://agp.eu.hcompany.ai/api/v2/vaults \
        -H "Authorization: Bearer $HAI_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "name": "prod-1password",
          "provider_config": {"provider": "onepassword", "op_vault_id": "abcd1234efgh5678"},
          "token": "ops_eyJ..."
        }'
      ```

      ```python Python theme={null}
      from hai_agents import Client, OnePasswordConfig

      client = Client()

      vault = client.vaults.create_vault(
          name="prod-1password",
          provider_config=OnePasswordConfig(op_vault_id="abcd1234efgh5678"),
          token="ops_eyJ...",
      )
      print(vault.id)
      ```

      ```typescript TypeScript theme={null}
      import { HaiAgentsClient } from "hai-agents";

      const client = new HaiAgentsClient();

      const vault = await client.vaults.createVault({
        name: "prod-1password",
        providerConfig: { opVaultId: "abcd1234efgh5678" },
        token: "ops_eyJ...",
      });
      console.log(vault.id);
      ```
    </CodeGroup>
  </Step>

  <Step id="bind-vault" title="Bind it to a browser">
    Set the browser's `vault_id` to the vault's `id`, inline in an agent's `environments` list or on a catalog [environment](/computer-use-agents/environments/create). The vault must belong to your organization.

    Vaults are only supported on cloud-hosted browsers (`host: "cloud"`, the default). Secrets are resolved and typed inside H Company infrastructure and never leave it, so a browser running on your own device cannot bind a vault; setting `vault_id` with `host: "user_device"` is rejected.

    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://agp.eu.hcompany.ai/api/v2/environments \
        -H "Authorization: Bearer $HAI_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "id": "signed-in-browser",
          "kind": "web",
          "vault_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
        }'
      ```

      ```python Python theme={null}
      client.environments.create_environment(
          id="signed-in-browser",
          kind="web",
          vault_id="f47ac10b-58cc-4372-a567-0e02b2c3d479",
      )
      ```

      ```typescript TypeScript theme={null}
      await client.environments.createEnvironment({
        id: "signed-in-browser",
        kind: "web",
        vaultId: "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      });
      ```
    </CodeGroup>
  </Step>

  <Step id="run-vault" title="Run with secret access">
    Run a session against an agent using that browser as usual. Whenever a credential in the vault matches the page the agent is on, the session offers it a [`fill_secret_at`](/computer-use-agents/browser/configuration#actions) action to sign in. Leave `vault_id` unset to run without secret access.
  </Step>
</Steps>

## How secrets are matched

Agents never name a 1Password item directly. When an agent fills a credential, the item is selected automatically from the page's URL:

* Domain gating: an item is eligible only if the page's hostname equals, or is a subdomain of, one of the item's stored sites. An agent on `test.hcompany.ai` can use an item stored for `hcompany.ai` (a parent domain), but not one stored for `prod.hcompany.ai` (a sibling).
* Closest host wins: when several eligible items hold the same field, the one whose hostname matches the page most specifically is chosen. An exact host beats a parent-domain match, and a deeper subdomain beats a shallower one.
* Path breaks ties: if two items match the hostname equally well, the one whose stored path best prefixes the page URL wins. Path is only a tiebreaker, never a requirement.

Store one item per site so matching stays unambiguous.
