sandpi/ platform

Operate

Billing & budgets

Understand Sandbox runtime credits, budgets and reservations.

On this page

Sandbox runtime

Sandpi Platform bills actual Sandbox runtime by the second. The fixed 2 vCPU / 4 GiB Sandbox rate is equivalent to $0.10/hour; the hourly figure is a price reference, not whole-hour billing. All Sessions in an Environment share that Sandbox and its runtime charge. Running and provisioning time is charged from Sandbox0 usage windows. Paused time is free. Files, browser access, initialization, scheduled work and other operations can keep or make the Sandbox active.

Model requests go directly from your Sandbox through the Harness to your API or gateway. Your provider bills model tokens, web search and other provider tools. Sandpi does not resell model Tokens or add a model service fee.

Credits and budgets

Top-ups have no fee: $100 paid adds $100 of credit. No personal subscription is required. An Environment needs at least one minute of runtime credit ($0.001666667) to start or resume. Live runtime observations conservatively reserve outstanding usage at the highest applicable historical rate plus one minute at the current rate; reservations reduce available credit and count toward Team Sandbox budgets. Confirmed Sandbox0 usage windows settle actual charges once and release consumed reservations.

When credit or a Team Sandbox budget is exhausted, active Runs are stopped and the Sandbox is paused with memory preserved. Monthly Team Sandbox budgets use UTC calendar months. Checkpoints and other runtime work are also chargeable. Rollback and deletion retain charges and accounting facts.

For a workload with its own runtime budget, create a dedicated Team, set its monthly Sandbox budget in the console, and use a Project-scoped Platform key for its workloads. Set a Session execution allowance when a task needs its own time limit. There is no separate per-Environment spending-cap setting. Reservations and periodic checks enforce runtime admission and stopping, but metering and pause completion are asynchronous; final charges can slightly exceed a budget. A Team Sandbox budget is not a guaranteed exact-dollar cap.

Model spending is a separate boundary: set a dedicated key's spending limit at your model provider or gateway. Sandpi cannot enforce that provider's bill through its runtime wallet or Team Sandbox budget. Your own Controller can stop a Run and decide whether its evidence meets your acceptance criteria.

Team Sandbox budgets

A Team budget limits actual Environment runtime charges across all its Projects over UTC calendar months. Promotional runtime counts toward the limit. Each Environment has one funding reservation and one settlement stream regardless of its Session count. Project model budgets remain historical configuration and no longer gate Sandbox runtime.

Read Team Sandbox budget

GET /v1/teams/{teamId}/sandbox-budget

Team budgets aggregate Environment runtime across Projects over UTC calendar months. Team writes require a personal key and Team admin access; Project keys can read their Team budget.

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: teamIdstring · min length 1Yesteam identifier.

Request example

sh
curl \
    "https://api.sandpi.ai/v1/teams/$TEAM_ID/sandbox-budget" \
    -H "Authorization: Bearer $SANDPI_API_TOKEN"

No request body.

Responses

200 Sandbox budget state.
Response body application/json
FieldType and constraintsRequiredDescription
dataobject · extra fields rejectedYesTeam Sandbox budget. Each Environment charge and hold is counted once.
data.limitUsdstring · nullableYeswithin dataConfigured USD limit, or null for unlimited.
data.revisioninteger · ≥ 0Yeswithin dataRevision for optimistic budget updates.
data.spentUsdstringYeswithin dataPosted Environment runtime charges across all Team Projects in this UTC month.
data.reservedUsdstringYeswithin dataOutstanding Environment runtime reservations; includes promotional funding.
data.periodStartsAtstring · format: date-timeYeswithin dataUTC calendar month start.
data.periodEndsAtstring · format: date-timeYeswithin dataUTC calendar month end.
Example
Example
{
  "data": {
    "limitUsd": "",
    "revision": 0,
    "spentUsd": "",
    "reservedUsd": "",
    "periodStartsAt": "2026-01-01T00:00:00Z",
    "periodEndsAt": "2026-01-01T00:00:00Z"
  }
}
Error responses
400 Invalid request.

application/json

401 Authentication required.

application/json

403 Budget management or resource scope denied.

application/json

404 Resource not found.

application/json

409 Budget revision changed.

application/json

503 Runtime pricing 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"
  }
}

Replace Team Sandbox budget

PUT /v1/teams/{teamId}/sandbox-budget

