Usage
What you have actually consumed, per meter, this period.
View as Markdowncurl -fsS "https://api.saved.sh/v1/workspaces/$WID/usage" \
-H "Authorization: Bearer $TOKEN"{
"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
Multiply each quantity by its rate from GET /v1/rates:
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)"
doneAny discount on your billing profile applies afterwards, and is not reflected in these quantities.
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 |
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.
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.
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
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 |
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.
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.
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
| Not counted | |
|---|---|
| API calls | Not metered |
| Members, workspaces, backups | Not metered. See 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.
max_stored_bytes in 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.