/verify
validates an authorization at that moment; it does not reserve the customer’s
funds or guarantee that a later /settle will succeed.
Exact payments: confirm before inference or streaming
An attacker can sign an authorization that expires shortly after verification. If your server verifies, runs inference, streams the result, and only then tries to collect, the payment may already have expired. Keeping a sufficient token balance does not prevent this attack. For costly exact-payment endpoints:- Match the payment to your server-controlled network, asset, recipient, amount and resource requirements. Do not let the client choose the terms you verify.
- Call
/verifyand requireisValid: true. - Immediately call
/settlewith that same payment and requirements. Wait for the confirmed successful outcome before starting inference, irreversible effects, or any paid response bytes. - If the outcome is pending or unknown, keep the application operation pending too. Preserve the original payload and transaction identity, then follow settlement recovery.
settlement_pending,
duplicate_settlement, and a lost response require reconciliation. Do not
start a replacement payment merely because the original authorization expired:
the original transfer may already have landed.
EVM: use the signed expiry
For EIP-3009, inspect the signedauthorization.validBefore. For Permit2, inspect
the signed permit2Authorization.deadline and any required sponsored approval’s
expiry. maxTimeoutSeconds in your requirements is not proof that the client
signed that much remaining lifetime.
PayAI’s default EVM verification buffer is approximately six seconds. This is a
settlement buffer, not a promise that an authorization will survive your handler.
If you enforce a longer resource-specific margin, allow for verification,
queueing, transaction inclusion and clock skew, and configure compatible clients.
A 120-second floor is useful defense in depth, but does not secure a longer
stream or reserve the wallet’s balance. Confirm exact payment before costly work.
Solana: validity now is not remaining lifetime
PayAI verifies the original signed blockhash through simulation. An expired blockhash is rejected, but a nearly expired one may still pass.isBlockhashValid also returns
only current validity, not remaining lifetime.
For a resource-specific freshness policy:
- Retain a trusted
{blockhash, lastValidBlockHeight}pair fromgetLatestBlockhashor a trusted facilitator response. - Decode the signed transaction and match its actual blockhash to that stored pair. An unsigned client-supplied height is not authoritative.
- Compare the stored height with
getBlockHeightfrom a healthy RPC at consistent commitment. Require enough remaining blocks for your settlement path. Reject unknown or stale hashes under this policy and obtain a fresh signed payment only when no prior payment is unresolved.
/supported blockhash hints do not force clients to use them; a freshness policy
must check the actual signed hash. Replacing that hash invalidates the payer’s
signature. For exact payments, confirm settlement before work:
sendTransaction only
acknowledges submission.
Funded channels: reserve before work, redeem afterward
Funded batch settlement does not defer a separate EIP-3009 transfer or signed Solana transaction for every resource request. Its per-request vouchers avoid this specific authorization/blockhash expiry issue, so the exact-payment advice to settle each request before inference does not apply to funded vouchers. The initial deposit or a top-up can still expire or fail. Confirm funding before treating it as spendable channel capacity. Validate the channel’s current state, reserve request capacity atomically across replicas, retain authorization and voucher records, and redeem within withdrawal grace. Pending funding, an exhausted channel, or a closing channel is not permission to keep serving. Follow the Solana batch guide or EVM batch guide for metered charges, durable storage, payout and closure. Internal batching of severalexact transfers into
one on-chain transaction does not turn them into funded payment channels.
