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

# Create a new sandbox

> Creates a sandbox from a template (defaults to `superserve/base` when
`from_template` is omitted). When the request returns successfully,
the sandbox is ready to use — you can run commands against it
immediately.

New sandboxes use strict preview routing: only ports explicitly
published through `/sandboxes/{sandbox_id}/preview-ports` are reachable.
`preview_access` defaults newly published ports to `public` or `private`;
each publication may override that default independently.




## OpenAPI

````yaml https://raw.githubusercontent.com/superserve-ai/sandbox/refs/heads/main/api/openapi.yaml post /sandboxes
openapi: 3.1.0
info:
  title: Superserve API
  version: 0.1.0
  description: >
    Superserve provides sandbox infrastructure to run AI agents in the cloud.
    Powered by Firecracker MicroVMs.


    ## Sandbox lifecycle


    ```

    active <--> paused --> deleted

    ```


    A sandbox is `active` when running and `paused` after being paused. Resuming

    a paused sandbox returns it to `active`. Deleting releases all resources.


    | Endpoint | What it does |

    |----------|-------------|

    | `POST /sandboxes` | Create a new sandbox (optionally `from_template`) |

    | `PATCH /sandboxes/:id` | Partially update a running sandbox (e.g. network
    rules) |

    | `POST /sandboxes/:id/pause` | Snapshot full state, suspend the VM |

    | `POST /sandboxes/:id/resume` | Restore from snapshot, continue where it
    left off |

    | `DELETE /sandboxes/:id` | Delete sandbox and all resources |


    ## Sandbox environment


    By default sandboxes boot from the curated `superserve/base` template
    (Ubuntu 24.04,

    1 vCPU, 1 GB RAM, 4 GB disk, with Python 3.12, Node.js 22, npm, git, curl,

    and build-essential pre-installed). Callers can override with any template

    name (e.g. `superserve/python-3.11`, `superserve/node-22`) or a team-owned
    template UUID

    via the `from_template` field on `POST /sandboxes`.


    ## Files and commands


    `/files`, `/exec`, and `/exec/stream` run against a single sandbox and use

    its `X-Access-Token` (returned by create, resume, and activate), not the

    team API key. Two host forms reach them:


    - `https://sandbox.superserve.ai/...` with `X-Superserve-Sandbox-Id:
    <sandbox_id>`.

    - `https://boxd-{sandbox_id}.sandbox.superserve.ai/...` — no routing header
    needed.
  contact:
    name: Superserve Team
  license:
    name: Proprietary
servers:
  - url: https://api.superserve.ai
    description: Production
security: []
paths:
  /sandboxes:
    post:
      tags:
        - Sandboxes
      summary: Create a new sandbox
      description: >
        Creates a sandbox from a template (defaults to `superserve/base` when

        `from_template` is omitted). When the request returns successfully,

        the sandbox is ready to use — you can run commands against it

        immediately.


        New sandboxes use strict preview routing: only ports explicitly

        published through `/sandboxes/{sandbox_id}/preview-ports` are reachable.

        `preview_access` defaults newly published ports to `public` or
        `private`;

        each publication may override that default independently.
      operationId: createSandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSandboxRequest'
      responses:
        '201':
          description: Sandbox created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SandboxResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          description: >
            Rate-limited or quota reached. The `error.code` distinguishes:

            - `rate_limited` — request rate exceeded; retry after a short
            backoff.

            - `too_many_sandboxes` — team has reached its active sandbox count
              limit (paused sandboxes do not count; pause or delete a sandbox to
              free a slot, or contact support to raise the cap).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - apiKey: []
