sandpi/ platform

Core concepts

Forks & checkpoints

Reuse a configured workspace or a specific checkpoint.

On this page

Prepare a reusable base

Install dependencies and configure files in a base Environment. Wait until it is idle and checkpoint capture has settled. Keep secrets out of reusable workspace files: RootFS files are copied to the child.

Fork current files

Fork a managed Environment from current files or a checkpoint

POST /v1/environments/{environmentId}/forks

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: environmentIdstring · min length 1YesEnvironment identifier. It must belong to the caller’s account or Project.
header: idempotency-keystring · min length 1; max length 128YesStable key for one logical operation. Retry with the same key and exact request body; a new key can admit new work.

Request example

sh
curl -X POST \
    "https://api.sandpi.ai/v1/environments/$ENVIRONMENT_ID/forks" \
    -H "Authorization: Bearer $SANDPI_API_TOKEN" \
    -H "idempotency-key: $REQUEST_KEY" \
    -H "Content-Type: application/json" \
    -d '{
  "name": "Task workspace"
}'
Request body · required application/json
FieldType and constraintsRequiredDescription
namestring · min length 1; max length 100
Validation pattern.*\S.*
YesHuman-readable name for this resource.
snapshotIdstring · min length 1; max length 200NoSandbox0 checkpoint identifier. Use a returned initial or Run checkpoint when pinning a fork.
Example
Example
{
  "name": "Task workspace"
}

Responses

201 Created.
Response body application/json
FieldType and constraintsRequiredDescription
dataobjectYesRun completion settles the file diff and RootFS checkpoint, then immediately requests a memory pause when no Run, rollback, or checkpoint remains. File and other runtime access uses a one-minute inactivity fallback. Queued Runs continue without an intervening pause. The interactive TUI retains its separate fifteen-minute idle policy. On access after a confirmed memory restoration failure, Sandpi automatically requests a durable cold restart from committed files for a qualified stopped source. Processes restart and memory or uncommitted writes may be lost. Pending or uncertain restores retain their original operation.
data.idstringYeswithin dataResource identifier used to read or manage this resource.
data.namestringYeswithin dataHuman-readable name for this resource.
data.statusstring · values: "ready" | "updating" | "error"Yeswithin dataCurrent resource state; inspect the allowed values and the operation’s lifecycle notes.
data.platformobject · extra fields rejectedYeswithin dataPlatform checkpoint, workspace revision and initialization metadata.
data.platform.initialCheckpointStatusstring · values: "pending" | "ready" | "failed"Yeswithin dataInitialization checkpoint state. Wait for ready before submitting work.
data.platform.initialCheckpointSnapshotIdstringNowithin dataInitial immutable RootFS checkpoint identifier, present after capture succeeds.
data.platform.initialCheckpointErrorstringNowithin dataDiagnostic text for initialization checkpoint failure.
data.platform.workspaceRevisioninteger · ≥ -9007199254740991; ≤ 9007199254740991Yeswithin dataObserved workspace revision used to fence conflicting changes and fork operations.
data.platform.forkedFromobject · extra fields rejectedNowithin dataSource Environment and selected fork boundary; present for forked workspaces.
data.platform.forkedFrom.environmentIdstringYeswithin dataEnvironment identifier. It must belong to the caller’s account or Project.
data.platform.forkedFrom.modestring · values: "current" | "checkpoint"Yeswithin dataWhether the fork copied current workspace files or a selected immutable checkpoint.
data.platform.forkedFrom.snapshotIdstringNowithin dataSandbox0 checkpoint identifier. Use a returned initial or Run checkpoint when pinning a fork.
data.platform.forkedFrom.revisioninteger · ≥ -9007199254740991; ≤ 9007199254740991Yeswithin dataSource Environment Run revision observed when the fork was created.
data.platform.repositoryobject · extra fields rejectedNowithin dataPublic HTTPS Git repository used to initialize the workspace.
data.platform.repository.urlstring · format: uriYeswithin dataPublic HTTPS Git URL used to initialize the workspace.
data.platform.repository.refstringNowithin dataOptional repository branch or tag to clone during initialization.
data.platform.repository.initializedbooleanYeswithin dataWhether repository initialization has finished.
data.labelsobject · max 32 keysYeswithin dataUser-defined labels for exact-match filtering. Up to 32 entries. Keys are 1–64 ASCII letters, digits, dots, underscores, slashes or hyphens, beginning with a letter or digit; constructor and prototype are reserved. Values are case-sensitive strings of up to 256 characters, including empty strings.
data.labels.{key}string · max length 256Noadditional keys—
data.labelsRevisioninteger · ≥ 0; ≤ 2147483647Yeswithin dataIndependent labels revision. Supply the last read revision when replacing labels; a stale revision returns 409.
data.networkPolicyobject · extra fields rejectedYeswithin dataEnvironment-wide outbound policy, enforced by Sandbox0. Domain exceptions allow destinations in block-all mode and deny destinations in allow-all mode. Enabled egress credentials also allow their destinations in block-all mode. This policy does not restrict HTTP methods, paths, or local commands.
data.networkPolicy.modestring · values: "allow-all" | "block-all"Yeswithin dataDefault for outbound traffic not matched by a domain exception or enabled credential destination.
data.networkPolicy.domainExceptionsarray · max 500 itemsYeswithin dataDomains allowed in block-all mode or denied in allow-all mode. Exact names do not automatically include subdomains.
data.networkPolicy.domainExceptions[]string · min length 1; max length 255Yeseach array itemExact domain or wildcard suffix such as *.example.com. URLs, paths, ports and IP literals are not supported. Names are normalized to lowercase and deduplicated.
data.{key}anyNoadditional keys—
Example
Example
{
  "data": {
    "id": "",
    "name": "",
    "status": "ready",
    "platform": {
      "initialCheckpointStatus": "pending",
      "workspaceRevision": -9007199254740991
    },
    "labels": {},
    "labelsRevision": 0,
    "networkPolicy": {
      "mode": "allow-all",
      "domainExceptions": [
        "example"
      ]
    }
  }
}
Error responses
400 Invalid request.

