Payment Sessions
Buy service credit in increments and sign each resource request.
Purchase and request signatures#
A purchase voucher authorizes cumulative merchant earnings for the session. The merchant claims it to settle onchain. A SessionRequest signature authorizes one resource request, with its ID, digest, price and deadline.
Claimed vouchers become public and anyone can relay them. Require the separate request signature to authenticate the customer; seeing a voucher is not proof that a caller can use their credit.
Configure the funded session#
Session terms identify chainId, core, asset, merchant, voucherSigner, sessionId and maxDeposit. Manager policy sets the service budget, purchase increment, request TTL, expiry and settlement behavior. Each operation checks funded state against that configuration.
Use decimal strings in the asset's base units. The budget must fit maxDeposit. Request preparation only creates authorizations and records accounting; token approval, funding and transaction submission happen separately.
Prepare and accept a request#
Configure the buyer and merchant managers first. Compute a digest of the resource and request body, then calculate the price from the server's billing rules. Keep the same request ID when retrying the same work.
// buyer and merchant are createSessionManager(...) instances.
const bundle = await buyer.prepare({
requestId: "job-42", requestDigest, amount: "10",
});
const receipt = await merchant.receive(bundle, {
requestId: "job-42",
requestDigest: serverComputedDigest,
amount: serverComputedPrice,
});
// Use the application's own durable job ledger before executing work.
// A repeated debit receipt should resume or return the same job result.Settle a voucher#
The merchant can settle its highest accepted voucher directly or let the manager worker do it. Once closing starts, stop new requests. Existing earned vouchers can still be claimed during the contract's close window.
At final closure, unclaimed deposit value goes back to the payer. Signing a purchase authorizes merchant earnings during that claim window. Unused purchased service credit follows the application's refund policy.
Fund the session#
For public funding, call openSession on a payer-connected createEthersBackend with merchant, voucherSigner, amount and a fresh salt. Approve token allowance first. The transaction sender is the payer; plain transfers to the rail contract do not open or top up a session.
For private funding, use the driver for the deployed factory. Its prepare result gives the withdrawal recipient and amount. Authorize that Pool withdrawal separately, wait for arrival and activate the escrow. Attach the driver to a manager with matching rail, session ID, authority and budget; the SDK does not build the withdrawal witness.
Save the manager policy#
Save policy when configuring the session, then reload those values after a restart. expiresAt stops application acceptance. Voucher claimability is governed separately by the core's close window.
Each purchase increment authorizes cumulative earnings. For a large reservation where only the measured cost should be captured later, use the Authorization rail. Signed Session purchases do not automatically refund unused service.
// Example for a reviewed six-decimal asset. Persist this policy once.
const policy = {
budget: "1000000", // 1 display unit of service purchases
purchaseStep: "100000", // purchase in 0.1-unit increments
requestTtl: "60",
expiresAt: String(configuredAt + 3600),
settlementInterval: "30",
broadcastTimeout: "300",
autoClose: false,
autoFinalize: true,
};
// terms.maxDeposit must cover policy.budget, and the session must be funded.Track purchases and usage#
The buyer records its signed purchases and reserves budget for prepared requests. The merchant records accepted purchases, debited requests and available service credit. The chain records deposits, claims and closure. Keep those amounts visible with their own meanings.
A prepared request keeps its buyer reservation even if it is never delivered. A merchant debit also remains after a provider failure. Store the application job and decide whether to resume it, return cached output or apply your refund policy.
Claim before the close window ends#
Stop accepting new work when closing starts. Claim the latest accepted voucher before closeAt. After that boundary, final closure refunds the unclaimed deposit, including signed value the merchant failed to claim in time.
Closing cannot revoke earnings already settled. Claims are cumulative: a higher voucher settles only the amount above earlier claims. Check rail state when a competing relayer succeeds; its claim has already changed what remains payable.
Restart and retry#
Reopen both original durable stores and recover the managers. Reuse the job ID, content digest and price for the same request. Changed content under that ID fails; an expired request can receive a renewed signature while policy still permits it.
The payment ledger deduplicates debits. Your application must also deduplicate provider work. Commit a stable job record and use provider idempotency or cached output for repeated requests, keeping that job associated with its payment receipt.