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

# Sandbox Lifecycle

Sandboxes instantly launch with the configuration you need. When a sandbox is created, it is always running until you stop it or it times out.
By default, this is based on your team’s default Session Timeout setting which you can change on the Settings page.
You can also configure the timeout per session during sandbox session creation

For example, set a custom session timeout when creating the sandbox:

<CodeGroup>
  ```typescript Node.js theme={null}
  const sandbox = await client.sandboxes.create({
    imageName: "node",
    timeoutMinutes: 30,
  });
  ```

  ```python Python theme={null}
  from hyperbrowser.models import CreateSandboxParams

  sandbox = client.sandboxes.create(
      CreateSandboxParams(
          image_name="python",
          timeout_minutes=30,
      )
  )
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.hyperbrowser.ai/api/sandbox \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "imageName": "node",
      "timeoutMinutes": 30
    }'
  ```
</CodeGroup>

## Getting a Sandbox

Fetch a detailed sandbox handle by ID:

<CodeGroup>
  ```typescript Node.js theme={null}
  const sandbox = await client.sandboxes.get("sandbox-id");

  // {
  //   "id": "sandbox-id",
  //   "teamId": "team-id",
  //   "status": "active",
  //   "endTime": null,
  //   "startTime": 1712749200000,
  //   "createdAt": "2026-04-10T11:59:00.000Z",
  //   "updatedAt": "2026-04-10T12:00:00.000Z",
  //   "region": "us-west",
  //   "sessionUrl": "https://app.hyperbrowser.ai/sandbox/sandbox-id",
  //   "duration": 30,
  //   "proxyBytesUsed": 0,
  //   "cpu": 2,
  //   "memoryMiB": 2048,
  //   "diskMiB": 8192,
  //   "runtime": {
  //     "transport": "regional_proxy",
  //     "host": "runtime-usw2.example.hyperbrowser.ai",
  //     "baseUrl": "https://your-runtime-url"
  //   },
  //   "exposedPorts": [
  //     {
  //       "port": 3000,
  //       "auth": true,
  //       "url": "https://your-runtime-url/p/3000",
  //       "browserUrl": "https://your-runtime-url/_hb/auth?grant=token&next=%2F",
  //       "browserUrlExpiresAt": "2026-04-10T12:10:00.000Z"
  //     }
  //   ],
  //   "token": "sandbox-runtime-token",
  //   "tokenExpiresAt": "2026-04-10T12:00:00.000Z"
  // }
  ```

  ```python Python theme={null}
  sandbox = client.sandboxes.get("sandbox-id")

  # sandbox.to_dict()
  # {
  #   "id": "sandbox-id",
  #   "team_id": "team-id",
  #   "status": "active",
  #   "end_time": None,
  #   "start_time": 1712749200000,
  #   "created_at": "<datetime>",
  #   "updated_at": "<datetime>",
  #   "region": "us-west",
  #   "session_url": "https://app.hyperbrowser.ai/sandbox/sandbox-id",
  #   "duration": 30,
  #   "proxy_bytes_used": 0,
  #   "cpu": 2,
  #   "memory_mib": 2048,
  #   "disk_mib": 8192,
  #   "runtime": {
  #     "transport": "regional_proxy",
  #     "host": "runtime-usw2.example.hyperbrowser.ai",
  #     "base_url": "https://your-runtime-url"
  #   },
  #   "exposed_ports": [
  #     {
  #       "port": 3000,
  #       "auth": True,
  #       "url": "https://your-runtime-url/p/3000",
  #       "browser_url": "https://your-runtime-url/_hb/auth?grant=token&next=%2F",
  #       "browser_url_expires_at": "<datetime>"
  #     }
  #   ],
  #   "token": "sandbox-runtime-token",
  #   "token_expires_at": "<datetime>"
  # }
  ```

  ```bash cURL theme={null}
  curl -X GET https://api.hyperbrowser.ai/api/sandbox/SANDBOX_ID \
    -H "x-api-key: YOUR_API_KEY"

  # {
  #   "id": "sandbox-id",
  #   "teamId": "team-id",
  #   "status": "active",
  #   "endTime": null,
  #   "startTime": 1712749200000,
  #   "createdAt": "2026-04-10T11:59:00.000Z",
  #   "updatedAt": "2026-04-10T12:00:00.000Z",
  #   "region": "us-west",
  #   "sessionUrl": "https://app.hyperbrowser.ai/sandbox/sandbox-id",
  #   "duration": 30,
  #   "proxyBytesUsed": 0,
  #   "vcpus": 2,
  #   "memMiB": 2048,
  #   "diskSizeMiB": 8192,
  #   "runtime": {
  #     "transport": "regional_proxy",
  #     "host": "runtime-usw2.example.hyperbrowser.ai",
  #     "baseUrl": "https://your-runtime-url"
  #   },
  #   "exposedPorts": [
  #     {
  #       "port": 3000,
  #       "auth": true,
  #       "url": "https://your-runtime-url/p/3000",
  #       "browserUrl": "https://your-runtime-url/_hb/auth?grant=token&next=%2F",
  #       "browserUrlExpiresAt": "2026-04-10T12:10:00.000Z"
  #     }
  #   ],
  #   "token": "sandbox-runtime-token",
  #   "tokenExpiresAt": "2026-04-10T12:00:00.000Z"
  # }
  ```
</CodeGroup>

## Listing Sandboxes

List your sandboxes with optional filtering:

