---
title: "Usage"
description: "What you have actually consumed, per meter, this period."
url: "https://saved.sh/docs/billing/usage"
---

```bash
curl -fsS "https://api.saved.sh/v1/workspaces/$WID/usage" \
  -H "Authorization: Bearer $TOKEN"
```

```json
{
  "period_start": "2026-08-01T00:00:00Z",
  "period_end": "2026-09-01T00:00:00Z",
  "billing_state": "active",
  "meters": [
    { "meter": "computation", "unit": "run-minutes", "quantity": 124.5 },
    { "meter": "storage",     "unit": "GB-hours",    "quantity": 38.2 },
    { "meter": "archive",     "unit": "GB-days",     "quantity": 1804.0 },
    { "meter": "transit",     "unit": "GB",          "quantity": 0 }
  ]
}
```

Permission: `billing:read`, which is **human-only**. A machine key cannot read usage.

## Turning it into money [#turning-it-into-money]

Multiply each quantity by its rate from `GET /v1/rates`:

```bash
paste <(curl -fsS https://api.saved.sh/v1/rates | jq -r '.rates[] | "\(.meter) \(.usd)"') /dev/null \
  | while read meter rate; do
      qty=$(curl -fsS "https://api.saved.sh/v1/workspaces/$WID/usage" \
            -H "Authorization: Bearer $TOKEN" \
            | jq -r --arg m "$meter" '.meters[] | select(.meter==$m) | .quantity')
      printf '%-12s %10.4f × %-8s = $%.2f\n' "$meter" "$qty" "$rate" "$(echo "$qty * $rate" | bc -l)"
    done
```

Any discount on your [billing profile](/docs/billing/credit#discounts) applies afterwards, and
is not reflected in these quantities.

## How each number is produced [#how-each-number-is-produced]

| Meter         | Written                                     | Granularity                      |
| ------------- | ------------------------------------------- | -------------------------------- |
| `computation` | At the end of each run's post-backup        | One record per run               |
| `storage`     | At the end of each run                      | One record per run               |
| `transit`     | At the end of each run, if bytes left us    | One record per run               |
| `transit`     | When a **download URL is issued**           | One record per issuance          |
| `archive`     | By a **daily job**, just after midnight UTC | One record per workspace per day |

<Callout type="warn">
  **A download is metered when the link is issued, not per fetch.** Asking for a download URL
  records the artifact's full stored size as transit, whether or not you then fetch it, and
  asking twice records it twice. Request the URL when you actually intend to download.
</Callout>

<Callout>
  Archive is sampled, not integrated continuously. It measures what you held **at the moment
  the daily job ran**, so an artifact created and deleted within the same day may never be
  sampled at all.
</Callout>

The daily sample is idempotent: its identity is derived from the workspace and the day, so a
re-run collides rather than double-counting.

## Lag [#lag]

Usage is recorded when a run finishes and reported onward **hourly**.

| Event                    | Visible in this endpoint                     |
| ------------------------ | -------------------------------------------- |
| A run completes          | Immediately                                  |
| Archive for today        | After the daily job, just after midnight UTC |
| Reflected on the invoice | Within about an hour of being recorded       |

<Callout type="warn">
  Usage records older than **35 days** are dropped rather than reported, because the payment
  processor will not accept them. In normal operation nothing gets near that. If you see a gap
  in an old period, that is the mechanism, and it is worth telling us about rather than
  reconciling around.
</Callout>

## Reading it as an operator [#reading-it-as-an-operator]

Three questions worth asking of this endpoint regularly.

**Is archive growing without bound?** It should flatten once every backup's retention reaches
steady state. If it climbs forever, some backup has no `expire_after`.

```bash
curl -fsS "https://api.saved.sh/v1/workspaces/$WID/usage" -H "Authorization: Bearer $TOKEN" \
  | jq -r '.meters[] | select(.meter=="archive") | "archive GB-days: \(.quantity)"'
```

**Is computation disproportionate?** High computation with low archive usually means many
small runs, or a schedule tighter than the data warrants.

**Is transit unexpected?** Transit is zero unless you deliver to your own buckets or keep a
second copy. A non-zero figure you did not plan means a delivery setting you did not intend.

## What is not in here [#what-is-not-in-here]

| Not counted                  |                                                 |
| ---------------------------- | ----------------------------------------------- |
| API calls                    | Not metered                                     |
| Members, workspaces, backups | Not metered. See [limits](/docs/billing/limits) |
| Bytes in your own buckets    | Yours, and billed by your provider              |
| Reading metadata             | Listing backups, runs and artifacts is free     |

Downloads **are** counted, on `transit`. See the table above.

<Callout>
  `max_stored_bytes` in [quotas](/docs/api/quotas) counts only artifacts held in **our**
  storage, on the same basis as the archive meter. Copies delivered to your own buckets count
  toward neither.
</Callout>

## Next [#next]

<Cards>
  <Card href="/docs/billing/pricing" title="Pricing" description="The rate for each meter." />

  <Card href="/docs/billing/invoices" title="Invoices" description="What was actually charged." />

  <Card href="/docs/concepts/retention" title="Retention" description="The lever on the archive line." />
</Cards>