Team budgets aggregate Environment runtime across Projects over UTC calendar months. Team writes require a personal key and Team admin access; Project keys can read their Team budget.

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: teamIdstring · min length 1Yesteam identifier.

Request example

sh
curl -X PUT \
    "https://api.sandpi.ai/v1/teams/$TEAM_ID/sandbox-budget" \
    -H "Authorization: Bearer $SANDPI_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
  "limitUsd": 1,
  "revision": 0
}'
Request body · required application/json

Replace a Sandbox budget without changing Environment billing.

FieldType and constraintsRequiredDescription
limitUsdnumber · nullable; ≥ 0; ≤ 100000YesSandbox budget in USD. Zero blocks execution; null removes the limit.
revisioninteger · ≥ 0YesCurrent budget revision. A stale update returns 409.
Example
Example
{
  "limitUsd": 1,
  "revision": 0
}

Responses

200 Sandbox budget state.
Response body application/json
FieldType and constraintsRequiredDescription
dataobject · extra fields rejectedYesTeam Sandbox budget. Each Environment charge and hold is counted once.
data.limitUsdstring · nullableYeswithin dataConfigured USD limit, or null for unlimited.
data.revisioninteger · ≥ 0Yeswithin dataRevision for optimistic budget updates.
data.spentUsdstringYeswithin dataPosted Environment runtime charges across all Team Projects in this UTC month.
data.reservedUsdstringYeswithin dataOutstanding Environment runtime reservations; includes promotional funding.
data.periodStartsAtstring · format: date-timeYeswithin dataUTC calendar month start.
data.periodEndsAtstring · format: date-timeYeswithin dataUTC calendar month end.
Example
Example
{
  "data": {
    "limitUsd": "",
    "revision": 0,
    "spentUsd": "",
    "reservedUsd": "",
    "periodStartsAt": "2026-01-01T00:00:00Z",
    "periodEndsAt": "2026-01-01T00:00:00Z"
  }
}
Error responses
400 Invalid request.

application/json

401 Authentication required.

application/json

403 Budget management or resource scope denied.

application/json

404 Resource not found.

application/json

409 Budget revision changed.

application/json

503 Runtime pricing 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"
  }
}

A Team owner or admin can manage its budget in the Console. Public writes require a personal Team admin key; a Project key can read its own Team budget but cannot raise its limit. Supply the current revision to update; stale writes return a conflict. Zero blocks execution; null removes the limit. Budget reads and updates do not wake a Sandbox.

Session execution budget

A Session budget is a lifetime execution allowance expressed in USD. At $0.10/hour, $0.01 permits six minutes of cumulative Harness execution. Runs share the allowance; queue time, Session idle time and Environment initialization/checkpoints are excluded. Those other operations still count toward the Team's actual Environment bill. Session budget consumption creates no wallet charge or additional Environment funding reservation.

Read Session Sandbox budget

GET /v1/environments/{environmentId}/sessions/{sessionId}/sandbox-budget

Session budgets limit cumulative Harness execution time using versioned Sandbox prices. No additional Sandbox charge or wallet reservation is created. Budget changes do not resume a Sandbox. Changing a running budget is enforced by the worker; the guest also carries its initial execution deadline.

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: environmentIdstring · min length 1Yesenvironment identifier.
path: sessionIdstring · min length 1Yessession identifier.

Request example

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

No request body.

Responses

200 Sandbox budget state.
Response body application/json
FieldType and constraintsRequiredDescription
dataobject · extra fields rejectedYesSession lifetime execution budget. Resume and rollback do not reset usage. Environment settlement remains unchanged.
data.limitUsdstring · nullableYeswithin dataConfigured USD limit, or null for unlimited.
data.revisioninteger · ≥ 0Yeswithin dataRevision for optimistic budget updates.
data.usedUsdstringYeswithin dataCumulative execution-time budget consumption, not an additional wallet charge.
data.runtimeSecondsnumber · ≥ 0Yeswithin dataCumulative Harness execution seconds across all Session Runs. Queue and idle time are excluded.
data.remainingRuntimeSecondsnumber · nullable; ≥ 0Yeswithin dataRemaining execution allowance at the current price, or null for unlimited.
data.usdPerHourstringYeswithin dataCurrent Sandbox hourly rate used to convert the execution allowance.
Example
Example
{
  "data": {
    "limitUsd": "",
    "revision": 0,
    "usedUsd": "",
    "runtimeSeconds": 0,
    "remainingRuntimeSeconds": 0,
    "usdPerHour": ""
  }
}
Error responses
400 Invalid request.

