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

# Use Secrets in a Sandbox

This page shows an end-to-end example of using a Secret in a sandbox: create the Secret, create a sandbox that references it, run code inside the sandbox that authenticates to an external service, and kill the sandbox when done. The sandbox only ever sees an opaque placeholder — the outbound proxy substitutes the real value for requests to hosts on the Secret's allow list.

## Prerequisites

Set the upstream credential before running:

```bash CLI icon="terminal" theme={"system"}
export OPENAI_API_KEY="your-openai-api-key"
```

## End-to-end example

The example creates a Secret, launches a sandbox with `secret_envs`, runs a command inside the sandbox that calls the upstream API using the placeholder, and finally kills the sandbox.

```python Python icon="python" theme={"system"}
import os
import uuid

from novita_sandbox import Novita

secret_name = f"openai-example-{uuid.uuid4().hex[:12]}"
openai_api_key = os.environ["OPENAI_API_KEY"]
novita = Novita()

# 1. Create a team-scoped Secret. The real value is stored encrypted;
#    substitution is only allowed for hosts in the allow list.
novita.secret.create(
    name=secret_name,
    value=openai_api_key,
    hosts=["api.openai.com"],
    description="Sandbox Secrets example",
)

# 2. Create a sandbox and map an env var to the Secret name.
#    The env var holds a placeholder, not the real value.
sandbox = novita.sandbox.create(
    secret_envs={"OPENAI_API_KEY": secret_name},
)

try:
    # 3. Run code inside the sandbox. It reads the placeholder from the env var
    #    and sends it in an HTTPS header; the proxy substitutes the real value
    #    in flight because api.openai.com is on the allow list.
    result = sandbox.commands.run(
        'curl -s https://api.openai.com/v1/models '
        '-H "Authorization: Bearer $OPENAI_API_KEY"'
    )
    print(result.stdout)
finally:
    # 4. Kill the sandbox when done.
    sandbox.kill()
```

```js JavaScript & TypeScript icon="js" theme={"system"}
import 'dotenv/config'
import { randomUUID } from 'crypto'
import { Novita } from 'novita-sandbox'

const secretName = `openai-example-${randomUUID().slice(0, 12)}`
const openaiApiKey = process.env.OPENAI_API_KEY
const novita = new Novita()

// 1. Create a team-scoped Secret. The real value is stored encrypted;
//    substitution is only allowed for hosts in the allow list.
await novita.secret.create({
  name: secretName,
  value: openaiApiKey,
  hosts: ['api.openai.com'],
  description: 'Sandbox Secrets example',
})

// 2. Create a sandbox and map an env var to the Secret name.
//    The env var holds a placeholder, not the real value.
const sandbox = await novita.sandbox.create({
  secretEnvs: { OPENAI_API_KEY: secretName },
})

try {
  // 3. Run code inside the sandbox. It reads the placeholder from the env var
  //    and sends it in an HTTPS header; the proxy substitutes the real value
  //    in flight because api.openai.com is on the allow list.
  const result = await sandbox.commands.run(
    'curl -s https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"'
  )
  console.log(result.stdout)
} finally {
  // 4. Kill the sandbox when done.
  await sandbox.kill()
}
```

> [!NOTE]
>
> The code inside the sandbox only ever reads the placeholder (for example `novita_secret_<random_hex>`). The real key is substituted at the proxy layer and is never present in the sandbox's environment variables, filesystem, or process arguments.

## How each step works

| Step | What happens |
| - | - |
| `novita.secret.create(...)` | Creates a team-scoped Secret and its first immutable version. Returns `SecretBinding` metadata (no real value). The `hosts` allow list controls which hosts the real value may be substituted for. Returns `409 Conflict` if an active Secret with the same name already exists. |
| `Novita.s``andbox.create(secret_envs=...)` | Maps environment variable names to Secret names. The env var is set to a placeholder, not the real value. If any referenced Secret cannot be resolved, sandbox creation fails. |
| `sandbox.commands.run(...)` | Runs a command inside the sandbox. When it makes an HTTPS request to an allow-listed host with the placeholder in a header, the proxy replaces the placeholder with the real value before the request leaves. |
| `sandbox.kill()` | Shuts down and removes the sandbox. The Secret itself is unaffected and can be reused by other sandboxes. |

> [!WARNING]
>
> `secret_envs` differs from regular `envs`: `envs` injects the given value directly, while `secret_envs` interprets the value as a Secret name and injects its placeholder. The same env var name cannot appear in both. Substitution only happens in HTTPS request header values for hosts on the allow list — request bodies, URL query parameters, plain HTTP, and WebSocket content are forwarded as-is.


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