---
title: "Track Sandbox costs"
description: "Check credit and wallet history, then attribute compute cost to API keys, Sandboxes, and charged runs."
---

> Documentation Index
> Fetch the complete documentation index at: https://boxcompute.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Track Sandbox costs

Use the public cost routes to attribute Sandbox compute to the API key that created each Sandbox.
These routes require `usage:read` and are available through direct HTTP, SDK 0.4.0, and the CLI.

The Sandboxes page in the BoxCompute dashboard provides the same account-owned breakdown.

## Check credit and wallet history

`GET /api/v2/billing` and `GET /api/v2/billing/transactions` require `usage:read`, remain readable
at zero credit, and never start or resume compute. They return only the authenticated account's data.
All monetary amounts are integer micro-USD: 1,000,000 micros is USD 1.

```bash
curl --fail-with-body -sS 'https://api.boxcompute.ai/api/v2/billing' \
  -H "Authorization: Bearer $BOXCOMPUTE_API_KEY"
```

An illustrative response with no running compute:

```json
{
  "billing": {
"currency": "usd",
"accountStatus": "active",
"balance": {
  "cashMicros": 5000000,
  "promoMicros": 2000000,
  "planMicros": 0,
  "totalMicros": 7000000,
  "availableMicros": 7000000,
  "reservedMicros": 0,
  "expiringPromo": { "micros": 2000000, "expiresAt": 1791676800000 }
},
"settledUsage": { "aiMicros": 0, "sandboxMicros": 3000000, "totalMicros": 3000000 },
"activeEstimate": {
  "status": "not_applicable",
  "asOf": null,
  "runtimeSeconds": 0,
  "billableSeconds": 0,
  "amountMicros": 0
},
"modelBillingMode": "observe"
  }
}
```

`totalMicros` is the wallet balance; `availableMicros` is spendable credit after reservations and
running compute. If live estimates fail, `activeEstimate.status` is `unavailable` and
`availableMicros` is `null`—unknown, not zero. `settledUsage` is all-time verified AI and compute
wallet deductions, not a date-window report, reservations, or running estimates. In `observe`
model billing mode, recorded AI costs do not debit the wallet. `expiringPromo` is nullable;
its `expiresAt`, like transaction timestamps, is Unix milliseconds.

Read one newest-first wallet page:

```bash
curl --fail-with-body -sS --get 'https://api.boxcompute.ai/api/v2/billing/transactions' \
  -H "Authorization: Bearer $BOXCOMPUTE_API_KEY" \
  --data-urlencode 'bucket=promo' \
  --data-urlencode 'limit=20'
```

The response is `{ "currency": "usd", "transactions": [...], "nextCursor": string | null }`.
Each entry contains `id`, `kind`, `bucket`, signed `amountMicros`, `description`, `createdAt`,
and nullable `expiresAt`. Positive amounts add credit; negative amounts subtract it. Entries are
bucket-level, so one charge can have multiple entries. Pass `nextCursor` as `before` with the same
filters until it is `null`. `limit` is 1–200 (default 50). Optional filters are inclusive `from`
and exclusive `to` RFC 3339 timestamps, `kind`, and `bucket` (`cash`, `promo`, or `plan`).

SDK 0.4.0 unwraps the summary, but returns the transaction page directly:

### TypeScript

```ts
const billing = await boxcompute.billing.get();
const page = await boxcompute.billing.transactions({
  bucket: "promo",
  limit: 20,
});
console.log(billing.balance.availableMicros);
console.log(page.nextCursor);
```
### Python

```python
billing = boxcompute.billing.get()
page = boxcompute.billing.transactions(
bucket="promo", limit=20,
)
print(billing.balance.available_micros)
print(page.next_cursor)
```

