---
title: "Create a sandbox"
method: POST
path: "/sandboxes"
tags: ["Sandboxes"]
---

# Create a sandbox

`POST /sandboxes`

Provisions a sandbox asynchronously. The response returns immediately with
`status: "starting"`; the sandbox transitions to `ready` (or `failed`) a few
moments later. Poll `GET /sandboxes/{id}` until `status` flips, or watch the
dashboard.

## Request body

- CreateSandboxInput
  - `name` string — Display name. Auto-generated (random animal) if omitted.
  - `template` string — Template name from the available sandbox images (e.g. `node-22`, `python-3.12`). Defaults to the server's configured default.
  - `teamId` string — Create the sandbox under a team you're a member of. Copy the team ID from the team's settings page in the dashboard. Omit for a personal sandbox.
  - `environmentId` string — Project-environment ObjectId to scope the sandbox to.
  - `region` string — Region `id` from `GET /v1/regions`, or `"auto"` to let the server pick one for you. Optional; defaults to `"auto"` when omitted.
  - `specs` SandboxSpecs
    - `cpu` integer — CPU shares in Nomad MHz units.
    - `memory` integer — Memory in MB.
    - `disk` integer — Ephemeral scratch disk in GB. Separate from persistent storage.
  - `autoDestroy` boolean — If true, sandbox auto-destroys after `destroyTimeout`.
  - `destroyTimeout` '30m' | '1h' | '3h' | '6h' | '12h' | '18h' — Required when `autoDestroy=true`. Ignored otherwise.
  - `oneShot` boolean — If true, sandbox auto-destroys when its main process exits.
  - `blockOutbound` boolean — Legacy shorthand for `egress.mode = deny_all`. Prefer `egress` for new integrations. Cannot be combined with `egress` on the same request.
  - `egress` SandboxEgressConfig
    - `mode` 'open' | 'restricted' | 'deny_all', required
    - `allow` string[] — Allowlist entries for `restricted` mode: IPv4 addresses, CIDR ranges, or hostnames. Required (min 1 entry) when updating to `restricted`; optional at create time.
  - `persistent` boolean — Provision a fresh per-sandbox persistent volume for the sandbox's workspace directory.
  - `persistentDiskGB` integer — Required when `persistent=true`. Mutually exclusive with `volumeId`.
  - `volumeId` string — Attach an existing detached volume. Mutually exclusive with `persistent` / `persistentDiskGB`.
  - `fromSnapshot` string — Restore from a snapshot you own; replaces the template image.
  - `snapshotMode` 'manual' | 'automatic'
  - `snapshotFrequency` string — 5-field cron expression (e.g. `0 */2 * * *`). Required when `snapshotMode=automatic`, forbidden otherwise.

## Response `200`

Sandbox provisioning queued

- CreateSandboxEnvelope
  - `message` string, required
  - `data` CreateSandboxResult, required
    - `id` string, required
    - `name` string, required
    - `template` string, required
    - `status` 'starting' | 'ready' | 'pausing' | 'paused' | 'resuming' | 'failed' | 'destroyed', required
    - `created_at` string, date-time, required
    - `expires_at` string, date-time, required

## Other responses

- `400` — Validation error / invalid state transition
- `403` — Plan / spending-limit / permission error
- `404` — Sandbox or related resource not found (also returned when owned by another user)

## Changes

- **2026-06-29** `4a016f074bc0` — 1 info
  - added the new optional request property `egress`
- **2026-05-23** `b236bf76f9a7` — 1 info
  - the request property `region` became optional

[Change history](https://skmtc.dev/brimblehq/apis/brimble-sandbox-api/changes/sandboxes/post.md)

---

[API](https://skmtc.dev/brimblehq/apis/brimble-sandbox-api.md) · [All operations](https://skmtc.dev/brimblehq/apis/brimble-sandbox-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/brimblehq/brimble-sandbox-api/revisions/4a016f074bc0/schema)
