API REFERENCE
Create or restore session sandbox
On this page
/api/sandboxProvisions 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 --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
repoUrlstringrequiredGitHub 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.
sessionIdstringOwning 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
createdAtintegerrequiredEpoch milliseconds when the sandbox handle was returned.
format: int64
timeoutintegerrequiredSandbox idle-timeout in milliseconds. The lifecycle workflow uses this to schedule hibernation.
format: int64
currentBranchstringrequiredBranch the sandbox checked out.
modestring · enumrequiredSandbox provider. Currently always vercel.
Values: "vercel"
timingobjectrequiredProperties for timing
readyMsintegerrequiredWall-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 · enumrequiredAlways "error" for error responses.
Values: "error"
errorstringrequiredHuman-readable error message.
401Unauthorized — invalid or missing API key / Bearer token.+
application/json
statusstring · enumrequiredAlways "error" for error responses.
Values: "error"
errorstringrequiredHuman-readable error message.
403Forbidden — the authenticated account does not own the supplied sessionId.+
application/json
statusstring · enumrequiredAlways "error" for error responses.
Values: "error"
errorstringrequiredHuman-readable error message.
404Not found — no session exists with the given sessionId.+
application/json
statusstring · enumrequiredAlways "error" for error responses.
Values: "error"
errorstringrequiredHuman-readable error message.
502Upstream error — the sandbox provider failed to provision a sandbox.+
application/json
statusstring · enumrequiredAlways "error" for error responses.
Values: "error"
errorstringrequiredHuman-readable error message.
Full specification
Download the OpenAPI file for complete schemas, constraints, and examples.
Download sandbox.jsonView operation source
{
"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"
}
}
}
}
}
}