Skip to content

Architecture proposal: storefront paid chat via x402 batch-settlement channels #671

Description

@bussyjd

Context

Issue #669 proposes an A2UI-style storefront surface contract for safe storefront customization. That issue is about the presentation layer: how sellers configure profile, layout, sections, theme, and safe public UI components.

This issue covers a different layer: the paid interaction runtime for a public Hermes-agent chat experience where users can connect a wallet, authorize/deposit enough for multiple turns, and then chat smoothly without a wallet prompt or onchain transaction per message.

References:

Problem statement

A one-transaction-per-turn or one-wallet-prompt-per-turn chat UX is not acceptable for a public storefront chat experience.

The user expectation should be closer to:

I connect my wallet, allow or deposit enough for up to N turns, then chat with the seller agent normally. I can see remaining capacity and recover/refund unused funds according to the channel rules.

Obol currently has strong support for exact x402 payment flows, including buyer-side pre-signed exact auth pools for buyer agents. That is useful for agent-to-agent or buyer-side routing, but it is not the right end-user storefront UX for a public chat surface. The storefront needs a repeated-payment flow optimized for many small paid requests.

x402 batch-settlement is the right protocol direction for this because it is designed for high-throughput repeated payments: the buyer deposits into escrow once, signs off-chain cumulative vouchers per request, the seller verifies those vouchers quickly, and a channel manager claims/settles/refunds onchain later.

Non-goals

  • Do not implement arbitrary seller-side credit accounting as the target design when x402 batch channels can represent the spending cap more directly.
  • Do not use upto as the primary multi-turn chat scheme. upto is useful for a single variable-cost request, not an N-turn session.
  • Do not put payment verification, channel management, or settlement behavior into the A2UI/storefront customization schema from Architecture proposal: customizable public storefront via A2UI-style surface contract #669.
  • Do not expose Hermes or the Obol internal frontend directly to the public internet.
  • Do not require token-metered dynamic pricing in the first version. A flat per-turn price is enough for the first POC.

Target UX

A first useful UX could be:

  1. User opens seller storefront.
  2. Storefront shows a Hermes-backed chat service with price per turn/request.
  3. User connects wallet.
  4. User chooses a budget preset such as 5 turns, 20 turns, or 100 turns.
  5. x402 batch client opens or tops up a channel by depositing approximately pricePerTurn * selectedTurns, subject to client-side caps.
  6. User sends chat messages without wallet prompts per turn.
  7. Each paid turn carries a signed cumulative voucher.
  8. Storefront shows remaining channel capacity and recovery/refund actions.
  9. Seller channel manager periodically claims, settles, and refunds idle channels according to policy.

The key product promise is: one deposit/top-up interaction, smooth paid conversation afterwards.

Proposed architecture

flowchart TD
  UI["Public storefront / PaidAgentChat component"] --> Client["x402 batch-settlement client"]
  Client --> Wallet["User wallet"]
  Client --> Deposit["Escrow channel deposit or top-up"]
  Client -->|"signed cumulative voucher per turn"| Gateway["Obol storefront paid-chat gateway"]
  Gateway --> Verifier["x402 batch-settlement verifier"]
  Verifier --> Storage["Channel storage"]
  Gateway --> Hermes["Hermes agent API / stream"]
  Manager["Channel manager"] --> Storage
  Manager -->|"claim / settle / refund"| Deposit

  Surface["#669 storefront surface"] --> UI
Loading

Layering with #669

Issue #669 should remain the presentation-layer architecture. It can expose safe UI components and data bindings such as:

  • PaidAgentChat
  • ServiceChatPanel
  • PaymentStatus
  • ChannelBalance
  • RefundAction

But the actual payment behavior should live in this architecture track:

  • ServiceOffer payment scheme support
  • x402 batch payment requirements
  • client deposit and voucher signing
  • server voucher verification
  • channel storage
  • channel manager claim/settle/refund
  • Hermes chat proxying

In other words, #669 can decide how the paid chat component appears. This issue decides how the paid chat component is paid for and authorized.

Payment model

Use x402 batch-settlement for Hermes chat routes.