application/json

401 Authentication required.

application/json

403 Budget management or resource scope denied.

application/json

404 Resource not found.

application/json

409 Budget revision changed.

application/json

503 Runtime pricing 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"
  }
}

Replace Session Sandbox budget

PUT /v1/environments/{environmentId}/sessions/{sessionId}/sandbox-budget

Session budgets limit cumulative Harness execution time using versioned Sandbox prices. No additional Sandbox charge or wallet reservation is created. Budget changes do not resume a Sandbox. Changing a running budget is enforced by the worker; the guest also carries its initial execution deadline.

Authentication: Platform API bearer token

Parameters and headers
FieldType and constraintsRequiredDescription
path: environmentIdstring · min length 1Yesenvironment identifier.
path: sessionIdstring · min length 1Yessession identifier.

Request example

sh
curl -X PUT \
    "https://api.sandpi.ai/v1/environments/$ENVIRONMENT_ID/sessions/$SESSION_ID/sandbox-budget" \
    -H "Authorization: Bearer $SANDPI_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
  "limitUsd": 1,
  "revision": 0
}'
Request body · required application/json

Replace a Sandbox budget without changing Environment billing.

FieldType and constraintsRequiredDescription
limitUsdnumber · nullable; ≥ 0; ≤ 100000YesSandbox budget in USD. Zero blocks execution; null removes the limit.
revisioninteger · ≥ 0YesCurrent budget revision. A stale update returns 409.
Example
Example
{
  "limitUsd": 1,
  "revision": 0
}

Responses

200 Sandbox budget state.
Response body application/json
FieldType and constraintsRequiredDescription
dataobject · extra fields rejectedYesSession lifetime execution budget. Resume and rollback do not reset usage. Environment settlement remains unchanged.
data.limitUsdstring · nullableYeswithin dataConfigured USD limit, or null for unlimited.
data.revisioninteger · ≥ 0Yeswithin dataRevision for optimistic budget updates.
data.usedUsdstringYeswithin dataCumulative execution-time budget consumption, not an additional wallet charge.
data.runtimeSecondsnumber · ≥ 0Yeswithin dataCumulative Harness execution seconds across all Session Runs. Queue and idle time are excluded.
data.remainingRuntimeSecondsnumber · nullable; ≥ 0Yeswithin dataRemaining execution allowance at the current price, or null for unlimited.
data.usdPerHourstringYeswithin dataCurrent Sandbox hourly rate used to convert the execution allowance.
Example
Example
{
  "data": {
    "limitUsd": "",
    "revision": 0,
    "usedUsd": "",
    "runtimeSeconds": 0,
    "remainingRuntimeSeconds": 0,
    "usdPerHour": ""
  }
}
Error responses
400 Invalid request.

application/json

401 Authentication required.

application/json

403 Budget management or resource scope denied.

application/json

404 Resource not found.

application/json

409 Budget revision changed.

application/json

503 Runtime pricing 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"
  }
}

Set sandboxBudgetUsd during Session creation or edit its budget in the Work view. Execution seconds consume allowance at the applicable versioned Sandbox price. Later Runs use the remaining allowance; price changes affect future execution and do not rewrite earlier consumption. Resume, model/key rotation, retries and rollback do not reset consumption. Lifetime observations remain with accounting facts after content deletion.

The guest supervisor carries the Run's initial time limit and stops its process group at the deadline, independently of observer connections. The worker records cumulative runtime receipts, enforces live budget reductions and stops the affected Session while allowing other Sessions to continue. A stopped Harness has up to three seconds to exit before force termination; actual runtime and Team settlement may slightly exceed a limit during stopping and checkpoint work. Increasing an active Session budget permits later Runs but does not extend an already-issued guest deadline. Executions retained from before the first rollout use worker-side timing from their first adoption until their next Run. Previously completed Runs are not backfilled into this new execution-control counter. Missing final runtime receipts are conservatively closed from the durable start and last observation, rather than resetting consumption.

When a Team budget is exhausted, active work is stopped and its Environments request a memory-preserving pause. Closing SSE or a browser does not stop execution. Session time limits indirectly constrain model activity; model charges and Token counts are not budgeted by Sandpi.

Read usage

Get Sandbox usage

GET /v1/environments/{environmentId}/usage