components:
  schemas:
    CreateSandboxRequest:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 64
          description: Human-readable name for the sandbox.
        from_template:
          type: string
          description: >
            Boot the sandbox from a template. Accepts either a template UUID or
            a name (e.g. `superserve/base`, `superserve/python-3.11`,
            `superserve/node-22`, or a team-owned name like `my-python-env`).
            The template must be owned by the caller's team OR be a curated
            system template (curated templates use the `superserve/` name
            prefix). The template's vCPU, memory, and disk values are inherited
            by the sandbox — they cannot be overridden per-sandbox because the
            snapshot dictates VM shape. When omitted, defaults to
            `superserve/base`.
        timeout_seconds:
          type: integer
          format: int32
          minimum: 1
          maximum: 604800
          description: >
            Optional auto-pause timeout in seconds. The sandbox is paused once
            its current active session has run this long; each resume starts a
            fresh window. When unset, the sandbox stays active until explicitly
            paused. Also settable later via `PATCH /sandboxes/{sandbox_id}`.
            Maximum 604800 (7 days).
        auto_delete_seconds:
          type: integer
          format: int32
          minimum: 0
          maximum: 2592000
          description: >
            Optional garbage-collection window for paused sandboxes, in seconds.
            Once the sandbox has been continuously paused for this long it is
            deleted automatically. The window arms each time the sandbox pauses
            and is cancelled by resume, so a sandbox in use is never eligible.
            `0` deletes the sandbox as soon as it pauses. When unset, paused
            sandboxes are kept until explicitly deleted. Also settable later via
            `PATCH /sandboxes/{sandbox_id}`. Maximum 2592000 (30 days).
        metadata:
          type: object
          additionalProperties:
            type: string
          description: |
            Flat string-to-string tags attached to the sandbox at creation.
            Useful for grouping, owner labels, environment, run IDs, etc.

            ## Constraints
              - **Strings only.** Values must be strings. There is no type
                coercion: `metadata.count=42` filters for the *string* "42".
              - **At most 64 keys.**
              - Each key may be at most **256 bytes**.
              - Each value may be at most **2048 bytes** (2 KB).
              - The serialized object may be at most **16384 bytes** (16 KB)
                in total.
              - Keys starting with `superserve.` or `_superserve` (case-
                insensitive) are reserved for platform use and rejected.

            Metadata can be updated after creation via `PATCH /sandboxes/:id`.
            Filter sandboxes by metadata via the `metadata.{key}` query
            parameter on `GET /sandboxes`.
          example:
            env: prod
            owner: agent-7
        env_vars:
          type: object
          additionalProperties:
            type: string
          description: |
            Environment variables injected into every process inside the
            sandbox (terminal sessions, exec calls). Merged on top of any
            defaults set by the template's `env` build steps — caller keys
            win on conflict. Survive pause/resume.
          example:
            OPENAI_API_KEY: sk-...
            DEBUG: '1'
            run_id: 7f3c-21
        network:
          $ref: '#/components/schemas/NetworkConfig'
        secrets:
          type: object
          additionalProperties:
            type: string
          description: |
            Bind team-stored credentials to environment variables inside the
            sandbox. Keys are env-var names; values are secret names from
            `POST /secrets`. The agent never sees the real value: it sees a
            proxy token in env, and the in-host enforcement daemon swaps the
            token for the real credential at egress.
          example:
            ANTHROPIC_API_KEY: anthropic-prod
            GITHUB_TOKEN: ghp-readonly
        preview_access:
          type: string
          enum:
            - public
            - private
          default: public
          description: |
            Default access for newly published preview ports. New sandboxes
            default to `public`; `private` ports stay closed with 401 until
            preview-token authentication is introduced. Both modes are strict:
            only explicitly published ports are reachable.
            `legacy_public` is reserved for sandboxes created before explicit
            publication and cannot be selected through the API.
    SandboxResponse:
      description: >-
        Single-sandbox shape — `SandboxListItem` plus `access_token` and bound
        secrets.
      allOf:
        - $ref: '#/components/schemas/SandboxListItem'
        - type: object
          properties:
            access_token:
              type: string
              description: |
                Per-sandbox access token for data-plane operations (file
                upload/download, terminal). Pass as the `X-Access-Token`
                header.
            secrets:
              type: array
              description: >
                Credentials bound to this sandbox. Each entry maps an env-var
                name visible to the agent to the secret name it resolves to.
                `revoked=true` when the underlying secret has been soft-deleted
                (the env var still holds the now-useless proxy token).
              items:
                type: object
                required:
                  - env_key
                  - secret_name
                properties:
                  env_key:
                    type: string
                  secret_name:
                    type: string
                  revoked:
                    type: boolean
                    default: false
    Error:
      type: object
      description: |
        Error envelope. `error.code` is a stable, machine-readable identifier
        (e.g. `bad_request`, `not_found`, `conflict`, `rate_limited`,
        `too_many_builds`, `too_many_templates`, `too_many_sandboxes`,
        `image_pull_failed`, `step_failed`, `snapshot_failed`,
        `start_cmd_failed`, `ready_cmd_failed`, `build_failed`).
        `error.message` is human-readable and may change between releases;
        clients should branch on `code`, not `message`.
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
    NetworkConfig:
      type: object
      description: >
        Egress network rules for a sandbox. `allow_out` accepts CIDRs (e.g.
        `8.8.8.8/32`) and domain names (e.g. `api.openai.com`, `*.github.com`).
        `deny_out` accepts CIDRs only. Private ranges (10/8, 172.16/12,
        192.168/16, 127/8, 169.254/16) are always blocked regardless of rules.
      properties:
        allow_out:
          type: array
          items:
            type: string
          description: CIDRs or domains to allow.
          example:
            - api.openai.com
            - '*.github.com'
            - 8.8.8.8/32
        deny_out:
          type: array
          items:
            type: string
          description: >-
            CIDRs to deny. Use `0.0.0.0/0` to block all traffic not in
            `allow_out`.
          example:
            - 0.0.0.0/0
    SandboxListItem:
      description: Sandbox shape returned by list endpoints.
      type: object
      properties:
        id:
          $ref: '#/components/schemas/PublicSandboxId'
        name:
          type: string
        status:
          type: string
          enum:
            - active
            - paused
            - resuming
          description: >
            Current state of the sandbox. `active` means running; `paused` means
            paused and awaiting resume. `resuming` is a transient state observed
            while the platform restores a paused sandbox (e.g. via auto-resume
            on `/exec`); clients should retry shortly.
        vcpu_count:
          type: integer
        memory_mib:
          type: integer
        snapshot_id:
          type: string
          format: uuid
          description: ID of the latest snapshot (present after a pause).
        created_at:
          type: string
          format: date-time
        timeout_seconds:
          type: integer
          format: int32
          description: >
            Auto-pause timeout in seconds, if configured. Absent when auto-pause
            is disabled.
        auto_delete_seconds:
          type: integer
          format: int32
          description: >
            Garbage-collection window for the paused state, if configured.
            Absent when auto-delete is disabled.
        auto_delete_at:
          type: string
          format: date-time
          description: >
            When the sandbox will be deleted. Present only while the sandbox is
            paused with `auto_delete_seconds` configured. The deadline is armed
            when the sandbox pauses (or when the setting is applied to an
            already-paused sandbox) and cleared on resume.
        network:
          $ref: '#/components/schemas/NetworkConfig'
          description: >
            Current egress allow/deny rules, if any have been configured. Absent
            when the sandbox uses default network settings.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: >
            User-supplied tags attached at creation. Always present — sandboxes
            created without metadata return `{}` rather than being absent.
          example:
            env: prod
            owner: agent-7
        preview_access:
          type: string
          enum:
            - legacy_public
            - public
            - private
          description: |
            Default access for newly published ports. `public` and `private`
            are strict modes; existing published rows keep their own access.
            `legacy_public` may be returned for an older sandbox and preserves
            all-port behavior until updated to a strict mode.
    PublicSandboxId:
      type: string
      pattern: >-
        ^(sb-[a-z0-9]+-)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$
      description: >
        Public sandbox ID: a bare UUID, or the region-tagged form
        `sb-<region>-<uuid>` (e.g. `sb-use-1b4e28ba-…`). Treat as an opaque
        string; the tagged form routes the request to the sandbox's home region.
        Endpoints accept both forms interchangeably.
  responses:
    BadRequest:
      description: Invalid request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Operation conflicts with the resource's current state
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key

````