application/json

401 Missing or invalid Platform API token.

application/json

402 Insufficient Platform credit.

application/json

404 Resource not found or outside token scope.

application/json

415 Unsupported request media type.

application/json

503 Platform execution is unavailable.

application/json

default Sandpi error.
Error body application/json

Standard error envelope containing a stable code, diagnostic message and request identity.

FieldType and constraintsRequiredDescription
errorobject · extra fields rejectedYesStructured failure information. Inspect the stable code and retain the request ID for investigation.
error.codestringYeswithin errorStable error code used to distinguish failures programmatically.
error.messagestringYeswithin errorHuman-readable diagnostic text.
error.requestIdstringYeswithin errorRequest identifier for correlating diagnostics and support investigations.
error.detailsanyNowithin errorOptional structured error context. Its shape is specific to the service failure.
error.loginUrlstringNowithin errorAuthentication URL supplied when a browser login is required.
error.registrationOpenbooleanNowithin errorWhether new account registration is enabled for this deployment.
Example
Example
{
  "error": {
    "code": "platform_balance_insufficient",
    "message": "Top up Platform credits before submitting a Run.",
    "requestId": "req_example"
  }
}

The default mode copies the current RootFS, including file edits since the latest Run checkpoint. A Project fork stays in the source Project. Persist the idempotency key and body so an ambiguous response can be retried safely.

Fork a specific checkpoint

Supply snapshotId from an initial or Run checkpoint returned by the API. This pins the selected historical files instead of current edits. The source must be idle with no queued Run, rollback or pending checkpoint. The target still needs its own initialization to complete.

Verify the child

Read the forked Environment. Its platform.forkedFrom records the source, fork mode, optional checkpoint and source Run revision. Wait for its Environment status and initial checkpoint to be ready before submitting work.

Get a managed Environment

GET /v1/environments/{environmentId}

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: environmentIdstring · min length 1YesEnvironment identifier. It must belong to the caller’s account or Project.

Request example

sh
curl \
    "https://api.sandpi.ai/v1/environments/$ENVIRONMENT_ID" \
    -H "Authorization: Bearer $SANDPI_API_TOKEN"

No request body.

Responses

