# How to read your usage ledger — every charge, every refund

> Reconcile a balance line by line — what an operation row holds, why a refund is negative, and how to find the member or key that spent the credits.

Published 2026-09-13 · eroq.ai — canonical: https://eroq.ai/blog/how-to-read-your-usage-ledger


The balance is 180 lower than your arithmetic says it should be, or 180 higher, and either way you would like to know why before you tell a client. The request log answers that, but only if you know what it is recording — because it is a ledger of *movements*, not a list of successful generations, and those are not the same list.

## One row per movement

Every credit that moves writes a row. The row holds when it happened, the operation, the model id and a signed credit amount — and that is what the request log renders, under **Request log** in [the developers dashboard](/dashboard/developers).

There are six operations and they are the only values you will see in that column:

- `chat` — a completion on RP+ or RP mini, including the extra 2 credits per attached image when vision is used.
- `image` — one image generation call. A batch of four is one row, not four.
- `video` — one queued clip.
- `speech` — one text-to-speech call, priced per started block of 100 characters.
- `transcription` — one speech-to-text call, flat.
- `storage` — an upload to the eroq Store, 2 credits per started 10 MB.

The log is workspace-scoped, so your teammates' calls are in it too, and it covers the last 30 days in pages of fifty. The model column is the public model id — `eroq-image-anime`, `seedance-2-5`, `eroq-voice-turbo` — which is the same string you passed in the request, so a row is traceable back to a specific call in your own logs.

## Charged at submission, not at delivery

The rule that explains most confusing ledgers: credits are spent *before* the engine runs, never after. Charging on success sounds fairer and is not implementable — a client that hangs up mid-stream would otherwise collect a free generation every time.

So the charge row exists the moment your request is accepted. A video clip debits when the job is queued, not when the file arrives. A batch of four images debits 40 credits before the first pixel is drawn. What makes this fair is the other half of the rule, which is that failures give the credits back.

## A negative row is a refund

Refunds are written as a second row with a negative amount, tagged **refund** in the table and rendered with a plus sign — because in the ledger a refund is money coming back to you.

Refunds are automatic and cover every way a generation can fail to deliver: an engine that returned nothing, a prompt the engine blocked, a video job still unfinished past its ten-minute deadline, a chat stream that died before emitting a token, an upload that failed after being charged. There is nothing to claim and no support ticket to open.

The amount tells you what failed. A video refund is always the full clip price, because a clip either arrives or it does not. An image refund is one unit — 10 credits — per failed take, so a batch of four with two duds shows a 40-credit charge and two separate 10-credit refunds. That asymmetry is the whole diagnostic: a partial refund on an image row means part of your batch came back empty.

## Reconciling a balance, worked

Say a session shows this, newest first, on a workspace that started the day at 5,000 credits:

```
video   seedance-2-5      +180   (refund)
video   seedance-2-5      −180
image   eroq-image-one     +10   (refund)
image   eroq-image-one     −40
video   eroq-motion-one   −100
```

Read bottom to top. A five-second Motion One clip cost 100 and delivered. A batch of four images cost 40, one take came back empty and refunded 10, so three images cost 30. A five-second Seedance 2.5 clip charged 180 and refunded 180 — it never delivered, and it cost nothing.

Net movement is 130 credits, and the balance is 4,870. Five rows, three deliverables, one free failure. Two things follow. First, the per-day chart totals are net of refunds, so the number it shows is what you actually spent. Second, the request counter only counts positive rows — a refund is not a request — which is why request count and row count differ on any day that had a failure.

## Finding who spent it

The log does not break spend down by person, because the place that does is the **Members** tab of [your workspace](/dashboard/workspace). Each member row carries their credits spent this calendar month, net of refunds and floored at zero.

That column is also the one a per-member monthly ceiling is measured against, and the netting is deliberate: a contractor whose render failed and refunded itself has not consumed any of their allowance. The ceiling resets on the first of the month, and an admin can raise it without touching anyone's role.

Attribution to a *key* works through the same column rather than a separate one. Every ledger row records the API key that made the call — studio calls record none, since a browser session is not a key — and a key belongs to exactly one member and inherits that member's role. So per-member spend is per-key spend, aggregated by holder. Give each integration its own member seat if you need the split to be clean; [workspace roles and permissions](/blog/workspace-roles-and-permissions) covers what each rung can do.

## The API's own view is narrower

`GET /v1/account` gives you a balance and a 30-day summary:

```json
{
  "object": "account",
  "credits": 4870,
  "usage_30d": { "requests": 213, "credits": 9614 }
}
```

One catch that costs people an afternoon: this endpoint is scoped to the *account* holding the key, while the dashboard log is scoped to the *workspace*. On a solo workspace they agree. On a shared one they will not — your key's `usage_30d` excludes everything your teammates spent out of the same wallet, even though `credits` is the shared balance they are all drawing down. Read the dashboard for workspace totals and `/v1/account` for "what has this key's owner done".

`usage_30d.credits` is also net of refunds, and `requests` counts charges only, exactly like the chart.

## The rows people do not expect

Two patterns account for most "what is this line" questions.

**A `storage` row next to a generation.** Passing `store: true` persists the output to the eroq Store and returns a CDN URL, charged on top at 2 credits per started 10 MB. That is a second row with model `eroq-store`, which is why a 10-credit image sometimes reads as 12. Saving a render to your Library is free and writes no row at all — only the Store does.

**Several `chat` rows for one conversation.** Chat bills per completion, so a twelve-turn scene is twelve rows of 3 credits on RP+. There is more on pricing that shape of usage in [credit pricing for AI APIs](/blog/credit-pricing-for-ai-apis), and on team wallets in [managing AI credits across a team](/blog/managing-ai-credits-across-a-team).

[Open the request log](/dashboard/developers) and reconcile your last session — it takes about a minute once you know which rows are refunds.

## FAQ

### Why does my balance drop before the render finishes?

Because credits are charged when a job is accepted rather than when it delivers, which is the only way to stop an abandoned request from collecting a free generation. If the render fails, times out or is blocked, a refund row puts the credits back automatically. Your balance ends where it should either way.

### What does a negative number in the credits column mean?

It is a refund being paid back into the workspace wallet, which is why the table tags the row and shows it with a plus sign. Every refund names the operation and model it reverses, so you can pair it with the charge above it. Blocked prompts, failed renders and jobs past their deadline all produce one.

### Why do my dashboard totals differ from what my API key reports?

The dashboard log covers the whole workspace and `GET /v1/account` covers only the account that owns the key. On a shared wallet the key's 30-day figures will be lower than the workspace's, because your teammates' spend is not attributed to your account. The `credits` balance is shared, so that one always matches.

### How far back does the request log go?

Thirty days, loaded fifty rows at a time. The per-day chart covers the same window, so if you need a longer history, export what you need before it rolls off. Per-member monthly spend on the workspace Members tab is calculated over the current calendar month, which is a different window again.
