Accept a one-shot payment
The full happy-path for charging a customer once.
You want to charge a customer one time for one thing. Here's the entire flow, with both server and client code.
Server: create the session
metadata is round-tripped to your webhooks unchanged. Use it to correlate Strimz sessions back to your own resources.
Client: redirect to checkout
That's the entire client side. The customer lands on
https://checkout.strimz.finance/pay/<sessionId>, picks a wallet (Reown handles the
picker for every major one), and approves two signature prompts: an
EIP-3009 ReceiveWithAuthorization for the token, and the Strimz PayIntent.
Neither prompt is a transaction. Strimz's relayer turns the two
signatures into the on-chain payWithAuthorization call, pays the gas
itself, and settles the transfer. The customer never pays gas. The fee split (platform fee to
FeeCollector, net to your payout) lands atomically in the same
transaction.
The full security model lives on the meta-tx flow page: what the customer signs, why the relayer cannot move funds on its own, how the signature expires.
Webhook: react when it confirms
Don't trust the redirect to successUrl for state changes. Anyone can navigate to that URL. The webhook is the source of truth.
The handler runs on your server. It verifies the raw request body before parsing it, and it awaits verifyWebhookSignature, which resolves to { valid: true } or { valid: false, reason }:
Edge cases to know about
- Session expiry: 30 minutes by default (set
expiresInMinutes, up to one day). If the customer doesn't pay in time, the session goes toexpiredand you'll receivepayment.failed. Create a new session. - Customer changes their mind mid-checkout: they hit the back button, you see no webhook. Don't fulfill until you receive
payment.completed. The session stayscreatedorawaiting_paymentuntil it expires. - Customer pays the same session twice: the token authorization's nonce is derived from the session id, so the token contract rejects a second authorization for the same session.
- Finality: Arc has deterministic finality. The indexer stays
CONFIRMATIONSblocks behind the chain head (required;1is recommended), so aconfirmedsession doesn't flip back.
What just happened on-chain
The customer's wallet signed an EIP-3009 authorisation. Strimz's
relayer wrapped it into a StrimzPayments.payWithAuthorization call
and broadcast the transaction. Arc settled it in under a second.
Your payoutAddress received amount - feeAmount USDC immediately.
The indexer picked up the PaymentExecuted event, matched its
ref to your PaymentSession.id, inserted a
Transaction(kind=one_shot, status=confirmed), and fired
payment.completed. End to end (the click to your webhook handler)
takes about 20 seconds.