200 Successful response.
Response body application/json
FieldType and constraintsRequiredDescription
dataobjectYesRun completion settles the file diff and RootFS checkpoint, then immediately requests a memory pause when no Run, rollback, or checkpoint remains. File and other runtime access uses a one-minute inactivity fallback. Queued Runs continue without an intervening pause. The interactive TUI retains its separate fifteen-minute idle policy. On access after a confirmed memory restoration failure, Sandpi automatically requests a durable cold restart from committed files for a qualified stopped source. Processes restart and memory or uncommitted writes may be lost. Pending or uncertain restores retain their original operation.
data.idstringYeswithin dataResource identifier used to read or manage this resource.
data.namestringYeswithin dataHuman-readable name for this resource.
data.statusstring · values: "ready" | "updating" | "error"Yeswithin dataCurrent resource state; inspect the allowed values and the operation’s lifecycle notes.
data.platformobject · extra fields rejectedYeswithin dataPlatform checkpoint, workspace revision and initialization metadata.
data.platform.initialCheckpointStatusstring · values: "pending" | "ready" | "failed"Yeswithin dataInitialization checkpoint state. Wait for ready before submitting work.
data.platform.initialCheckpointSnapshotIdstringNowithin dataInitial immutable RootFS checkpoint identifier, present after capture succeeds.
data.platform.initialCheckpointErrorstringNowithin dataDiagnostic text for initialization checkpoint failure.
data.platform.workspaceRevisioninteger · ≥ -9007199254740991; ≤ 9007199254740991Yeswithin dataObserved workspace revision used to fence conflicting changes and fork operations.
data.platform.forkedFromobject · extra fields rejectedNowithin dataSource Environment and selected fork boundary; present for forked workspaces.
data.platform.forkedFrom.environmentIdstringYeswithin dataEnvironment identifier. It must belong to the caller’s account or Project.
data.platform.forkedFrom.modestring · values: "current" | "checkpoint"Yeswithin dataWhether the fork copied current workspace files or a selected immutable checkpoint.
data.platform.forkedFrom.snapshotIdstringNowithin dataSandbox0 checkpoint identifier. Use a returned initial or Run checkpoint when pinning a fork.
data.platform.forkedFrom.revisioninteger · ≥ -9007199254740991; ≤ 9007199254740991Yeswithin dataSource Environment Run revision observed when the fork was created.
data.platform.repositoryobject · extra fields rejectedNowithin dataPublic HTTPS Git repository used to initialize the workspace.
data.platform.repository.urlstring · format: uriYeswithin dataPublic HTTPS Git URL used to initialize the workspace.
data.platform.repository.refstringNowithin dataOptional repository branch or tag to clone during initialization.
data.platform.repository.initializedbooleanYeswithin dataWhether repository initialization has finished.
data.labelsobject · max 32 keysYeswithin dataUser-defined labels for exact-match filtering. Up to 32 entries. Keys are 1–64 ASCII letters, digits, dots, underscores, slashes or hyphens, beginning with a letter or digit; constructor and prototype are reserved. Values are case-sensitive strings of up to 256 characters, including empty strings.
data.labels.{key}string · max length 256Noadditional keys—
data.labelsRevisioninteger · ≥ 0; ≤ 2147483647Yeswithin dataIndependent labels revision. Supply the last read revision when replacing labels; a stale revision returns 409.
data.networkPolicyobject · extra fields rejectedYeswithin dataEnvironment-wide outbound policy, enforced by Sandbox0. Domain exceptions allow destinations in block-all mode and deny destinations in allow-all mode. Enabled egress credentials also allow their destinations in block-all mode. This policy does not restrict HTTP methods, paths, or local commands.
data.networkPolicy.modestring · values: "allow-all" | "block-all"Yeswithin dataDefault for outbound traffic not matched by a domain exception or enabled credential destination.
data.networkPolicy.domainExceptionsarray · max 500 itemsYeswithin dataDomains allowed in block-all mode or denied in allow-all mode. Exact names do not automatically include subdomains.
data.networkPolicy.domainExceptions[]string · min length 1; max length 255Yeseach array itemExact domain or wildcard suffix such as *.example.com. URLs, paths, ports and IP literals are not supported. Names are normalized to lowercase and deduplicated.
data.{key}anyNoadditional keys—
Example
Example
{
  "data": {
    "id": "",
    "name": "",
    "status": "ready",
    "platform": {
      "initialCheckpointStatus": "pending",
      "workspaceRevision": -9007199254740991
    },
    "labels": {},
    "labelsRevision": 0,
    "networkPolicy": {
      "mode": "allow-all",
      "domainExceptions": [
        "example"
      ]
    }
  }
}
Error responses
400 Invalid request.

application/json

401 Missing or invalid Platform API token.

application/json

404 Resource not found or outside token scope.

application/json

default Sandpi error.
Error body application/json

Standard error envelope containing a stable code, diagnostic message and request identity.

FieldType and constraintsRequiredDescription
errorobject · extra fields rejectedYesStructured failure information. Inspect the stable code and retain the request ID for investigation.
error.codestringYeswithin errorStable error code used to distinguish failures programmatically.
error.messagestringYeswithin errorHuman-readable diagnostic text.
error.requestIdstringYeswithin errorRequest identifier for correlating diagnostics and support investigations.
error.detailsanyNowithin errorOptional structured error context. Its shape is specific to the service failure.
error.loginUrlstringNowithin errorAuthentication URL supplied when a browser login is required.
error.registrationOpenbooleanNowithin errorWhether new account registration is enabled for this deployment.
Example
Example
{
  "error": {
    "code": "platform_balance_insufficient",
    "message": "Top up Platform credits before submitting a Run.",
    "requestId": "req_example"
  }
}

What carries over

StateFork behavior
Selected workspace files and agents.mdCopied
Platform Sessions and Run historyFresh and independent
Platform-managed native harness historyIndependent
Usage and billing ledgerIndependent
Egress credential bindings and materialConfigure again
MCP configurationCopied with new IDs and no credentials

Deleting the source does not delete completed forks. Rolling back the source does not alter an independent child. See MCP, egress credentials and retention and deletion.