Initial pricing model:

  • Flat price per accepted chat turn/request.
  • Route price is the per-turn maximum.
  • The client deposit policy maps user-facing presets to channel capacity, for example:
    • 5 turns ~= price * 5
    • 20 turns ~= price * 20
    • 100 turns ~= price * 100
  • Avoid token-metered settlement overrides in the first POC.

Later pricing options:

  • Charge less than max with settlement overrides for failed or discounted turns.
  • Token-metered pricing for model output, where the route price remains the per-request maximum.
  • Separate prices for model tiers or service categories.

Request flow

1. Discovery / storefront rendering

The storefront service catalog should expose enough metadata for a chat UI to know that the service supports batch-settlement:

  • service name and route
  • chat capability flag
  • network
  • asset/token
  • per-turn maximum price
  • supported payment schemes including batch-settlement
  • deposit presets or recommended deposit multiplier
  • refund/recovery capability

This metadata can be consumed by the #669 storefront surface renderer, but payment semantics should remain sourced from ServiceOffer/payment configuration rather than arbitrary storefront config.

2. Channel open/top-up

When the user chooses a budget preset, the browser x402 client should open or top up a channel using the batch-settlement client SDK.

The user-facing text should be phrased as a spending budget or turn capacity, not as an internal protocol term:

  • “Deposit for up to 20 turns”
  • “Add 20 chat turns”
  • “Allow up to 20 paid turns”

The underlying protocol operation is channel deposit/top-up.

3. Paid chat turn

For each chat request:

  1. UI sends the message through the x402 batch-aware client.
  2. Client includes a signed cumulative voucher for the channel.
  3. Obol paid-chat gateway verifies the voucher against channel state.
  4. If valid, gateway proxies to Hermes and streams the response.
  5. On success, server records the latest accepted voucher/channel state.
  6. Response includes payment/channel status so the UI can update remaining capacity.

For the POC, charge one flat turn once the request is accepted and Hermes begins producing a response. More nuanced partial-failure behavior can come later.

4. Claim / settle / refund

A seller-side channel manager must run periodically to:

  • claim latest vouchers from many channels
  • settle claimed funds to the receiver
  • refund idle channels when appropriate

The withdrawDelay must be configured with enough safety margin relative to claim cadence so outstanding vouchers can be claimed before a payer withdrawal can finalize.

Obol implementation areas

ServiceOffer API and CRD

Current ServiceOffer payment configuration is effectively exact-only. Add first-class scheme support for batch settlement.

Likely changes:

  • Extend ServiceOfferPayment.scheme enum to include batch-settlement.
  • Preserve scheme through internal route payment configuration.
  • Add batch-settlement-specific public payment fields, such as receiver authorizer, withdraw delay, and asset transfer method.
  • Keep existing exact flow working unchanged.

x402 payment requirements

Add a builder path for scheme: batch-settlement payment requirements.

The requirement should include all fields needed by x402 clients to open/top-up channels and submit vouchers, including the batch-settlement extras required by the EVM implementation.

Paid chat gateway

Introduce or extend a public route that:

  • accepts batch-settlement x402 payments/vouchers
  • verifies channel/voucher state
  • proxies accepted requests to Hermes
  • streams responses back to the browser
  • reports payment/channel state in response metadata

This gateway should expose only the intended chat surface, not the full Hermes API or internal Obol services.

Channel storage

Server storage must persist latest voucher and channel state.

Suggested phases:

  • POC single-node: file storage on a PVC or equivalent durable local storage.
  • Multi-instance/serverless: Redis/Valkey storage with atomic channel updates.

Avoid process-local in-memory storage except for unit tests and demos because outstanding vouchers must survive restarts.

Channel manager

Add a runtime component responsible for claim, settle, and refund loops.

Open implementation questions:

  • Should this run inside the existing serviceoffer-controller, as a separate deployment, or as a sidecar to the x402 verifier/gateway?
  • How should receiver authorizer keys be generated, stored, rotated, and backed up?
  • What default claim/settle/refund cadence is safe for Base Sepolia and mainnet?

