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"
}'Try it
Fill in the fields, send the request from your browser, and read the live response. The curl below updates as you type.
Kept in this browser tab only and cleared when it closes.
curl --request POST \
--url 'https://recoup-api.vercel.app/api/sandbox' \
--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"
}
}
}
}
}
}