PLATINUM DOCS

Billing

Prepaid credits, per-second metering, and spend limits for orgs and members.

Platinum billing is prepaid. You buy credits, and metered usage draws down the org balance. Manage billing in the dashboard or with the /v1/billing/* endpoints.

What is billed

Platinum samples usage every 60 seconds. It prices vCPU-seconds, GiB-seconds of RAM, and GiB-hours of disk. Volumes, snapshots, and GPU attachments are free.

Sandbox stateCPURAMDisk
runningbilledbilledbilled
stoppedbilled
archived
deleted

Compute charges stop when a sandbox stops. A stopped sandbox costs at most its disk. Set auto_stop_minutes (Sandboxes) to control idle cost.

Zero balance

Usage debits the org balance. At balance ≤ 0:

SurfaceWhat happens
New compute — create, start, resume, restore, restore-from-backup, clone, fork402 insufficient_credits
Running sandboxes60-minute grace period; then auto-stopped (never deleted)
Stopped sandboxesPlatinum keeps the disk. After the balance is positive, call /start or /resume. Credits alone do not restart them.
Preview URLsTraffic to an exposed port does not restart a stopped sandbox

Add credits

New signups get a one-time $10 trial credit on the personal org. Later orgs start at $0.

Only owners and admins can buy credits. Any member can read the balance, ledger, limits, and usage.

To add credits:

  1. Open dashboard → Billing.
  2. Pick a credit pack, or enter a custom amount.
  3. Complete the Stripe-hosted checkout.

The balance updates when the payment clears, usually seconds after checkout. There is no API or CLI route to buy credits.

Set spend limits

Only owners and admins can set limits. Limits reset on the first day of each calendar month (UTC). A limit is independent of the balance: it blocks spend even when credits remain.

An alert only warns. A limit blocks. After you hit a limit, spend-increasing calls (POST/PUT/PATCH) return 402. Reads, deletes, and /v1/billing/* stay open, so you can watch usage, shed cost, or raise the limit.

SettingApplies toNotifies atBlocks at
usage_alert_usdwhole orgthe amount you set — email + org.usage_alert webhooknever
usage_limit_usdwhole org50 / 80 / 90 / 100% — email + org.usage_limit_reached webhook100% → 402 usage_limit_exceeded
limit_usdone member50 / 80 / 90 / 100% — email to that member100% → 402 user_usage_limit_exceeded

Webhook payloads: Webhooks.

The SDKs have no typed billing helpers. Use client.request().

Read current limits

Any member can read /v1/billing/limits. It returns the org caps plus the caller's own cap and spend. /v1/billing/user-limits is owner/admin only. It lists each member's cap and spend.

const limits = await client.request("GET", "/v1/billing/limits");
const userLimits = await client.request("GET", "/v1/billing/user-limits");
limits = client.request("GET", "/v1/billing/limits")
user_limits = client.request("GET", "/v1/billing/user-limits")
pt api /v1/billing/limits
pt api /v1/billing/user-limits
curl -H "Authorization: Bearer $PT_TOKEN" "$PT_API_URL/v1/billing/limits"
curl -H "Authorization: Bearer $PT_TOKEN" "$PT_API_URL/v1/billing/user-limits"

Set the org cap

The org limit cannot drop below the total already allocated to members.

await client.request("PUT", "/v1/billing/limits", {
  usage_limit_usd: 200,
  usage_alert_usd: 150,
});
client.request("PUT", "/v1/billing/limits", {"usage_limit_usd": 200, "usage_alert_usd": 150})
pt api PUT /v1/billing/limits -d '{"usage_limit_usd":200,"usage_alert_usd":150}'
curl -X PUT "$PT_API_URL/v1/billing/limits" -H "Authorization: Bearer $PT_TOKEN" \
  -H "Content-Type: application/json" -d '{"usage_limit_usd":200,"usage_alert_usd":150}'

Cap a member

You cannot cap an owner. Member caps cannot sum past the org limit; over-allocation returns 400. limit_usd: null clears a cap. The API rejects the value 0.

await client.request("PUT", `/v1/billing/user-limits/${userId}`, { limit_usd: 50 });
client.request("PUT", f"/v1/billing/user-limits/{user_id}", {"limit_usd": 50})
pt api PUT /v1/billing/user-limits/$USER_ID -d '{"limit_usd":50}'
curl -X PUT "$PT_API_URL/v1/billing/user-limits/$USER_ID" -H "Authorization: Bearer $PT_TOKEN" \
  -H "Content-Type: application/json" -d '{"limit_usd":50}'

Query usage

GET /v1/billing/usage rolls up the org's metered usage. The default window is the last 30 days. For one sandbox, use GET /v1/sandboxes/:id/usage (SDK: sbx.usage()).

const usage = await client.request("GET", "/v1/billing/usage?group=sandbox");
const one = await sbx.usage(); // one sandbox
usage = client.request("GET", "/v1/billing/usage?group=sandbox")
one = sbx.usage()  # one sandbox
pt api /v1/billing/usage --query "group=sandbox"
pt api /v1/sandboxes/$SBX/usage
curl -H "Authorization: Bearer $PT_TOKEN" "$PT_API_URL/v1/billing/usage?group=sandbox"
curl -H "Authorization: Bearer $PT_TOKEN" "$PT_API_URL/v1/sandboxes/$SBX/usage"
ParamEffect
since_mswindow start (epoch ms)
group=sandboxper-sandbox breakdown, spend-ordered
serieshour or day — time-bucketed points; hour defaults to the last 24 h