<CodeGroup>
  ```typescript Node.js theme={null}
  const response = await client.sandboxes.list({
    status: "active",
    page: 1,
    limit: 20,
  });

  // {
  //   "totalCount": 1,
  //   "sandboxes": [
  //     {
  //       "id": "sandbox-id",
  //       "status": "active",
  //       "region": "us-west"
  //     }
  //   ]
  // }
  ```

  ```python Python theme={null}
  from hyperbrowser.models import SandboxListParams

  response = client.sandboxes.list(
      SandboxListParams(
          status="active",
          page=1,
          limit=20,
      )
  )

  # response.model_dump()
  # {
  #   "total_count": 1,
  #   "sandboxes": [
  #     {
  #       "id": "sandbox-id",
  #       "status": "active",
  #       "region": "us-west"
  #     }
  #   ]
  # }
  ```

  ```bash cURL theme={null}
  curl -X GET "https://api.hyperbrowser.ai/api/sandboxes?status=active&page=1&limit=20" \
    -H "x-api-key: YOUR_API_KEY"
  ```
</CodeGroup>

## Refreshing and Connecting

Connect to an existing sandbox or refresh the runtime token.

<Note>
  The runtime token is given when the sandbox is created. For long running sandboxes, refresh may be needed to extend the token lifetime.
  For a more detailed guide to runtime tokens, see [Sandbox Runtime URLs](/sandboxes/runtime).
</Note>

<CodeGroup>
  ```typescript Node.js theme={null}
  // Refresh an existing handle
  await sandbox.refresh();

  // Reconnect from an ID
  const reattached = await client.sandboxes.connect("sandbox-id");

  // {
  //   "id": "sandbox-id",
  //   "runtime": {
  //     "baseUrl": "https://your-runtime-url"
  //   }
  // }
  ```

  ```python Python theme={null}
  # Refresh an existing handle
  sandbox.refresh()

  # Reconnect from an ID
  reattached = client.sandboxes.connect("sandbox-id")

  # reattached.to_dict()
  # {
  #   "id": "sandbox-id",
  #   "runtime": {
  #     "base_url": "https://your-runtime-url"
  #   }
  # }
  ```
</CodeGroup>

## Stopping a Sandbox

Always stop a sandbox when you are done with it:

<CodeGroup>
  ```typescript Node.js theme={null}
  await sandbox.stop();

  // {
  //   "id": "sandbox-id",
  //   "status": "stopped"
  // }
  ```

  ```python Python theme={null}
  response = sandbox.stop()

  # response.model_dump()
  # {
  #   "success": True
  # }
  ```

  ```bash cURL theme={null}
  curl -X PUT https://api.hyperbrowser.ai/api/sandbox/SANDBOX_ID/stop \
    -H "x-api-key: YOUR_API_KEY"
  ```
</CodeGroup>

<Tip>
  Stopping a sandbox is safe to call more than once.
</Tip>

## Exposing Ports

Expose a port when you need a custom process to be accessible from outside from the sandbox.
This provides a custom runtime URL for that exposed port.

<CodeGroup>
  ```typescript Node.js theme={null}
  const exposure = await sandbox.expose({
    port: 3000,
    auth: true,
  });

  // {
  //   "port": 3000,
  //   "auth": true,
  //   "url": "https://your-runtime-url/p/3000",
  //   "browserUrl": "https://your-runtime-url/_hb/auth?grant=token&next=%2F",
  //   "browserUrlExpiresAt": "2026-04-10T12:00:00Z"
  // }

  // Helper for deriving the URL for an exposed port:
  // sandbox.getExposedUrl(3000)
  ```

  ```python Python theme={null}
  from hyperbrowser.models import SandboxExposeParams

  exposure = sandbox.expose(
      SandboxExposeParams(
          port=3000,
          auth=True,
      )
  )

  # exposure.model_dump(mode="json")
  # {
  #   "port": 3000,
  #   "auth": True,
  #   "url": "https://your-runtime-url/p/3000",
  #   "browser_url": "https://your-runtime-url/_hb/auth?grant=token&next=%2F",
  #   "browser_url_expires_at": "2026-04-10T12:00:00Z"
  # }

  # Helper for deriving the URL for an exposed port:
  # sandbox.get_exposed_url(3000)
  ```

  ```bash cURL theme={null}
  curl -X POST https://api.hyperbrowser.ai/api/sandbox/SANDBOX_ID/expose \
    -H "x-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "port": 3000,
      "auth": true
    }'

  # {
  #   "port": 3000,
  #   "auth": true,
  #   "url": "https://your-runtime-url/p/3000",
  #   "browserUrl": "https://your-runtime-url/_hb/auth?grant=token&next=%2F",
  #   "browserUrlExpiresAt": "2026-04-10T12:00:00Z"
  # }
  ```
</CodeGroup>

If `auth` is enabled, send the sandbox bearer token when calling the exposed URL:

<CodeGroup>
  ```typescript Node.js theme={null}
  const detail = await sandbox.info();
  const response = await fetch(`${exposure.url}/health`, {
    headers: {
      Authorization: `Bearer ${detail.token}`,
    },
  });

  const body = await response.text();

  // {
  //   "status": 200,
  //   "body": "<service response>"
  // }
  ```

  ```python Python theme={null}
  import requests

  detail = sandbox.info()
  response = requests.get(
      f"{exposure.url}/health",
      headers={"Authorization": f"Bearer {detail.token}"},
      timeout=30,
  )
  response.raise_for_status()
  body = response.text

  # {
  #   "status_code": 200,
  #   "body": "<service response>"
  # }
  ```

  ```bash cURL theme={null}
  curl "$EXPOSED_URL" \
    -H "Authorization: Bearer $SANDBOX_TOKEN"
  ```
</CodeGroup>

<Note>
  For a dedicated guide to runtime URLs, exposed service URLs, browser auth
  links, and end-to-end examples, see [Sandbox Runtime URLs](/sandboxes/runtime).
</Note>

<Warning>
  Port `4001` is reserved for the sandbox runtime API url and cannot be exposed.
</Warning>
