# BSVKey usage receipts (v1)

A signed, content-addressed receipt for every metered inference call, so a client
can audit the broker's meter **offline, later, with nobody watching**.

## The problem

A prepaid channel is funded by one on-chain transaction, so the *payment* is
verifiable. But each call then draws down that balance off-chain, and the
per-token **count is the broker's word**. A bare signed number only proves "the
broker asserted N"; it does not prove the numbers add up.

To audit the meter without asking the broker, a client must be able to decide
three things on its own:

1. **This claim is for my channel and no other.** (channel binding + signature)
2. **This claim has not been counted before.** (a monotonic sequence number)
3. **The sum of all claims matches what the channel has actually paid out.**
   (running cumulative totals, bounded by the funded amount)

## The receipt

Every settled call returns a `usageReceipt`. Its **signed body** is:

| field | meaning |
|---|---|
| `v` | schema id, `bsvkey.usage-receipt/1` |
| `channelId` | the channel this call drew down (binding) |
| `seq` | monotonic per channel, 1-based, no gaps |
| `model` | model actually run |
| `inputTokens`, `outputTokens` | metered tokens for this call |
| `sats` | sats charged for this call |
| `cumTokens`, `cumSats` | running totals over the channel, **after** this call |
| `fundedSats` | the channel's on-chain funded amount (conservation cap) |
| `timestamp` | ISO 8601 |

Plus three verification credentials (not part of the signed body):

- `claimId` = `0x` + `sha256(canonical(body))`, where `canonical` is JSON with
  object keys sorted recursively (rail-neutral content addressing, identical to
  `bsv-capacity-attest`).
- `signature` = a compact, recoverable **Bitcoin Signed Message** signature over
  `claimId` (secp256k1, the same primitive as the payment channel, different
  envelope). BSM is a legacy compat API; a future version may move to BRC-77.
- `brokerPubKey` = the broker key, carried for convenience. **Not trusted**:
  verification recovers the signer from the signature itself and pins it to the
  broker's published key.

Pin the broker's key once from **`GET /v1/receipt-key`**.

## Verifying (offline, no broker round-trip)

For each receipt:

1. `claimId == 0x + sha256(canonical(body))`.
2. Recover the public key from `signature` over `claimId`; it must equal the
   pinned broker key from `/v1/receipt-key`.
3. `channelId` is yours.

Across the channel's receipts, sorted by `seq`:

4. `seq` is exactly `previous + 1` (no gap, no replay).
5. `cumSats == previous cumSats + sats`, and `cumTokens == previous cumTokens +
   inputTokens + outputTokens`.
6. `cumSats` never exceeds `fundedSats`.

If all hold, you have non-repudiable proof the broker committed to these exact
numbers, that none were double-counted, and that the totals reconcile and stay
within what you funded.

A reference verifier (`verifyReceipt`, `verifyReceiptChain`) is in
`src/payments/usage-receipt.js`; it needs only `@bsv/sdk`.

## What this does and does not prove

- **Proves:** authorship (the broker signed these numbers and cannot repudiate
  them), no replay or gaps, and internal + funded conservation.
- **Does not prove:** that the token counts equal the model's true usage. That is
  still the broker's meter. This scheme shrinks the trust surface to "the
  broker's signed, sequenced, conserved numbers"; it does not remove it.

The on-chain channel funding remains independently verifiable, and (optionally)
each receipt's `claimId` can be anchored on-chain for a tamper-evident timestamp.