Sandbox0-confirmed runtime at $0.10 per Sandbox hour for the fixed 2 vCPU / 4 GiB Sandbox. Paused time is free; model usage is billed by your provider.

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/usage" \
    -H "Authorization: Bearer $SANDPI_API_TOKEN"

No request body.

Responses

200 Successful response.
Response body application/json
FieldType and constraintsRequiredDescription
dataobject · extra fields rejectedYesSandbox0-confirmed runtime at $0.10 per Sandbox hour for the fixed 2 vCPU / 4 GiB Sandbox. Paused time is free; model usage is billed by your provider.
data.runtimeSecondsnumber · ≥ 0Yeswithin dataConfirmed runtime duration in seconds.
data.amountUsdstringYeswithin dataPosted Sandbox runtime charges in USD.
data.reservedUsdstringYeswithin dataCredit currently held for unsettled runtime and admission.
data.usdPerHourstring · values: "0.100000000"Yeswithin dataUSD per hour of the fixed 2 vCPU / 4 GiB Sandbox.
Example
Example
{
  "data": {
    "runtimeSeconds": 0,
    "amountUsd": "",
    "reservedUsd": "",
    "usdPerHour": "0.100000000"
  }
}
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"
  }
}

The Environment is the billing unit. Its usage reports confirmed runtime seconds, posted amount, reserved credit and the hourly rate. Settlement can lag the live Sandbox. A Run's usage reports only windows attributable entirely to that Run; Environment usage includes initialization, idle active time and shared workspace access.

Historical model call charges and unresolved reservations remain available for audit and reconciliation. The $0.10/hour price starts at deployment activation. Earlier runtime retains its previous rate even when reported later; windows crossing activation are split between rates.

New BYOK Runs do not populate the historical rated model-call ledger. Empty usage.calls and zero model-fee fields do not mean the model request was free. Collect model token usage and cost from native Harness events where available and from your provider or gateway's usage records. Run timestamps measure execution duration; billed Sandbox runtime can also include initialization, checkpoints and workspace access. For validation reports, have the workload record each command, exit code, result and duration in an artifact, then retrieve it through the file API.

New user Promotion Credits

New verified accounts registered after this feature is deployed can claim $5 in Promotion Credits, once per account, after successfully binding a card through Stripe Checkout (no payment is collected). They expire 30 days (720 hours) after registration, even if you have not used Platform yet. Registration alone grants no balance. Canceled or failed card setup grants nothing. Existing accounts and built-in administrator accounts are not backfilled.

Promotion Credits pay for Sandbox runtime and are used before paid credits. They are stored separately from money added through Stripe: they cannot be refunded, withdrawn or transferred. Expired unused credits are unavailable. Usage & billing shows paid credits, available Promotion Credits, reservations and the expiration date separately. Runtime ledger entries show the promotional amount applied.

Runtime used before expiration can still consume Promotion Credits when Sandbox0 usage arrives later. Windows crossing the expiration time are split, so runtime after expiration uses paid credits. Live reservations hold only the eligible pre-expiration portion; unused future holds do not extend the promotion. If no paid credit remains, active Runs stop and the Sandbox pauses with memory preserved.

Team Projects use their owner's wallet, including that owner's eligible Promotion Credits, and still enforce the Team Sandbox budget. A member's personal promotion does not fund another owner's Project. Negative paid balances must be repaid before runtime can start; Promotion Credits do not clear refund debt.

Refund unused credits

In your Personal workspace, open Usage & billing → Top-ups & refunds. Select a paid top-up, choose a USD amount, and confirm the refund to its original payment method. Refunds support partial amounts down to one cent. Team members cannot refund the Team owner's wallet; the owner manages refunds in their Personal workspace.

The maximum is the smaller of the payment's remaining unrefunded amount and your current available paid wallet balance, rounded down to whole cents. Used credits and amounts reserved for Sandbox runtime or historical model calls cannot be refunded. Legacy top-up fees already converted to credit are included in the refundable payment total. Posted Sandbox charges and historical model usage remain payable.

Submitting a refund immediately removes that amount from available credit. The receipt shows Processing, Pending, Refunded, Failed, Canceled, Action required, or Under review. Failed and canceled requests return their frozen credit once. An uncertain outcome keeps the credit frozen while Platform reconciles it with Stripe. Contact support for Action required or Under review; bank processing time varies.

Stripe Dashboard refunds also appear in the wallet. An operator refund can exceed the balance left after usage, creating a negative balance that must be replenished before new Sandbox starts or Runs.