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

# Create or restore session sandbox

> Provisions a Sandbox for the given session. If a per-org base snapshot exists, the sandbox boots from it (skipping the full repo clone, ~75s saved). Otherwise the sandbox boots from the default base snapshot and a background workflow builds an org-specific snapshot for next time. When the session has prior runtime state (a paused or running sandbox under the same `sandboxName`), the call resumes it instead of creating a new one. On success, the session row is updated with the new `sandboxState` and lifecycle is bumped to `active`; the lifecycle workflow is kicked to manage hibernation and expiry from there.



## OpenAPI

````yaml POST /api/sandbox
openapi: 3.1.0
info:
  title: Recoup API - Session Sandboxes
  description: >-
    Per-session sandbox lifecycle for agent runs. These endpoints provision,
    restore, and report status on the Sandbox bound to a single agent session.
    Distinct from the legacy `/api/sandboxes` (plural) account-scoped endpoints
    — these are session-scoped and used by the open-agents-style chat UI to
    drive the "loading sandbox…" state on session entry.
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://api.recoupable.dev
security:
  - ApiKeyAuth: []
  - BearerAuth: []
paths:
  /api/sandbox:
    post:
      summary: Create or restore session sandbox
      description: >-
        Provisions a Sandbox for the given session. If a per-org base snapshot
        exists, the sandbox boots from it (skipping the full repo clone, ~75s
        saved). Otherwise the sandbox boots from the default base snapshot and a
        background workflow builds an org-specific snapshot for next time. When
        the session has prior runtime state (a paused or running sandbox under
        the same `sandboxName`), the call resumes it instead of creating a new
        one. On success, the session row is updated with the new `sandboxState`
        and lifecycle is bumped to `active`; the lifecycle workflow is kicked to
        manage hibernation and expiry from there.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateSandboxRequest'
      responses:
        '200':
          description: Sandbox provisioned and bound to the session.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateSandboxResponse'
        '400':
          description: >-
            Invalid request body — malformed JSON, missing required fields, or
            invalid GitHub repository URL.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — invalid or missing API key / Bearer token.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: >-
            Forbidden — the authenticated account does not own the supplied
            `sessionId`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Not found — no session exists with the given `sessionId`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: Upstream error — the sandbox provider failed to provision a sandbox.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    CreateSandboxRequest:
      type: object
      required:
        - repoUrl
      properties:
        repoUrl:
          type: string
          description: >-
            GitHub repository URL the sandbox should clone (e.g.
            `https://github.com/owner/repo`). Validated against GitHub URL
            rules; private repos require the service GitHub token configured
            server-side.
        sessionId:
          type: string
          description: >-
            Owning session id. Required for the chat UX flow — the sandbox is
            named deterministically from the session id, enabling resume across
            reconnects. When omitted, a one-shot ephemeral sandbox is created
            (legacy).
    CreateSandboxResponse:
      type: object
      required:
        - createdAt
        - timeout
        - currentBranch
        - mode
        - timing
      properties:
        createdAt:
          type: integer
          format: int64
          description: Epoch milliseconds when the sandbox handle was returned.
        timeout:
          type: integer
          format: int64
          description: >-
            Sandbox idle-timeout in milliseconds. The lifecycle workflow uses
            this to schedule hibernation.
        currentBranch:
          type: string
          description: Branch the sandbox checked out.
        mode:
          type: string
          enum:
            - vercel
          description: Sandbox provider. Currently always `vercel`.
        timing:
          type: object
          required:
            - readyMs
          properties:
            readyMs:
              type: integer
              format: int64
              description: >-
                Wall-clock milliseconds from request receipt until the sandbox
                was ready. Useful for tracking cold-start vs warm-resume
                performance.
    Error:
      type: object
      required:
        - status
        - error
      properties:
        status:
          type: string
          enum:
            - error
          description: Always `"error"` for error responses.
        error:
          type: string
          description: Human-readable error message.
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
    BearerAuth:
      type: http
      scheme: bearer

````