Receipts
Each job has one receipt. It records what you asked for, which offer won, what the job used, what it cost
and how fast it ran. The exchange writes it just after it answers. A receipt is final once its
settlement_status is settled, credited or released.
Use the receipt to check a charge. supplier_charge_usd plus fee_usd, less credits_usd, is
buyer_charge_usd. Fees explains the fee.
Read a receipt
GET /v1/jobs/{job_id}: one receipt. The job ID is in thex-liquid-job-idheader and inexchange.job_id.GET /v1/exchange/receipts: your receipts, newest first. It takeslimit,cursor,modelandoutcome(comma-separated lists for the last two) and returnsreceiptsandnext_cursor.- The console shows the same receipts with filters and charts. The
list_receiptsMCP tool lists them for an agent.
A key with read scope or higher can call these routes. A job of another workspace returns 404. A call
at once after the answer can also return 404. Try again after a moment.
curl "https://router.inference.ai.exchange/v1/exchange/receipts?limit=20&outcome=completed" \
-H "Authorization: Bearer $LIQUID_API_KEY"
A stored receipt is one flat JSON object. A receipt for a job
with a winner also has the exchange block of the live response, and can have requested_purchase. An
absent field does not apply to the job. It is not zero. Money fields are USD numbers. A rate is USD per
million tokens.
The exchange block
The exchange block of a live response has a charge object and a usage object. They name the same money as the fields below.
- Each amount has two fields.
supplier_usdis a JSON number in USD.supplier_nanosis the same amount as an integer of nano-USD, so it is exact.cap,estimated,supplier,fee,creditsandtotaleach have both fields. supplier_*is what the provider earns, before the exchange fee.total_*is what you paid:supplierplusfee, lesscredits.usagecounts tokens asprompt_tokens,cached_tokens,cache_write_tokensandcompletion_tokens.reasoning_tokensappears when the provider reports it.usage.pricinglists the use by billable. See Usage below.
"charge": { "cap_nanos": 50000000, "supplier_nanos": 1200000, "fee_nanos": 60000, "credits_nanos": 0, "total_nanos": 1260000 },
"usage": { "prompt_tokens": 120, "completion_tokens": 40, "pricing": [{ "billable": "output_text", "unit": "mtok", "quantity": 40, "usd": 0.000019 }] }
Identity
job_id: one logical request has one job.award_id: the award of the job to an offer. Empty when no offer took the job. It is also the idempotency key that the provider receives.tenant,key_id: your workspace and the API key.key_idis absent for a job from the console.client: the program that sent the job:nameandversion.cost_tag: the label from yourx-liquid-tagheader. A provider never sees it.applied_preset,named_preset: the preset that the key applied, and the preset that you named asmodel, each with its revision.workload: the workload profile of the job. Absent when the profile names no stored workload.requested_model: the name that you sent asmodel. A job with no award has noaddressing, so this is its only model name.created_at,settled_at: when the exchange received the job, and when it settled.
Outcome
outcome: how the job ended. See below.settlement_status: the state of the money. See below.service:met,missed,failed,pending,unknown,not_startedorsingle_supplier_refused.finish_reason:stop,length(the answer reached the output limit) ortool_calls. Absent when no output came.shortfall:needed_usdandbalance_usd. Present only when your balance excluded every offer that could take the job.output_limit:asked_tokensandapplied_tokens. Present when the exchange lowered your output limit so that an offer could take the job.reasoning_effort:askedandsent. They differ when the offer accepts other levels and the exchange sent the nearest onesentis absent when the offer takes no level.
outcome and what each value charges:
| Value | Meaning | Charge |
|---|---|---|
completed |
The provider finished the job. | The tokens used. |
no_eligible_offer |
No offer passed the gate. See eligibility. |
None. The hold is released. |
failed_before_output |
The job failed before any output. | None. The hold is released. |
cancelled_after_output |
The job stopped after output began. | The tokens used. |
provider_error_after_output |
The provider failed after output began. You keep the output. | A full credit. The provider earns nothing. |
partial_output |
A stream stopped after output began, not by the provider's fault. | The input and relayed tokens, as a lower bound. |
deadline_missed |
Old receipts only. A late job is now completed with service missed. |
A full credit. |
settlement_status:
reserved: the exchange holds the price cap. The job is not settled yet.settled: the job was charged.credited: the job was charged and then credited back.pending: usage is missing or in conflict. You get a credit after the deadline. The exchange does not bill you without a warning.released: the hold went back to your balance. You paid nothing.
A job that missed its deadline is charged like any other completed job. credits_usd is zero.
Charge
cap_usd: the most the job could cost, locked before the first token. Also thex-liquid-cap-usdheader.estimated_charge_usd: the cold estimate that ranked the offer, before any cache credit.cache_credit:hit_rate,source(buyerormeasured) andcredit_usd. Ranking uses it. The cap, the hold and the charge do not.supplier_charge_usd: what the provider earns, before the exchange fee.fee_usd: the exchange fee, after any referral discount. See Fees.fee_discount_usdis the part that a referral discount took off.credits_usd: credit that the exchange gave back for the job.buyer_charge_usd: what you paid. It never exceedscap_usd.charge_split: what the input, cache reads, cache writes and output each cost, fee included, astokensandusd. Absent for a job not priced in tokens. When the cap limited the job, the parts add up tobuyer_charge_usdpluscap_held_usd.cap_held_usd: what the cap took off the metered charge, fee included. Present only when the job used more than its cap. The provider carries it.uncached_charge_usd,cache_charge_usd: the charge if all input had the uncached rate, and the part that cache reads and writes cost. Present only when some input used a cache. For information only.rates: the rates that priced the job:uncached_input,cache_read,cache_write_short,cache_write_longandgeneration. They stay as at award time if the provider changes them later.web_search: the search that you asked for with:web. Itscharge_usdis part offee_usdandbuyer_charge_usd.
Usage
meters: what the provider reported, in its own tokenizer. See below.reasoning_tokens: hidden reasoning tokens, billed as output. Present only when the provider reports them.tokenizer_id,rate_schema_version: the tokenizer that counted the tokens, and the rate table that priced the job.usage_provenance: the upstream usage report, unchanged. On a failed job it holds anerror. Null for some media jobs.answer_checks: what the exchange checked in the answer. See below. Absent means not checked, and you must not count it as a pass.
meters fields. A media meter is absent when it is zero.
uncached_input: input tokens that no cache served or kept.cache_read: input tokens that a cache served.cache_write_short,cache_write_long: input tokens written to the cache, by lifetime.generation: output tokens, reasoning included.audio_generationis the audio part.images,characters,video_seconds,audio_seconds: the quantity of an image, speech, video or transcription job. Not tokens.
The exchange.usage block gives the same numbers in a simpler form. prompt_tokens is the sum of all input
meters.
exchange.usage.pricing lists the same use by billable. Each line has billable, unit, quantity and
usd. The usd is the provider charge for that quantity before the exchange fee, at the rate that priced the
job. A receipt with no stored rates has no table. The flat counters stay.
answer_checks changes no charge, except that a chat answer with a bad tool call is rejected before you
receive it.
structured_output.result: the check against yourresponse_format:passed,not_json,schema_mismatch,cut,refusedorunchecked.keywordnames the broken JSON Schema keyword forschema_mismatch. See Structured output.tool_calls,tool_call_errors: the tool calls in the answer, and how many were bad. See Tool calls.tool_call_faults: the bad calls by kind:invalid_json,unknown_name,schema_mismatch.tool_markup: 1 when the text has tool-call markup but the answer has no tool call.
Timing
ttft_ms: time to first token. It starts when the request arrives, so it includes the auction.completion_ms: time from the first byte to the last.promised_ttft_ms: the first-token time that the offer promised. The receipt keeps it.ttft_limit_ms: your limit. Absent for an image job and for old receipts.ttft_deadline_ms:ttft_limit_msplus 1 second for each 10,000 input tokens. The exchange judges the job against this, not against the promise. A job with attft_msabovepromised_ttft_mscan still bemet.
Provider and offer
provider_id: the provider, stable when it changes its slug.provider_slug: its slug at the time.offer_id: the offer that served the job. Use it to trace a charge.provider_attribution: what the provider said about its data handling at award time. Each claim has abasis(declaredorchecked),checked_atandvalid_until. The receipt freezes it.
Addressing
addressing says how your request became a served model. It is absent on a job with no award.
requested,target: the name that you sent, and what it is: amodel, arouteror apreset.match_type:exact,approved_set,routerorauto.router,router_version: the router model that chose the models, and the Auto mode version.served_model,served_precision: the model that answered, and its precision, such asbf16orfp4.provider-managedmeans the provider does not state it.auto: why Auto chose the model. See Auto Router.auto_fallback: why a call to a router model ranked by price and not by Auto.synthetic(a local substitute answered),unverified(no operator reviewed the deployment) andprobe(the exchange sent the job to measure a deployment): do not use such a job as evidence about a model.
Competition
clearing_rule: how the price was set.first_pricecharges the locked rates of the winner, up to its cap.offers_considered,offers_eligible: the offers that the gate looked at, and those that passed.suppliers_eligible,single_supplier: the independent providers behind the eligible offers, and whether only one was eligible.eligibility.excluded: each offer that the gate refused, withprovider,offer_id,reasonand, when it helps,detail.exchange.routing.eligibilitygives the same as counts for each provider and reason.
reason values:
job_kind_not_served,model_not_served: the offer does not make this kind of output, or this model.feature_unsupported,media_unsupported: the deployment cannot do a feature or accept an attachment.detailnames it.context_too_large,output_bound_unsupported: the prompt, your output limit, or a media size is outside what the offer allows.recently_failed: the model failed a job recently, or health samples show it down.service_too_slow,throughput_too_low: the offer's promised deadline is too slow for your limit.cap_exceeds_buyer_cap,cap_exceeds_budget: the worst-case charge is above yourcap_usd, or your balance.rate_above_ceiling,above_cost_tier: the published rate is above your maximum rate or cost tier.region_policy,retention_policy,provider_requirements: the provider does not meet your region, data-retention or provider-claim rules.model_not_allowed,provider_not_allowed,vendor_not_allowed,provider_blocked: your model list, provider list, creator list or block list excludes the offer.offer_expired,pinned_offer_not_resting: the offer is no longer on the book.workload_profile_not_targeted: the offer is outside the workload profile that you named.superseded_by_own_offer: the same provider had a lower offer that also qualified.score_unmapped,score_missing: Auto has no approved score for the deployment, or for the task.
Exchange block and requested purchase
exchange is the block of the live response. See Purchasing rules.
requested_purchase is what the request asked for before the preset of its key limited it: target,
models, strategy, rules and sources. Absent on old jobs.
Check a receipt
- Add
supplier_charge_usdandfee_usd, subtractcredits_usd, and compare withbuyer_charge_usd. It must not exceedcap_usd. - For a job priced in tokens, multiply each
metersvalue by the matching rate inrates. The sum issupplier_charge_usd, unless the cap limited the job. - Compare
fee_usdwith Fees. - Compare
ttft_mswithttft_deadline_ms, not withpromised_ttft_ms.