> ## 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.

# Partially update a running sandbox

> Applies a partial update to a running sandbox. Each top-level field
in the request body is optional; only fields that are present are
applied. Omitted top-level fields are left unchanged. Nested objects
are full replacements when present — to clear a list, send it as an
empty array.

At least one top-level field must be present, otherwise the request
is rejected with `400`. Unknown top-level fields are also rejected
with `400` so typos surface as errors instead of silent no-ops.

## Currently patchable fields

- `network` — replaces the egress allow/deny rules. The sandbox
  must be in the `active` state; patching a paused sandbox
  returns `409`. Rules take effect immediately and are persisted so
  they survive a future pause/resume cycle.
- `metadata` — replaces the sandbox's metadata tags. Can be updated
  regardless of sandbox state (active, paused).
- `auto_delete_seconds` — sets or clears (`null`) the
  garbage-collection window for the paused state. Can be updated
  regardless of sandbox state. When applied to an already-paused
  sandbox, the deletion deadline counts from the moment of this
  request — never retroactively from when the sandbox paused — so
  you always get the full window.
- `timeout_seconds` — sets or clears (`null`) the auto-pause
  timeout. Can be updated regardless of sandbox state; on a paused
  sandbox it applies to the next active session. The timeout is
  evaluated against the current active session, so lowering it
  below already-elapsed time pauses the sandbox promptly.
- `preview_access` — sets the default access mode for ports published
  in the future. Existing per-port modes are unchanged. It also moves
  an older `legacy_public` sandbox to strict routing. `legacy_public`
  cannot be selected.




## OpenAPI

````yaml https://raw.githubusercontent.com/superserve-ai/sandbox/refs/heads/main/api/openapi.yaml patch /sandboxes/{sandbox_id}
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/{sandbox_id}:
    parameters:
      - $ref: '#/components/parameters/SandboxId'
    patch:
      tags:
        - Sandboxes
      summary: Partially update a running sandbox
      description: |
        Applies a partial update to a running sandbox. Each top-level field
        in the request body is optional; only fields that are present are
        applied. Omitted top-level fields are left unchanged. Nested objects
        are full replacements when present — to clear a list, send it as an
        empty array.

        At least one top-level field must be present, otherwise the request
        is rejected with `400`. Unknown top-level fields are also rejected
        with `400` so typos surface as errors instead of silent no-ops.

        ## Currently patchable fields

        - `network` — replaces the egress allow/deny rules. The sandbox
          must be in the `active` state; patching a paused sandbox
          returns `409`. Rules take effect immediately and are persisted so
          they survive a future pause/resume cycle.
        - `metadata` — replaces the sandbox's metadata tags. Can be updated
          regardless of sandbox state (active, paused).
        - `auto_delete_seconds` — sets or clears (`null`) the
          garbage-collection window for the paused state. Can be updated
          regardless of sandbox state. When applied to an already-paused
          sandbox, the deletion deadline counts from the moment of this
          request — never retroactively from when the sandbox paused — so
          you always get the full window.
        - `timeout_seconds` — sets or clears (`null`) the auto-pause
          timeout. Can be updated regardless of sandbox state; on a paused
          sandbox it applies to the next active session. The timeout is
          evaluated against the current active session, so lowering it
          below already-elapsed time pauses the sandbox promptly.
        - `preview_access` — sets the default access mode for ports published
          in the future. Existing per-port modes are unchanged. It also moves
          an older `legacy_public` sandbox to strict routing. `legacy_public`
          cannot be selected.
      operationId: patchSandbox
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SandboxPatch'
      responses:
        '204':
          description: Patch applied
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '500':
          $ref: '#/components/responses/InternalError'
      security:
        - apiKey: []
components:
  parameters:
    SandboxId:
      name: sandbox_id
      in: path
      required: true
      schema:
        $ref: '#/components/schemas/PublicSandboxId'
      description: The unique identifier of the sandbox.
  schemas:
    SandboxPatch:
      type: object
      description: |
        Partial update body for `PATCH /sandboxes/{sandbox_id}`. Each
        top-level field is optional; only fields that are present are
        applied. Omitted fields are left unchanged. Nested objects are
        full replacements when present — to clear a list, send it as an
        empty array.

        At least one top-level field must be set, otherwise the request
        is rejected with `400`. Unknown fields are also rejected with
        `400`.
      properties:
        network:
          allOf:
            - $ref: '#/components/schemas/NetworkConfig'
          description: |
            Replace the sandbox's egress rules. The sandbox must be in
            the `active` state. The provided `allow_out` and `deny_out`
            lists fully replace whatever was previously configured.
        metadata:
          type: object
          additionalProperties:
            type: string
          description: |
            Replace the sandbox's metadata tags. Fully replaces the existing
            metadata — omitted keys are removed. Can be patched regardless of
            sandbox state. Same validation limits as on create (64 keys,
            256-byte keys, 2 KB values, 16 KB total).
        auto_delete_seconds:
          type: integer
          format: int32
          nullable: true
          minimum: 0
          maximum: 2592000
          description: |
            Set or clear the garbage-collection window for the paused state.
            Once the sandbox has been continuously paused for this many
            seconds it is deleted automatically. `0` deletes as soon as the
            sandbox pauses; `null` disables auto-delete. On an already-paused
            sandbox the deadline counts from this request, so the sandbox
            gets the full window. Maximum 2592000 (30 days).
        timeout_seconds:
          type: integer
          format: int32
          nullable: true
          minimum: 1
          maximum: 604800
          description: |
            Set or clear the auto-pause timeout. Same semantics as on
            create; `null` disables auto-pause. Evaluated against the
            current active session, so lowering it below already-elapsed
            time pauses the sandbox promptly. Maximum 604800 (7 days).
        preview_access:
          type: string
          enum:
            - public
            - private
          description: |
            Set the default access for newly published ports and move a legacy
            sandbox to strict routing. Existing per-port modes are unchanged.
            `legacy_public` cannot be selected through the API.
      example:
        metadata:
          env: prod
          owner: agent-7
    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.
    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
    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
  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'
    NotFound:
      description: Resource not found
      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

````