On this page

Streaming & Usage Billing

Bill a stream in segments and settle its purchases periodically.

How streaming payments work#

The application sells service credit in increments and consumes it in units such as tokens, bytes or time slices. The buyer signs increasing cumulative purchase amounts. The merchant periodically claims its highest accepted voucher.

The contract needs transactions to settle; it does not send money by itself every second. Your application measures usage and executes the service. A payment does not prove that a model response or other provider work completed.

Purchasing service credit and billing each request
Purchasing service credit and billing each request

Choose a billing unit#

Define your unit, digest codec and price in the server's billing rules. Give each segment or batch a stable request ID. Its request signature authorizes that resource separately from the purchase voucher.

If the unit price is smaller than one atomic token unit, carry the remainder and round at purchase boundaries. Rounding each unit upward overcharges the stream. Signed payment amounts must remain unsigned integers in atomic units.

RecordWhat it tells you
Provider usage receiptThe provider's measured usage claim
Signed SessionRequest and debitOne resource unit was authorized and debited
Purchase VoucherCumulative earnings authorized for the merchant
Settled CreditValue settled and backed by the payment rail
Pool settlement receiptReturned assets reserved for a private note

Pause and reconnect#

Pause new billable segments when credit runs out, policy expires or closing starts. Ask for another purchase authorization. If capacity is too small, wait for a separately approved top-up to confirm first.

On SSE reconnect, reuse the accepted segment's billing identity. Resume its job from cached output or a saved cursor so a connection failure does not create another charge.

Accept a segment#

Wrap the buyer and merchant managers in your transport. The example accounts for one segment. Your application still computes the digest, checks server pricing and keeps a job ledger to prevent repeated execution.

javascript
const requestId = `${streamId}:segment:${segmentIndex}`;
const bundle = await buyer.prepare({
  requestId, requestDigest: segmentDigest, amount: segmentPrice,
});
const debit = await merchant.receive(bundle, {
  requestId,
  requestDigest: independentlyComputedSegmentDigest,
  amount: independentlyComputedSegmentPrice,
});
// Commit or resume the durable segment job, then deliver cached/new bytes.
// A debit receipt is not proof that delivery succeeded.

Monitor settlement#

Leave time to claim before the close window ends, accounting for stale RPC reads, confirmation lag and worker outages. All transports serving one merchant session must share its accounting ledger, including request deduplication records.

The SDK has no HTTP/SSE gateway or Tempo/MPP adapter. If you need those protocols, implement and test their challenges, credentials and receipts against the payment backend. Changing a contract address alone will not make them compatible.

Save the stream state#

Before the first segment, configure a funded session and saved manager policy, then create a durable stream job. Its ID and segment indices or batch boundaries must survive reconnects. Store the digest and price for each boundary.

The buyer authorizes a segment and the merchant checks its content and price before delivery. After the debit commits, save a resumable job state. If delivery then fails, resume that segment rather than assigning it another billing ID.

PhasePayment stateApplication state
ReadyA funded open session with saved policyThe stream job is saved
PreparedBuyer budget reserved and authorization savedContent and price set for the segment
AcceptedMerchant debit committed onceThe segment job can run or resume
DeliveredNo additional debitOutput and delivery cursor saved
PausedCredit ran out, policy expired or closing beganNew billable segments stop
SettledThe highest accepted voucher was claimedThe service receipt is kept separately

Carry fractional charges#

Meter sub-atomic prices in an agreed finer scale, keeping the remainder until a purchase boundary produces an integer payable amount. Include that scale in the service terms and the request data the server checks.

The read-only function below shows that arithmetic. The SDK requires positive SessionRequest amounts, so collect a large enough batch before authorizing it; a zero-priced result from the function cannot be sent as a request.

javascript
function meterBatch({ units, priceNumerator, priceDenominator, remainder = 0n }) {
  if (units < 0n || priceNumerator < 0n || priceDenominator <= 0n) {
    throw new Error("Invalid agreed billing scale");
  }
  const scaled = units * priceNumerator + remainder;
  return {
    amountAtomic: scaled / priceDenominator,
    remainder: scaled % priceDenominator,
  };
}
// 3 units at 1/10 atomic unit each retain 3/10 as a remainder.
const first = meterBatch({ units: 3n, priceNumerator: 1n, priceDenominator: 10n });
// A later 7-unit batch reaches exactly one atomic unit.
const next = meterBatch({
  units: 7n, priceNumerator: 1n, priceDenominator: 10n,
  remainder: first.remainder,
});
console.log(next.amountAtomic.toString(), next.remainder.toString());

Coordinate workers and shutdown#

Use the same merchant store to serialize acceptance across stream and API workers. Otherwise, two workers can both see the same credit as available. The chain tracks cumulative Voucher amounts, not which resource request has already used that credit.

At shutdown, stop new segments and save active cursors before stopping the settlement worker. Arrange for a supervised process or restart to continue watching the close window. A timer in a stopped process cannot submit a claim, and passing onchain time does not run a keeper.

Receive settled value privately#

Settled Credit is an ERC-20 backed by assets in the payment rail. Deposit it through the Pool's existing guarded admission flow to obtain a Credit note. An admitted redemption adapter can return underlying assets to the Pool for a measured settlement note.

Create the Deferred Note only from assets actually returned by that route. Usage receipts and future earnings cannot fund it. Shared-Pool route admission and HTTP integration still need their own deployment and funded end-to-end tests; contract tests cover only the contract part.