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

# Environment variables

> Every environment variable the SDK and the MCP server read, with defaults.

Set the three required variables, and know what each optional one changes.

## Required

```bash theme={null}
export SELF_AGENT_PAY_API_KEY=av_...                               # from the dashboard
export SELF_AGENT_PAY_PROXY_URL=wss://proxy.agentvault.io/v1             # the proxy
export SELF_AGENT_PAY_API_URL=https://api.agentvault.io  # the API
```

The SDK and the MCP server read the same variables, with one exception: the
MCP server also reads `AGENTVAULT_NETWORK_FAMILY_AUTOSELECTION`, a network
setting you rarely need. The checkout playbooks entry point reads two more of
its own. Both are listed under [Reference](#reference).

The fastest way to get the values is the dashboard's framework picker, on
**Overview** or **API keys**. It generates the whole block with your key and
your deployment's URLs filled in.

<Note>
  The values on this page are the hosted service's. On a self-hosted Agent Vault,
  copy the whole block from your dashboard instead: it uses your deployment's
  install, proxy and API URLs. See [Install the SDK](/sdk/install#the-install-url).
</Note>

## Reference

<ParamField path="SELF_AGENT_PAY_API_KEY" type="string" required>
  The agent's API key. Used for the proxy session and for every authenticated API
  call. Override it per call with `listTokens({ apiKey })` and the equivalent
  option on other helpers, and per session with `chromium.launch({ apiKey })`.
  The option wins over the variable.
</ParamField>

<ParamField path="SELF_AGENT_PAY_PROXY_URL" type="string">
  The proxy's WebSocket URL. Override it per session with
  `chromium.launch({ proxyUrl })`. The option wins over the variable, and a
  blank option falls back to it.
  Set it to `wss://proxy.agentvault.io/v1` for the hosted service. Unset, it
  falls back to `ws://localhost:4000/v1`, a local development proxy.
</ParamField>

<ParamField path="SELF_AGENT_PAY_API_URL" type="string">
  The API base URL, which serves the token catalog and the recipe registry.
  If it is unset, the SDK falls back to the backend URL variables that an Agent
  Vault deployment's own build sets, so code running inside a deployment needs
  no value.
</ParamField>

<ParamField path="SELF_AGENT_PAY_TUNNEL" type="string">
  Controls whether the browser's traffic leaves through **this machine's** IP
  address rather than the proxy's cloud IP.

  | Value | Behaviour |
  | - | - |
  | Unset (default) | Use the tunnel when it can be established, otherwise connect directly |
  | `1` | Require the tunnel. The proxy refuses to launch a browser without one |
  | `0` | Never use the tunnel |

  The `tunnel` option on `chromium.launch()` overrides this variable. See
  [Egress and tunnelling](/sdk/tunnel).
</ParamField>

<ParamField path="SELF_AGENT_PAY_REQUEST_TIMEOUT_MS" type="number" default="180000">
  How long an ordinary call may go unanswered before the SDK treats the
  connection as dead and closes the session. A value that is not a positive
  number is ignored, and 180000 applies.

  <Warning>
    **Keep this at 150000 or above.** The proxy answers a stalled call at 120
    seconds with the recoverable `unanswered`. A shorter client deadline closes the
    session before that answer arrives, losing the browser and its cookies. The SDK
    logs a warning when the value is lower.
  </Warning>
</ParamField>

<ParamField path="SELF_AGENT_PAY_ACTION_TIMEOUT_MS" type="number">
  A hard bound, in milliseconds, on each page call. Unset means none. A call
  past it rejects with `action_timeout` and the session stays open, unlike
  `request_timeout`. Fills, typing, `selectOption`, the attested checkout, the
  challenge handoff and `browser.close` are never bound by it. Same as
  `chromium.launch({ actionTimeoutMs })`. See
  [The per-action bound](/sdk/sessions-and-timeouts#the-per-action-bound).
</ParamField>

<ParamField path="SELF_AGENT_PAY_RESUME" type="string">
  On by default: after a network drop the SDK reconnects to the same session,
  and only the call in flight fails, with `connection_resumed`. Set to `0` to
  end the session on any drop. Same as `chromium.launch({ resume: false })`.
</ParamField>

<ParamField path="SELF_AGENT_PAY_RESIDENTIAL_EGRESS" type="string">
  Set to `1` to require residential egress without a tunnel through your
  machine, for a hosted agent. A session that cannot get it is refused with
  `egress_unavailable` and never leaves from the proxy's own address. The exit
  country comes from your account, or is the deployment's fallback country when
  your cards and addresses do not agree on one. See
  [Residential egress country](/sdk/tunnel#residential-egress-country). Same as
  `chromium.launch({ residentialEgress: true })`.
</ParamField>

<ParamField path="SELF_AGENT_PAY_STRICT_APPROVAL" type="string">
  Set to `1` so a total the agent reports below the approval threshold never
  skips the account holder's approval. Same as `chromium.launch({ strictApproval: true })`.
  A checkout whose total cannot be read always asks for approval when a threshold
  is set, with or without this.
</ParamField>

<ParamField path="SELF_AGENT_PAY_VERIFIED_OUTCOMES" type="string">
  On by default: a challenge handoff reports `solved` or `released_unsolved`.
  Set to `0` to receive the older single value `completed` instead, if your code
  cannot handle the new values yet. Same as
  `chromium.launch({ verifiedChallengeOutcomes: false })`.
</ParamField>

<ParamField path="SELF_AGENT_PAY_LIVENESS_PROBE_MS" type="number" default="30000">
  How often the SDK checks the connection is alive during a challenge handoff,
  in milliseconds. Values below 1000 are raised to 1000, and values above 65
  minutes (3900000) are lowered to that.
</ParamField>

<ParamField path="AGENTVAULT_NETWORK_FAMILY_AUTOSELECTION" type="string">
  **MCP server only.** The SDK ignores it. By default the server connects to one
  address per host instead of racing IPv4 against IPv6, which avoids silent
  `fetch failed` errors on networks with a broken IPv6 path. Set to `1` to keep
  Node's default racing behaviour. Any other value, including `0`, keeps the
  default.
</ParamField>

<ParamField path="NODE_ENV" type="string">
  Read only for a warning. When it is `production` and
  `SELF_AGENT_PAY_PROXY_URL` points at `localhost`, the SDK logs a warning. It
  changes nothing else.
</ParamField>

### Checkout playbooks

The `@agentvault/playwright/playbooks` entry point builds fallback tokens from
two variables of its own when you do not pass a catalog. The main SDK and the
MCP server never read them.

<ParamField path="AGENT_USER_ID" type="string">
  Your account's user id, the last part of every token. Unset, the fallback
  tokens are incomplete. Prefer the live catalog from `listTokens()`.
</ParamField>

<ParamField path="CARD_INDEX" type="string" default="1">
  Which card's number and security code tokens the fallback builds.
</ParamField>

## Which deadline applies

`SELF_AGENT_PAY_REQUEST_TIMEOUT_MS` is the default for ordinary calls. Some calls
use their own deadline:

| Call | Deadline |
| - | - |
| `browser.close` | 30 seconds |
| Any card or credential fill | 65 minutes, so the session's full 60-minute lifetime |
| `attestedCheckout`, `requestChallengeHandoff` | 65 minutes, so the session's full lifetime |
| A call with an explicit `timeout`, such as `waitFor` or `goto` | That `timeout` plus 60 seconds, when that is longer, up to 65 minutes |
| A call passed `{ timeout: 0 }` | 65 minutes, so the session's full lifetime |
| Everything else, including `context.close` and `page.close` | `SELF_AGENT_PAY_REQUEST_TIMEOUT_MS` |

No deadline is longer than 65 minutes, so the session's 60-minute hard timeout
always ends a call first.

## Local development

```bash theme={null}
export SELF_AGENT_PAY_PROXY_URL=ws://localhost:4000/v1
export SELF_AGENT_PAY_API_URL=http://localhost:3000
```

Use `http://` for a local server. Keeping `https://` points at a port nothing is
listening on.

Check the proxy is up with `GET /health` on its HTTP origin. It returns
`{"ok":true,...}`.

## Related

* [Install the SDK](/sdk/install)
* [Sessions and timeouts](/sdk/sessions-and-timeouts)
* [Limits and timeouts](/reference/limits)


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