> ## 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.

> ## Agent Instructions
> H Platform has four products: the Agents API (managed computer-use agents, base URL https://agp.eu.hcompany.ai/api/v2 or https://agp.hcompany.ai/api/v2 for the US), the Models API (OpenAI-compatible Holo vision-language models at https://api.hcompany.ai/v1), HoloDesktop CLI (Holo on the user's own desktop), and HoloTab (a free no-code Chrome extension that runs Holo in the user's browser, with recordable routines and schedules).
> Authenticate with a bearer API key from the HAI_API_KEY environment variable. SDKs: `pip install hai-agents` (Python, `from hai_agents import Client`) and `npm install hai-agents` (TypeScript, `import { HaiAgentsClient } from "hai-agents"`). CLI: `hai`.
> Agents do work in a browser or on a desktop; describe the task as an imperative instruction. To run a task quickly, prefer the pre-built agent `h/web-surfer-flash`. Read results from the session's `latest_answer` after it reaches a terminal status.
> Sessions are the unit of work; wait for a terminal status (completed, failed, timed_out, interrupted) before reading the answer. Use webhooks or the `changes` long-poll endpoint to follow progress.

# Vaults

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

export const Vaults = () => {
  const stroke = {
    fill: "none",
    stroke: "currentColor",
    strokeWidth: 1.75,
    strokeLinecap: "round",
    strokeLinejoin: "round"
  };
  const S = c => ({
    className: c,
    ...stroke
  });
  const icons = {
    agent: c => <svg viewBox="0 0 24 24" {...S(c)}><path d="M12 8V4H8" /><rect width="16" height="12" x="4" y="8" rx="2" /><path d="M2 14h2M20 14h2M15 13v2M9 13v2" /></svg>,
    lock: c => <svg viewBox="0 0 24 24" {...S(c)}><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></svg>,
    vault: c => <svg viewBox="0 0 24 24" {...S(c)}><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-5M12 22V12" /></svg>,
    globe: c => <svg viewBox="0 0 24 24" {...S(c)}><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>
  };
  const Card = ({icon, title, sub, children, className = ""}) => <div className={className}>
      <div className="flex h-full flex-col rounded-xl border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
        <div className="flex items-center gap-2.5">
          <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">{icon("h-5 w-5")}</span>
          <div>
            <div className="whitespace-nowrap text-base font-semibold leading-6 text-zinc-900 dark:text-zinc-100">{title}</div>
            {sub && <div className="whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400">{sub}</div>}
          </div>
        </div>
        {children}
      </div>
    </div>;
  const Arrow = ({top, bottom, dir = "right"}) => <div className="flex flex-col items-stretch justify-center gap-1 px-3 text-center text-xs leading-4 text-zinc-500 dark:text-zinc-400">
      {top && <span className="whitespace-nowrap">{top}</span>}
      <div className={`${dir === "left" ? "flex flex-row-reverse items-center text-zinc-400 dark:text-zinc-600" : "flex items-center text-zinc-400 dark:text-zinc-600"}`}>
        <span className="h-px flex-1 bg-current" />
        <svg className="-ml-px h-3 w-2 shrink-0" viewBox="0 0 8 12" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={dir === "left" ? {
    transform: "scaleX(-1)",
    marginLeft: 0,
    marginRight: -1
  } : undefined}>
          <path d="M1 1.5 6 6l-5 4.5" />
        </svg>
      </div>
      {bottom && <span className="whitespace-nowrap">{bottom}</span>}
    </div>;
  const Down = ({label}) => <div className="flex items-center gap-3 py-1 pl-5">
      <div className="flex flex-col items-center text-zinc-400 dark:text-zinc-600">
        <span className="h-6 w-px bg-current" />
        <svg className="-mt-px h-2 w-3" viewBox="0 0 12 8" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M1.5 1 6 6l4.5-5" /></svg>
      </div>
      <span className="text-xs text-zinc-500 dark:text-zinc-400">{label}</span>
    </div>;
  const Chip = ({children}) => <span className="whitespace-nowrap rounded-md bg-zinc-100 px-2 py-0.5 font-mono text-xs text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300">{children}</span>;
  const Group = ({label, children, className = ""}) => <div className={className}>
      <div className="flex h-full flex-col rounded-2xl border border-dashed border-zinc-300 p-4 dark:border-zinc-700">
        <div className="mb-4 text-xs font-semibold uppercase tracking-wide text-zinc-500 dark:text-zinc-400">{label}</div>
        {children}
      </div>
    </div>;
  return <div className="not-prose my-8 overflow-x-auto">
      <div className="flex min-w-[720px] items-stretch">
        <Group label="Agent side" className="flex shrink-0 flex-col">
          <Card icon={icons.agent} title="Agent" sub="never sees the value" className="my-auto">
            <div className="mt-4 flex flex-col items-start gap-2 text-sm text-zinc-600 dark:text-zinc-400">
              <Chip>fill_secret_at(field)</Chip>
              <div>Knows the field, not the secret</div>
            </div>
          </Card>
        </Group>

        <div className="flex min-w-[120px] flex-1 flex-col justify-center gap-6">
          <Arrow top="fill_secret_at" />
          <Arrow bottom="done" dir="left" />
        </div>

        <Group label="Secret side" className="shrink-0">
          <div className="flex items-stretch">
            <Card icon={icons.lock} title="Secret broker" sub="resolves by page URL" />
            <div className="flex min-w-[100px] flex-1 flex-col justify-center gap-6">
              <Arrow top="match URL" />
              <Arrow bottom="secret" dir="left" />
            </div>
            <Card icon={icons.vault} title="Your vault" sub="1Password, org-scoped" />
          </div>

          <Down label="enter_secret: types, then submits" />

          <div className="flex items-center gap-4 rounded-xl border border-zinc-200 bg-white p-4 dark:border-zinc-800 dark:bg-zinc-950">
            <span className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-200">{icons.globe("h-5 w-5")}</span>
            <div className="whitespace-nowrap text-base font-semibold text-zinc-900 dark:text-zinc-100">Login form</div>
            <div className="flex flex-1 flex-col gap-1.5">
              <div className="h-6 rounded-md bg-zinc-100 dark:bg-zinc-800" />
              <div className="flex h-6 items-center rounded-md bg-zinc-100 px-2 font-mono text-xs tracking-[0.2em] text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400">••••••••</div>
            </div>
            <div className="rounded-md bg-zinc-900 px-3 py-1.5 text-xs font-medium text-white dark:bg-zinc-100 dark:text-zinc-900">Sign in</div>
          </div>
        </Group>
      </div>
    </div>;
};

A vault links your organization to an external secrets provider so an agent can sign in to sites without credentials passing through the API. The agent pulls the matching secret when it needs it. Secrets never travel through your requests and no endpoint returns them. [1Password](https://developer.1password.com/) is the only supported provider.

<Vaults />

| Field | Required | Description |
| - | - | - |
| `name` | Yes | Label for the vault config. |
| `provider_config.op_vault_id` | Yes | The 1Password vault to read credentials from. |
| `provider_config.provider` | No | Default `onepassword`, the only supported value. |
| `token` | Yes | A 1Password [service account token](https://www.1password.dev/service-accounts) for that vault. Validated against the provider, write-only, never returned. |

## Set up a vault

A vault does nothing until a [browser](/agents-api/browser/configuration) environment binds it with `vault_id`. Create the vault, then bind it inline in an agent's `environments` or on a catalog [environment](/agents-api/environments/create):

<CodeGroup>
  ```bash cURL theme={"system"}
  VAULT_ID=$(curl -sX 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..."
    }' | jq -r .id)

  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\": \"$VAULT_ID\"}"
  ```

  ```python Python theme={"system"}
  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...",
  )
  client.environments.create_environment(id="signed-in-browser", kind="web", vault_id=vault.id)
  ```

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

  const client = new HaiAgentsClient();
  const vault = await client.vaults.createVault({
    name: "prod-1password",
    providerConfig: { opVaultId: "abcd1234efgh5678" },
    token: "ops_eyJ...",
  });
  await client.environments.createEnvironment({ id: "signed-in-browser", kind: "web", vaultId: vault.id });
  ```
</CodeGroup>

Then run sessions as usual with an agent that uses this browser. When a vault credential matches the current page, the agent is offered a [`fill_secret_at`](/agents-api/browser/configuration#actions) action to sign in.

* The vault must belong to your organization.
* Cloud browsers only (`host: "cloud"`, the default). Secrets are resolved and typed inside H's infrastructure and never leave it, so `vault_id` with `host: "user_device"` is rejected.
* Leave `vault_id` unset to run without secret access.
* Manage vaults (list, update, [rotate the token](/agents-api/vaults/rotate-token), delete, [health-check](/agents-api/vaults/health)) from the [Vaults](/agents-api/vaults/create) endpoints.

## How secrets are matched

Agents never name a 1Password item. The page URL picks the item:

| Rule | Behavior | Example (page `test.hcompany.ai`) |
| - | - | - |
| Domain gating | Eligible only if the page hostname equals, or is a subdomain of, a site stored on the item. | `hcompany.ai` item: eligible. `prod.hcompany.ai` item (sibling): not eligible. |
| Closest host wins | Among eligible items with the same field, the most specific hostname match wins. Exact host beats parent domain. Deeper subdomain beats shallower. | `test.hcompany.ai` item beats `hcompany.ai` item. |
| Path breaks ties | Equal hostname matches: the stored path that best prefixes the page URL wins. Path is never required. | Two `hcompany.ai` items on page `test.hcompany.ai/app/login`: path `/app` beats `/`. |

Store one item per site so matching stays unambiguous.

Related: [Two-factor authentication](/agents-api/two-factor-auth) (one-time codes at login), [Browser profiles](/agents-api/browser/profiles) (start signed in from saved cookies).


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