Storefront client integration

The public storefront needs a lightweight wallet/payment client path:

  • wallet connect
  • x402 batch client registration
  • channel open/top-up
  • voucher signing per chat request
  • corrective 402 recovery
  • refund action
  • remaining capacity display

This should be implemented as part of the storefront chat component, while keeping the payment data model sourced from ServiceOffer/payment metadata.

Security and correctness constraints

  • Per-channel updates must be atomic to avoid accepting conflicting vouchers concurrently.
  • Server must serialize or lock request handling per channel where required by the batch-settlement scheme.
  • Channel storage must be durable before this can be used beyond demos.
  • Receiver authorizer private keys must be managed as secrets, not frontend config.
  • Deposit presets should have client-side and server-side caps to prevent accidental over-deposit.
  • Public gateway must not expose arbitrary Hermes tools, host filesystem access, or admin APIs.
  • Streaming failure behavior must be defined before charging partial or dynamic amounts.
  • Refund and recovery flows must be visible enough that users understand unused funds are not trapped.

Why not the alternatives?

Exact turn pack + seller ledger

This is simpler, but it creates seller-side credit accounting. It may still be useful as a stepping stone, but it is less protocol-native than batch-settlement for repeated paid turns.

Upto

upto is useful when a single request has unknown final cost and the server needs to settle less than or equal to a signed maximum. It does not give the desired multi-turn channel UX by itself.

Existing buyer-side pre-signed auth pool

Obol’s buyer-side stored signed auths are useful for buyer agents making paid model calls, but they do not map cleanly to a public browser storefront where a human wants one smooth wallet interaction followed by many chat turns.

Suggested implementation phases

Phase 1: Architecture spike

  • Confirm x402 Go SDK version and batch-settlement support needed by Obol.
  • Identify exact CRD/API shape for scheme: batch-settlement.
  • Decide where the paid-chat gateway and channel manager should run.
  • Decide storage backend for POC.
  • Decide POC pricing model: flat per accepted chat turn.

Phase 2: Minimal batch-settlement route

  • Add batch-settlement payment requirement generation for one protected HTTP route.
  • Add channel storage and manager using the simplest durable backend.
  • Add integration tests for deposit, voucher verification, claim, settle, and refund where feasible.
  • Keep exact routes unchanged.

Phase 3: Hermes chat POC

  • Add a single storefront chat service backed by Hermes.
  • Add wallet connect and batch-settlement client setup in the public storefront.
  • Let user select a turn budget and open/top-up a channel.
  • Send signed vouchers per chat turn.
  • Stream Hermes responses.
  • Display remaining channel capacity.

Phase 4: Storefront surface integration

Phase 5: Production hardening

  • Redis/Valkey channel storage for multi-instance deployments.
  • Receiver authorizer key rotation and backup guidance.
  • Metrics for accepted vouchers, claim lag, settlement lag, refunds, failed verifications.
  • Better dynamic pricing/settlement overrides if needed.
  • Mainnet-ready defaults for claim/settle/refund intervals.

Open questions

  • Should the first paid chat route charge per submitted user message, per successful assistant response, or per full request/response cycle?
  • Should the POC use file storage on PVC or go directly to Redis/Valkey?
  • Should the channel manager run in the existing controller or a separate deployment?
  • How should the public storefront describe refund timing and idle channel behavior to users?
  • Which wallet stack should the public storefront use for the POC?
  • Do we need SIWX for identity display/session binding, or is the batch channel payer identity sufficient for the first version?
  • How should retries and duplicate chat submissions be handled for streamed responses?

Acceptance criteria for the architecture direction

  • Team agrees that x402 batch-settlement is the target scheme for storefront paid chat.
  • Team agrees Architecture proposal: customizable public storefront via A2UI-style surface contract #669 remains the presentation/customization layer and this issue owns payment/session runtime.
  • Team agrees on the first POC pricing model and storage backend.
  • Team agrees on the Obol components that must own channel verification, storage, and channel management.
  • A follow-up implementation plan can be split into CRD/API, backend verifier/channel manager, and frontend wallet/chat work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions