---
title: Usage and cost
description: List your lane's runs with their durations and estimated costs. Every cost is an estimate, never a bill.
---

**Every cost on this page is an estimate.** It is worked out from a run's seconds, its CPU and memory size, and published rates. It is not read from a bill, and the data says so: each cost carries `"estimate": true`.

Your key shows only its own lane's runs. A run is one sandbox, from its create to its end.

## From the command line

```sh
ibby usage
ibby usage --since 2026-11-01T00:00:00Z --until 2026-12-01T00:00:00Z
ibby usage --json
```

`ibby usage` fetches every page and prints a table. Its columns are fixed, in this order, and named after the API's fields:

| Column | What it holds |
| --- | --- |
| `started_at` | When the run started, in UTC |
| `sandbox_id` | The sandbox, `sbx_...` |
| `name` | The sandbox's name, or `-` |
| `outcome` | How the sandbox ended, or `-` while it runs: `removed` (you removed it), `lifetime_reached` (its lifetime ran out), `resource_limit` (its size limit stopped it) or `failed` (the create failed or the platform lost it). New values may be added. |
| `duration_ms` | How long it lasted, or `-` while it runs |
| `cpu` | CPU cores |
| `memory_mib` | Memory, in MiB |
| `region` | The lane's region |
| `estimated_cost` | The estimated cost in USD, as a decimal, or `-` while it runs |

Cells are separated by spaces, and no cell contains a space, so a script can split each line on whitespace. The last line holds the totals of the runs that have ended:

```text
total (estimate): 12 runs, duration_ms 720000, estimated_cost 0.007920 USD
```

With `--json`, the tool prints `{ "runs", "totals", "next_cursor": null }`: every run, and the totals over all of them.

## From code

`usage()` returns one page, newest first, with totals for that page. Pass `next_cursor` back as `cursor` for the next page, or let the SDK follow the pages for you.

```ts
import { Ibby } from "@ibby-ai/sdk";

const ibby = new Ibby({ apiKey: process.env["IBBY_API_KEY"] ?? "" });

const page = await ibby.usage({ since: "2026-11-01T00:00:00Z", limit: 50 });
console.log(page.totals.duration_ms, page.totals.estimated_cost.amount);

for await (const each of ibby.usagePages({ since: "2026-11-01T00:00:00Z" })) {
  for (const run of each.runs) {
    console.log(
      run.sandbox_id,
      run.outcome,
      run.duration_ms,
      run.estimated_cost?.amount
    );
  }
}
```

```python
import os

from ibby import Ibby

with Ibby(os.environ["IBBY_API_KEY"]) as client:
    page = client.usage(since="2026-11-01T00:00:00Z", limit=50)
    print(page.totals.duration_ms, page.totals.estimated_cost.amount)

    for each in client.usage_pages(since="2026-11-01T00:00:00Z"):
        for run in each.runs:
            cost = run.estimated_cost.amount if run.estimated_cost else None
            print(run.sandbox_id, run.outcome, run.duration_ms, cost)
```

A cost's `amount` is a decimal string, such as `"0.000660"`. Add amounts as decimals, not floats, or the totals drift.

## Estimate limits

A run's times are when the platform saw it start and end, so an estimate can be off in three known ways:

- A sandbox that stops on its own is seen to end at the next call on it, or at the platform's next check, a few minutes at most. It is counted until then, except a run that reached its lifetime, which is never counted longer than its lifetime.
- A create whose answer was lost, and which the platform later finds running, is counted from when it was found, not from when it really started.
- A sandbox made after its create had already been given up on is removed by the platform and never counted.

## What a run record holds

Only ids, times, durations, CPU and memory size, region, outcome and the estimate. The platform never stores command text, environment values, output or file names, so none of them can appear here.