These snippets use the authenticated client from the [SDK quickstart](/quickstart); Python's
date-start filter is `from_`. CLI 0.10.0 provides `bxc credits`, `bxc billing transactions`, and
`bxc usage`; see [CLI commands](/cli/commands#credit-wallet-history-and-usage).

## Get an account report

Request the default 30-day window:

```bash
curl 'https://api.boxcompute.ai/api/v2/costs/sandboxes' \
  -H 'Authorization: Bearer bc_live_REDACTED'
```

Set an inclusive `from` and exclusive `to` with RFC 3339 timestamps when you need another period.
A window can span at most 400 days:

```bash
curl --get 'https://api.boxcompute.ai/api/v2/costs/sandboxes' \
  -H 'Authorization: Bearer bc_live_REDACTED' \
  --data-urlencode 'from=2026-09-01T00:00:00Z' \
  --data-urlencode 'to=2026-10-01T00:00:00Z'
```

The response groups the same costs by creating API key and by Sandbox:

```json
{
  "costs": {
"from": 1788220800000,
"to": 1790812800000,
"currency": "usd",
"estimates": "available",
"totals": {
  "runs": 3,
  "billableSeconds": 420,
  "settledMicros": 7000,
  "estimatedMicros": 500
},
"apiKeys": [
  {
    "apiKey": {
      "id": "key_REDACTED",
      "name": "Batch jobs",
      "hint": "ab12",
      "revoked": false
    },
    "sandboxes": 1,
    "runs": 3,
    "billableSeconds": 420,
    "settledMicros": 7000,
    "estimatedMicros": 500
  }
],
"sandboxes": [
  {
    "id": "sbx_REDACTED",
    "sandboxId": "sbx_REDACTED",
    "name": "Data import",
    "deleted": false,
    "vmSandbox": true,
    "size": "small",
    "createdByApiKeyId": "key_REDACTED",
    "createdAt": 1788220800000,
    "deletedAt": null,
    "firstStartedAt": 1788307200000,
    "lastEndedAt": 1788912000000,
    "runs": 3,
    "billableSeconds": 420,
    "settledMicros": 7000,
    "estimatedMicros": 500
  }
],
"unattributed": {
  "runs": 0,
  "billableSeconds": 0,
  "settledMicros": 0,
  "estimatedMicros": 0
}
  }
}
```

Amounts are integer millionths of the stated currency: `1,000,000` micros is USD 1. Settled
amounts are exact ledger charges for runs that ended in the window. `estimatedMicros` covers work
still running and is replaced by its settled charge after that run ends. `estimates` is
`available`, `not_applicable`, or `unavailable`; an unavailable estimate does not make settled
amounts approximate.

Billing is per second with a 60-second minimum for each run. A report includes active and deleted
Sandboxes. Its `sandboxes` rows identify the original customer-facing `sandboxId`, creation key,
runtime type and size, timestamps, run count, billable seconds, and settled and estimated amounts.
`unattributed` contains charges whose surviving records cannot identify a Sandbox.

Filter by one creating key with `apiKeyId=key_REDACTED`. Use `apiKeyId=none` for Sandboxes created
without an API key, such as from the dashboard or another account-owned product surface. Revoked
keys remain identifiable in historical results.

## Inspect charged runs

Get every retained charged run plus any running estimate for an active Sandbox:

```bash
curl 'https://api.boxcompute.ai/api/v2/sandboxes/sbx_REDACTED/costs' \
  -H 'Authorization: Bearer bc_live_REDACTED'
```

For a deleted Sandbox, use the `dsb_…` deletion-record ID returned by
`GET /api/v2/deleted-sandboxes`:

```bash
API_BASE='https://api.boxcompute.ai/api/v2'
curl "$API_BASE/deleted-sandboxes/dsb_REDACTED/costs" \
  -H 'Authorization: Bearer bc_live_REDACTED'
```

The `{ "costs": ... }` detail includes Sandbox and creating-key metadata, `currency`, estimate
status, settled `runs`, current `running` estimates, and `truncated`. Each settled run reports
`startedAt`, `endedAt`, `runtimeSeconds`, `billableSeconds`, `rateMicrosPerMinute`, and
`amountMicros`. At most 1,000 settled runs are returned; `truncated: true` means additional runs
were omitted. Deleted-Sandbox detail has no running estimate.

Cost lookups are limited to the authenticated account. An unknown or cross-account active or
deleted Sandbox returns `404`.

Source: https://boxcompute.ai/docs/costs/index.mdx
