Payments & connected services https://docs.hazbase.com/en/patterns/payments/ IMPLEMENTATION PATTERNS Payments & connected services Connect usage and payment with wallet integration and x402. ← All implementation patterns EXAMPLE Unlock an equipment-report API after payment An equipment-report API returns x402 payment terms. After the user reviews and pays them, the service grants access to the report. Your service manages products, orders and access rights, while hazBase handles the wallet payment integration. Build a select, review, pay and access flow, with repeat access tied to the same order. Architecture and responsibilities 0 1 Report API and orders Bind price, payment asset, recipient and expiry to the report. Merchant backend / Order DB 0 2 Payment-term handling Select supported chains and assets and display terms for review. @hazbase/kit/x402 0 3 Authentication and payment Submit payment with an authenticated session and operation authorization. @hazbase/kit/wallet / @hazbase/auth 0 4 Settlement and access Verify payment against the order server-side and grant access once. Payment verification / Access DB Example data model Map application records to the data managed by the chain or APIs. Field names and values below illustrate the application model for this architecture. Field and example Stored in Purpose and mapping orderId / resourceUrl ORDER-001 / report URL Your server Order and canonical report URL, associated with the purchaser’s session. paymentRequestId issued request ID Payment request Use an ID issued by the connected payment service, not an arbitrary string sent to the payment API. network / asset / payTo eip155:… / 0x… / 0x… Order and request Allowed chain, token and merchant recipient, checked against your configuration. amountAtomic 1000000 Order and request Amount in atomic units: 1,000,000 represents one unit for six decimals. Distinguish this from fiat-currency amounts. paymentAttemptId / status attempt ID / settled Payment API and DB Persist the attempt ID after submission and check that attempt’s completion status. accessGrant orderId + memberId Your DB Access permission for the order, protected against duplicate grants by a unique constraint. Processing flow 1 Create a payment request for the order Return payment terms for the report request. Payment-request creation and merchant configuration follow the connected service’s integration contract. The Wallet SDK used here does not register arbitrary merchant orders. Merchant API → HTTP 402 / paymentRequestId 2 Validate and display the terms Parse the response and check chain, asset, recipient, resource URL and amount limit against policy. Display the report and amount and obtain the user’s payment confirmation. summarizeX402Request / isX402RequestExpired 3 Pay with an authenticated wallet Obtain emailSession, smartAccountAddress, deviceBindingId and highTrustToken through the authentication flow. Send the approved amount and recipient as expectedAmountAtomic and expectedPayTo. payX402WithHazbaseWallet(input) 4 Track the same payment attempt If processing continues, retain paymentAttemptId and query its status. Distinguish submitted, verified and settled states; a slow response must not trigger a new payment. getX402HazbaseWalletPaymentStatus({ emailSession, paymentRequestId, paymentAttemptId }) 5 Verify on the server and grant access The merchant server verifies trusted payment status or proof against the order, purchaser, amount, asset and recipient. Save access using a DB transaction and unique constraint, then return the report. Server payment verification → accessGrant → report response Before using the code Provide a valid paymentRequestId issued by the connected service and its supported chain, asset and merchant recipient. Integrate a payment confirmation screen and the session, device registration and operation authorization required by the Wallet API. Keep authentication tokens out of logs, URLs and public configuration. Pass values from that user’s authentication flow in auth. Install npm install --save-exact @hazbase/kit@0.9.0 ethers@6.16.0 The TypeScript functions below are called from your application with the appropriate connections, permissions and data. Integrate the UI, persistence and recovery using the architecture above. Inspect payment terms and submit the approved request Use inspectReportPayment to extract the terms, display them for confirmation, then call payApprovedReport. payload is the JSON from the payment service; policy contains your service’s accepted terms. pattern-payments.ts 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import { summarizeX402Request , isX402RequestExpired , type HazbaseX402Request } from '@hazbase/kit/x402' ; import { createHazbaseWalletClient , type PayX402WithHazbaseWalletInput } from '@hazbase/kit/wallet' ; import { getAddress } from 'ethers' ; export function inspectReportPayment ( payload : Record < string , unknown > , resourceUrl : string , policy : { network : string ; asset : string ; payTo : string ; maxAmountAtomic : bigint } , ) { const request = summarizeX402Request ( payload , { sourceUrl : resourceUrl } , { networks : [ policy . network ] , assets : [ { address : policy . asset } ] , requirePayTo : true , } ) ; if ( ! request ) throw new Error ( 'Unsupported payment request.' ) ; const terms = request . requirement ; if ( terms . resource !== resourceUrl || getAddress ( terms . payTo ) !== getAddress ( policy . payTo ) ) { throw new Error ( 'Payment does not match the requested service.' ) ; } const amount = BigInt ( terms . amountAtomic ) ; if ( amount <= 0n || amount > policy . maxAmountAtomic ) throw new Error ( 'Amount is outside policy.' ) ; if ( isX402RequestExpired ( request , Date . now ( ) ) ) throw new Error ( 'Payment request expired.' ) ; return request ; } export async function payApprovedReport ( request : HazbaseX402Request , auth : Pick < PayX402WithHazbaseWalletInput , 'emailSession' | 'smartAccountAddress' | 'deviceBindingId' | 'highTrustToken' > , ) { // Call only after the user confirms the displayed resource and payment terms. if ( isX402RequestExpired ( request , Date . now ( ) ) ) throw new Error ( 'Payment request expired.' ) ; const wallet = createHazbaseWalletClient ( ) ; return wallet . payX402WithHazbaseWallet ( { ... auth , paymentRequestId : request . paymentRequestId , expectedAmountAtomic : request . requirement . amountAtomic , expectedPayTo : request . requirement . payTo , waitForReceipt : false , } ) ; } Download the example Result and application integration Retain paymentRequestId and paymentAttemptId to track status. Do not grant access based only on a paid: true value supplied by the frontend; use merchant-server verification. Implementation considerations Display amounts and expiry Compare atomic amounts as well as display values. The SDK expiry check is a receipt-time guard; the server must also validate the order’s absolute expiry. Duplicate payments and access grants After a timeout, query the existing attempt and retain payment state per order. Repeated completion notifications must not create duplicate access grants. Recipient or resource substitution Compare resource URL, asset, chain and recipient with the canonical order. Check the association between the authenticated buyer and request ID on the server. Extending the architecture Metered and recurring access Extend a single report purchase to usage allowances or time-limited access. Your service’s authorization model defines how many uses each payment permits and for how long. Wallet extension integration You can publish the x402 request on the page and hand it to a compatible wallet. Even when the wallet handles payment UI, the merchant server remains responsible for order verification and access. Related API and SDK reference summarizeX402Request PayX402WithHazbaseWalletInput Wallet payment API Authentication / Wallets Start with the sample application Deployment and operations