pending_usd_micros vs held: what Sume's settle sweeper still owns
Sume /v1/usage splits open holds into held and pending_usd_micros. Read the two fields and settle_state to tell parked rows from spend, and when final flips.

pending_usd_micros is the part of held_usd_micros that sits on reserved rows parked in a pending_* state and waiting for Sume's settle sweeper. It is not spend. Quote debited_usd_micros for money that left the wallet, and treat both held and pending as money that may still be returned or captured.
The summary fields come from the Sume OpenAPI schema and the usage docs (read 2026-10-11). Use them when a job-scope or run-scope total looks lower than the amount you expect to be billed.
The four money fields side by side
Every call to GET /v1/usage with a thread_id, run_id or job_id returns a summary that folds over all ledger rows the scope caused. The limit parameter only caps the rows listed, not the totals.
Read them as a set. Each field answers one question about the same scope.
| Field | What it means | Is it spend? |
|---|---|---|
| debited_usd_micros | Amount the wallet deducted: captured rows of every operation type | Yes, quote this |
| held_usd_micros | Holds still open, with parked pending rows included | No, not yet |
| pending_usd_micros | Hold of reserved rows parked pending_*, awaiting the settle sweeper | No, a subset of held |
| refunded_usd_micros | Holds given back after a failure, a cancellation or queue_full | No |
What settle_state tells you per row
Each usage row carries a settle_state that is orthogonal to its status. A row that is reserved and in pending_usage, pending_topup, unpriced or model_mismatch is a hold the settle sweeper still owns. The OpenAPI description says exactly that, and it is the reason a scope can hold money for a short while after the job looks finished.
The three status values stay simple: reserved means Sume reserved the estimated usage before provider execution, captured means it captured the billable usage after a successful completion, and refunded means it released the reservation after a failure or a cancellation before capture.
When final flips to true
final is true when no hold is open. While any row is parked, final stays false, so a dashboard that prints debited_usd_micros alone can understate a campaign. A safe reporting rule is to print the debited figure, print held next to it, and mark the number as provisional until final is true.
If you poll, poll the scope that you care about, such as one run, and stop when final flips. A related post covers what `final: false` means in more detail.
A worked reading of a provisional total
Imagine a run that submits ten jobs and the summary shows a debited figure that is lower than your estimate, with final at false. The gap is not lost money. It is the held amount, and inside it the pending part is what the sweeper has not yet settled. Wait for final to become true, then compare the debited figure with your estimate.
A quick habit helps here: log the summary at submit time, at completion and one more time after a few minutes. Three snapshots show whether money is moving from held to debited or back to refunded, without any guesswork. If final never flips, look at the rows: filter for the reserved ones and read their settle_state. That tells you whether the row waits for usage, for a top-up, for a price-book stamp or for a model match, and it gives support a precise thing to look at.
Why pending matters for a spend cap
The admission model reserves your balance at submit time, so open holds reduce what you can start next, and 402 insufficient_credits can appear while earlier jobs are still parked. If a script keeps hitting that error after the jobs finish, check pending_usd_micros before you top up: the money may be coming back.
Never add rows yourself to reach a total. The usage docs say not to sum rows, and a refunded row keeps its hold amount in billable_amount_usd_micros, which would double count. Use the summary, and see why sub-cent rows do not add up for the rounding rule.
Sources
Related posts
More in Developers
- unpriced_usd_micros: legacy rows still inside Sume's debited total
unpriced_usd_micros in Sume /v1/usage is captured spend from legacy rows with no price-book stamp. It is inside debited, so never subtract or add it twice.
- TanStack Start webhook route for Sume jobs: verify the raw body
Receive a signed Sume job webhook in a TanStack Start server route: read request.text(), verify with the SDK, answer 204, and dedupe on job_id.
- Usage hold_counts: open, browser_session, billing_pending
A scoped Sume usage summary can show final false with money held. hold_counts says whether a turn runs, a Browser session is open, or work is being priced.
- What one script_run call cost: the usage script_runs array
Sume's usage summary lists each script_run call with its rows, debited, held and refunded micros, so a fan-out of TTS or image jobs has one price.
Written by Sume