Build

Receipts and verification.

Every request returns a receipt. Follow it to its settlement and check it against the public log.

On this page

Every request returns a receipt: what was billed, at which price, and where it settles.

The same receipt appears in five places:

  • The JSON body, as receipt.
  • A stream's last comment line, : receipt {…}.
  • The x-request-id header, with the cost in x-cost-units on a response that is not streamed. A chat or text completion paid per request carries receipt.paid instead.
  • GET /v1/receipts/{id}, with the key that made the request.
  • The MCP receipt tool.

The receipt on a response

"receipt": {
  "request_id": "<request_id>",
  "model": "<model>",
  "provider": "<provider>",
  "status": "ok",
  "usage": { "prompt_tokens": …, "completion_tokens": …, "cached_tokens": … },
  "price": { "version": "<price sheet>", "input": …, "output": … },
  "cost": { "units": "<units>", "usd": "<usd>", "usdf": "<usdf>" },
  "balance": { "units": "<units>", "usd": "<usd>", "usdf": "<usdf>" },
  "data_policy": { … },
  "settlement": {
    "status": "unsettled",
    "next_batch_after": "<time>",
    "lookup": "https://api.usdf.fi/v1/receipts/<request_id>"
  }
}

Looked up later, the receipt adds when it was made and its place in the usage log:

Look up a receipt

curl
curl https://api.usdf.fi/v1/receipts/<request_id> \
  -H "Authorization: Bearer $USDF_API_KEY"

Response

{
  "request_id": "<request_id>",
  "model": "<model>",
  "provider": "<provider>",
  "status": "ok",
  "created_at": "<time>",
  "usage": { "prompt_tokens": …, "completion_tokens": …, "cached_tokens": … },
  "price_version": "<price sheet>",
  "cost": { "units": "<units>", "usd": "<usd>", "usdf": "<usdf>" },
  "settlement": { "status": "unsettled", "next_batch_after": "<time>" },
  "log": {
    "leaf_index": …, "tree_size": …, "status": "published",
    "anchored_by": null,
    "proof": "https://api.usdf.fi/v1/log/proof/<request_id>"
  }
}

Every field:

FieldMeaning
request_idThe request's id. Also the response id.
modelThe model, without any routing suffix.
providerThe route that served it.
statusok, partial, or failed_refunded with a reason: upstream_error, upstream_timeout, empty_output, gateway_shutdown or gateway_error.
usageThe provider's token counts.
price, price_versionThe sheet version and the rates charged. A lookup names the version.
costWhat was charged, as { units, usd, usdf }.
balanceOn a response: the balance after the charge.
data_policyWhat the serving route does with content, and what was asked.
settlementstatus and next_batch_after; once settled, batch, tx_hash, explorer and rows.
logOn a lookup: leaf_index, tree_size, status, anchored_by and the proof URL.

A partial receipt was cut short and is billed for what was produced. A failed_refunded one costs zero.

A request paid per request carries the payment too:

  • paid: the quote, which is what was charged; usage_cost: what the request used.
  • payment: tx, explorer, payer, amount, asset and method.
  • settlement.scheme: x402 exact, or mpp evm charge, with the network.
  • On non-chat endpoints, modality, endpoint and billed, plus lookup.

The receipt of any request, keyed or paid per request, is public with no key. It publishes nothing the log does not.

Read a public receipt

curl
curl https://api.usdf.fi/x402/v1/receipts/<request_id>

A USDG payment, or a refund, has settlement none: its own payment transaction is the on-chain record. A USDF payment is burned in a later settlement batch with the rest of the spend.

GET /v1/receipts lists the latest receipts, newest first, with limit, before, model and status.

A key lists its own requests. A session lists the account's. Naming another key gets 403 key_scope.

List and read receipts

curl "https://api.usdf.fi/v1/receipts?limit=20" \
  -H "Authorization: Bearer $USDF_API_KEY"

curl https://api.usdf.fi/v1/receipts/<request_id> \
  -H "Authorization: Bearer $USDF_API_KEY"

Response, trimmed

{
  "data": [
    {
      "request_id": "<request_id>",
      "created_at": "<time>",
      "model": "<model>",
      "cost": { … },
      "status": "ok",
      "settlement": { "status": "unsettled", … },
      "receipt": "https://api.usdf.fi/v1/receipts/<request_id>"
    }
  ],
  "page": { "next_before": "<before>" }
}

Spend settles on-chain in batches. A receipt's settlement.status moves through these states:

StatusMeaning
unsettledCharged in the ledger. The spent USDF is still in the gateway's custody.
pendingIn a batch that has opened.
sentThe batch's transaction is broadcast.
confirmedMined. The USDF was burned and the same USDG paid out.

A batch runs hourly, or sooner once 50 USDF unsettled has built up. Its transaction burns the batch's spent USDF, releases the same USDG to the revenue wallet, and carries the batch digest and a log checkpoint in its calldata.

A settled receipt, settlement only

"settlement": {
  "batch": "<batch>",
  "status": "confirmed",
  "tx_hash": "<transaction hash>",
  "explorer": "…",
  "rows": "https://api.usdf.fi/v1/settlements/<batch>"
}

GET /v1/settlements lists batches. GET /v1/settlements/{batch} lists every row in one, with recomputed_digest and digest_matches, so anyone can check that the digest on-chain commits to exactly those requests.

Every request, keyed or paid per request, is a leaf in an RFC 6962 Merkle log. Its roots are anchored on-chain by the settlement transactions.

EndpointReturns
GET /v1/log/checkpointsThe roots anchored on-chain.
GET /v1/log/proof/{id}A request's leaf and its inclusion proof.
GET /v1/log/consistencyA consistency proof between two tree sizes, from and to.
GET /v1/log/frontierThe tree's current frontier.
GET /v1/log/leavesThe leaves themselves.

Check a request in the log

curl
curl https://api.usdf.fi/v1/log/proof/<request_id>
curl https://api.usdf.fi/v1/log/checkpoints

The log publishes figures, never content. See Data handling.

Three more public reads let anyone check the money:

EndpointReturns
GET /v1/audit/costsEvery charge recomputed from public inputs: the usage and the archived price sheet.
GET /v1/flowsEvery USDF and USDG movement the gateway claims, with its transaction.
GET /v1/reserveThe reserve, the supply and the gateway's custody, read from the chain.

Verify runs these checks in your browser against the chain. Transparency shows the same figures live.

A private-tier request is tied to the provider's own signed receipt. Its data_policy.attestation starts pending, then turns verified or failed.

GET /v1/privacy/receipts/{id}, with the same key, returns the provider's archived receipt byte for byte, with its hash. See Private inference.

Next: errors and status codes