RecoupGet a Free AuditFree Audit

API REFERENCE

Create or restore session sandbox

On this page
POST/api/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.

Authentication

x-api-key in header

BearerAuth bearer

Request

cURL
curl --request POST \
  --url 'https://api.recoupable.dev/api/sandbox' \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
  "repoUrl": "string"
}'

Request body required

application/json

repoUrlstringrequired

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.

sessionIdstring

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

Responses

200Sandbox provisioned and bound to the session.

application/json

createdAtintegerrequired

Epoch milliseconds when the sandbox handle was returned.

format: int64

timeoutintegerrequired

Sandbox idle-timeout in milliseconds. The lifecycle workflow uses this to schedule hibernation.

format: int64

currentBranchstringrequired

Branch the sandbox checked out.

modestring · enumrequired

Sandbox provider. Currently always vercel.

Values: "vercel"

timingobjectrequired
Properties for timing
readyMsintegerrequired

Wall-clock milliseconds from request receipt until the sandbox was ready. Useful for tracking cold-start vs warm-resume performance.

format: int64

400Invalid request body — malformed JSON, missing required fields, or invalid GitHub repository URL.

application/json

statusstring · enumrequired

Always "error" for error responses.

Values: "error"

errorstringrequired

Human-readable error message.

401Unauthorized — invalid or missing API key / Bearer token.

application/json

statusstring · enumrequired

Always "error" for error responses.

Values: "error"

errorstringrequired

Human-readable error message.

403Forbidden — the authenticated account does not own the supplied sessionId.

application/json

statusstring · enumrequired

Always "error" for error responses.

Values: "error"

errorstringrequired

Human-readable error message.

404Not found — no session exists with the given sessionId.

application/json

statusstring · enumrequired

Always "error" for error responses.

Values: "error"

errorstringrequired

Human-readable error message.

502Upstream error — the sandbox provider failed to provision a sandbox.

application/json

statusstring · enumrequired

Always "error" for error responses.

Values: "error"

errorstringrequired

Human-readable error message.

Full specification

Download the OpenAPI file for complete schemas, constraints, and examples.

Download sandbox.json
View operation source
json
{
  "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"
          }
        }
      }
    }
  }
}