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
/v1/teams/{teamId}/sandbox-budgetTeam 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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: teamId | string · min length 1 | Yes | team identifier. |
Request example
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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | object · extra fields rejected | Yes | Team Sandbox budget. Each Environment charge and hold is counted once. |
data.limitUsd | string · nullable | Yeswithin data | Configured USD limit, or null for unlimited. |
data.revision | integer · ≥ 0 | Yeswithin data | Revision for optimistic budget updates. |
data.spentUsd | string | Yeswithin data | Posted Environment runtime charges across all Team Projects in this UTC month. |
data.reservedUsd | string | Yeswithin data | Outstanding Environment runtime reservations; includes promotional funding. |
data.periodStartsAt | string · format: date-time | Yeswithin data | UTC calendar month start. |
data.periodEndsAt | string · format: date-time | Yeswithin data | UTC calendar month end. |
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
Example
{
"error": {
"code": "platform_balance_insufficient",
"message": "Top up Platform credits before submitting a Run.",
"requestId": "req_example"
}
}Replace Team Sandbox budget
/v1/teams/{teamId}/sandbox-budgetTeam 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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: teamId | string · min length 1 | Yes | team identifier. |
Request example
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
limitUsd | number · nullable; ≥ 0; ≤ 100000 | Yes | Sandbox budget in USD. Zero blocks execution; null removes the limit. |
revision | integer · ≥ 0 | Yes | Current budget revision. A stale update returns 409. |
Example
{
"limitUsd": 1,
"revision": 0
}Responses
200 Sandbox budget state.Response body application/json
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | object · extra fields rejected | Yes | Team Sandbox budget. Each Environment charge and hold is counted once. |
data.limitUsd | string · nullable | Yeswithin data | Configured USD limit, or null for unlimited. |
data.revision | integer · ≥ 0 | Yeswithin data | Revision for optimistic budget updates. |
data.spentUsd | string | Yeswithin data | Posted Environment runtime charges across all Team Projects in this UTC month. |
data.reservedUsd | string | Yeswithin data | Outstanding Environment runtime reservations; includes promotional funding. |
data.periodStartsAt | string · format: date-time | Yeswithin data | UTC calendar month start. |
data.periodEndsAt | string · format: date-time | Yeswithin data | UTC calendar month end. |
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
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
/v1/environments/{environmentId}/sessions/{sessionId}/sandbox-budgetSession 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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: environmentId | string · min length 1 | Yes | environment identifier. |
path: sessionId | string · min length 1 | Yes | session identifier. |
Request example
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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | object · extra fields rejected | Yes | Session lifetime execution budget. Resume and rollback do not reset usage. Environment settlement remains unchanged. |
data.limitUsd | string · nullable | Yeswithin data | Configured USD limit, or null for unlimited. |
data.revision | integer · ≥ 0 | Yeswithin data | Revision for optimistic budget updates. |
data.usedUsd | string | Yeswithin data | Cumulative execution-time budget consumption, not an additional wallet charge. |
data.runtimeSeconds | number · ≥ 0 | Yeswithin data | Cumulative Harness execution seconds across all Session Runs. Queue and idle time are excluded. |
data.remainingRuntimeSeconds | number · nullable; ≥ 0 | Yeswithin data | Remaining execution allowance at the current price, or null for unlimited. |
data.usdPerHour | string | Yeswithin data | Current Sandbox hourly rate used to convert the execution allowance. |
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
Example
{
"error": {
"code": "platform_balance_insufficient",
"message": "Top up Platform credits before submitting a Run.",
"requestId": "req_example"
}
}Replace Session Sandbox budget
/v1/environments/{environmentId}/sessions/{sessionId}/sandbox-budgetSession 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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: environmentId | string · min length 1 | Yes | environment identifier. |
path: sessionId | string · min length 1 | Yes | session identifier. |
Request example
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
limitUsd | number · nullable; ≥ 0; ≤ 100000 | Yes | Sandbox budget in USD. Zero blocks execution; null removes the limit. |
revision | integer · ≥ 0 | Yes | Current budget revision. A stale update returns 409. |
Example
{
"limitUsd": 1,
"revision": 0
}Responses
200 Sandbox budget state.Response body application/json
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | object · extra fields rejected | Yes | Session lifetime execution budget. Resume and rollback do not reset usage. Environment settlement remains unchanged. |
data.limitUsd | string · nullable | Yeswithin data | Configured USD limit, or null for unlimited. |
data.revision | integer · ≥ 0 | Yeswithin data | Revision for optimistic budget updates. |
data.usedUsd | string | Yeswithin data | Cumulative execution-time budget consumption, not an additional wallet charge. |
data.runtimeSeconds | number · ≥ 0 | Yeswithin data | Cumulative Harness execution seconds across all Session Runs. Queue and idle time are excluded. |
data.remainingRuntimeSeconds | number · nullable; ≥ 0 | Yeswithin data | Remaining execution allowance at the current price, or null for unlimited. |
data.usdPerHour | string | Yeswithin data | Current Sandbox hourly rate used to convert the execution allowance. |
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
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
/v1/environments/{environmentId}/usageSandbox0-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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
path: environmentId | string · min length 1 | Yes | Environment identifier. It must belong to the caller’s account or Project. |
Request example
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
| Field | Type and constraints | Required | Description |
|---|---|---|---|
data | object · extra fields rejected | Yes | 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. |
data.runtimeSeconds | number · ≥ 0 | Yeswithin data | Confirmed runtime duration in seconds. |
data.amountUsd | string | Yeswithin data | Posted Sandbox runtime charges in USD. |
data.reservedUsd | string | Yeswithin data | Credit currently held for unsettled runtime and admission. |
data.usdPerHour | string · values: "0.100000000" | Yeswithin data | USD per hour of the fixed 2 vCPU / 4 GiB Sandbox. |
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.
| Field | Type and constraints | Required | Description |
|---|---|---|---|
error | object · extra fields rejected | Yes | Structured failure information. Inspect the stable code and retain the request ID for investigation. |
error.code | string | Yeswithin error | Stable error code used to distinguish failures programmatically. |
error.message | string | Yeswithin error | Human-readable diagnostic text. |
error.requestId | string | Yeswithin error | Request identifier for correlating diagnostics and support investigations. |
error.details | any | Nowithin error | Optional structured error context. Its shape is specific to the service failure. |
error.loginUrl | string | Nowithin error | Authentication URL supplied when a browser login is required. |
error.registrationOpen | boolean | Nowithin error | Whether new account registration is enabled for this deployment. |
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.