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

# Proxy routing with secrets injection

> Inject secrets, headers, and body fields into outbound sandbox requests through the Blaxel proxy so code never sees raw API keys or credentials.

<Note>
  This feature is currently in public preview and is not recommended for production use.
</Note>

The Blaxel proxy intercepts outbound HTTPS requests from the sandbox and injects headers, body fields, and secrets server-side.

## Header injection

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { SandboxInstance } from "@blaxel/core";

  const sandbox = await SandboxInstance.create({
    name: "my-sandbox",
    image: "blaxel/base-image:latest",
    region: "us-was-1",
    network: {
      proxy: {
        routing: [
          {
            destinations: ["api.stripe.com"],
            headers: {
              "Authorization": "Bearer {{SECRET:stripe-key}}",
              "Stripe-Version": "2024-12-18.acacia",
            },
            secrets: {
              "stripe-key": "sk_live_...",
            },
          },
        ],
      },
    },
  });
  ```

  ```python Python theme={null}
  from blaxel.core.sandbox import SandboxInstance

  sandbox = await SandboxInstance.create({
      "name": "my-sandbox",
      "image": "blaxel/base-image:latest",
      "region": "us-was-1",
      "network": {
          "proxy": {
              "routing": [
                  {
                      "destinations": ["api.stripe.com"],
                      "headers": {
                          "Authorization": "Bearer {{SECRET:stripe-key}}",
                          "Stripe-Version": "2024-12-18.acacia",
                      },
                      "secrets": {
                          "stripe-key": "sk_live_...",
                      },
                  },
              ],
          },
      },
  })
  ```
</CodeGroup>

Code inside the sandbox calls `api.stripe.com` normally - the proxy intercepts the request, injects the `Authorization` and `Stripe-Version` headers with the resolved secret, and forwards it. The sandbox never sees the raw API key.

## Body injection (POST requests)

<CodeGroup>
  ```typescript TypeScript theme={null}
  await SandboxInstance.create({
    name: "body-injection",
    network: {
      proxy: {
        routing: [
          {
            destinations: ["api.stripe.com"],
            headers: {
              "Authorization": "Bearer {{SECRET:stripe-key}}",
            },
            body: {
              "api_key": "{{SECRET:stripe-key}}",
            },
            secrets: {
              "stripe-key": "sk_live_...",
            },
          },
        ],
      },
    },
  });
  ```

  ```python Python theme={null}
  await SandboxInstance.create({
      "name": "body-injection",
      "network": {
          "proxy": {
              "routing": [
                  {
                      "destinations": ["api.stripe.com"],
                      "headers": {
                          "Authorization": "Bearer {{SECRET:stripe-key}}",
                      },
                      "body": {
                          "api_key": "{{SECRET:stripe-key}}",
                      },
                      "secrets": {
                          "stripe-key": "sk_live_...",
                      },
                  },
              ],
          },
      },
  })
  ```
</CodeGroup>

The proxy merges body fields into outbound POST/PUT/PATCH JSON payloads. User-sent fields are preserved; injected fields are added alongside them.

## Multiple routing rules

<CodeGroup>
  ```typescript TypeScript theme={null}
  await SandboxInstance.create({
    name: "multi-route",
    network: {
      proxy: {
        routing: [
          {
            destinations: ["api.stripe.com"],
            headers: { "Authorization": "Bearer {{SECRET:stripe-key}}" },
            secrets: { "stripe-key": "sk_live_..." },
          },
          {
            destinations: ["api.openai.com"],
            headers: { "Authorization": "Bearer {{SECRET:openai-key}}" },
            secrets: { "openai-key": "sk-proj-..." },
          },
        ],
        bypass: ["*.s3.amazonaws.com"],
      },
    },
  });
  ```

  ```python Python theme={null}
  await SandboxInstance.create({
      "name": "multi-route",
      "network": {
          "proxy": {
              "routing": [
                  {
                      "destinations": ["api.stripe.com"],
                      "headers": {"Authorization": "Bearer {{SECRET:stripe-key}}"},
                      "secrets": {"stripe-key": "sk_live_..."},
                  },
                  {
                      "destinations": ["api.openai.com"],
                      "headers": {"Authorization": "Bearer {{SECRET:openai-key}}"},
                      "secrets": {"openai-key": "sk-proj-..."},
                  },
              ],
              "bypass": ["*.s3.amazonaws.com"],
          },
      },
  })
  ```
</CodeGroup>

Secrets are scoped per rule — the Stripe key is never injected into OpenAI requests and vice versa.

## Global catch-all rule

<CodeGroup>
  ```typescript TypeScript theme={null}
  await SandboxInstance.create({
    name: "global-auth",
    network: {
      proxy: {
        routing: [
          {
            destinations: ["*"],
            headers: {
              "X-Global-Auth": "Bearer {{SECRET:global-key}}",
            },
            secrets: {
              "global-key": "token-xyz",
            },
          },
        ],
      },
    },
  });
  ```

  ```python Python theme={null}
  await SandboxInstance.create({
      "name": "global-auth",
      "network": {
          "proxy": {
              "routing": [
                  {
                      "destinations": ["*"],
                      "headers": {"X-Global-Auth": "Bearer {{SECRET:global-key}}"},
                      "secrets": {"global-key": "token-xyz"},
                  },
              ],
          },
      },
  })
  ```
</CodeGroup>

The `["*"]` destination matches all proxied traffic.

## Proxy bypass

Domains listed in `bypass` skip the proxy tunnel entirely (direct connection):

<CodeGroup>
  ```typescript TypeScript theme={null}
  await SandboxInstance.create({
    name: "bypass-only",
    network: {
      proxy: {
        bypass: ["*.s3.amazonaws.com", "169.254.169.254"],
      },
    },
  });
  ```

  ```python Python theme={null}
  await SandboxInstance.create({
      "name": "bypass-only",
      "network": {
          "proxy": {
              "bypass": ["*.s3.amazonaws.com", "169.254.169.254"],
          },
      },
  })
  ```
</CodeGroup>

S3 and metadata endpoint traffic goes direct; everything else routes through the proxy.

## Secret interpolation

Secrets are referenced in headers and body values using the `{{SECRET:name}}` syntax:

```text theme={null}
"Authorization": "Bearer {{SECRET:api-token}}"          → "Bearer tok_live_abc123"
"X-Multi":       "{{SECRET:part-a}}-{{SECRET:part-b}}"  → "ALPHA-BETA"
"X-Plain":       "no-secret-here"                        → "no-secret-here" (unchanged)
```

* Multiple `{{SECRET:...}}` placeholders can appear in a single value
* Secrets are resolved server-side by the proxy — the sandbox runtime never sees raw secret values
* Secrets are write-only: the `secrets` field is stripped from API responses
* Secrets are scoped per routing rule: a secret defined on route A cannot be resolved by route B
* User code inside the sandbox can also send `{{SECRET:name}}` in its own request headers or body — the proxy will resolve them if the secret exists on the matching route

## Reading proxy config from an existing sandbox

After creation or retrieval, network config is available as typed model attributes:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { SandboxInstance } from "@blaxel/core";

  const sandbox = await SandboxInstance.get("my-sandbox");
  const network = sandbox.spec.network;

  if (network?.proxy?.routing) {
    for (const route of network.proxy.routing) {
      console.log(route.destinations);
      console.log(route.headers["Authorization"]);
    }
    if (network.proxy.bypass) {
      console.log(network.proxy.bypass);
    }
  }

  if (network?.allowedDomains) {
    console.log(network.allowedDomains);
  }
  ```

  ```python Python theme={null}
  from blaxel.core.sandbox import SandboxInstance
  from blaxel.core.client.types import Unset

  sandbox = await SandboxInstance.get("my-sandbox")
  network = sandbox.spec.network  # SandboxNetwork (or Unset)

  if not isinstance(network, Unset) and not isinstance(network.proxy, Unset):
      for route in network.proxy.routing:
          print(route.destinations)
          print(route.headers["Authorization"])
      if not isinstance(network.proxy.bypass, Unset):
          print(network.proxy.bypass)

  if not isinstance(network, Unset) and not isinstance(network.allowed_domains, Unset):
      print(network.allowed_domains)
  ```
</CodeGroup>
