When an autonomous AI agent pays for a metered API call over x402 or initiates a transfer through a server wallet, it is tempting to treat payment execution like a simple synchronous request.
In a typical x402 flow, an agent requests a paid resource and receives an HTTP 402 Payment Required challenge. The client creates a signed payment payload and retries the request; the resource server or facilitator verifies and settles the payment, then returns the HTTP response. (In a direct server-wallet flow, the wallet signs and broadcasts the transfer directly before or alongside the service call.)
That happy path is straightforward—until an illustrative distributed systems failure occurs: what happens if the request times out or the upstream server returns 500 / 502 Bad Gateway while the payment is in flight?
A timeout or HTTP error leaves the caller uncertain about whether onchain settlement actually occurred. If the retry loop creates a fresh payment authorization or submits a new transfer without resolving the original attempt, the agent risks paying twice for the same request (depending on the payment protocol, whether the original authorization is reused, and the executor's idempotency handling).
While building and testing execution adapters for OnChainDiligence (OCD), I kept coming back to this exact ambiguity: when an HTTP response is lost or fails, an application error log and a wallet status response do not give you a complete picture of what happened onchain. To investigate and recover safely without giving up control of your wallet keys, you need to separate the Payment Path from the Evidence Path.
Four Distinct Sources of Evidence in an Agent Payment
Instead of flattening an automated payment into a single "success: true" boolean, it helps to model the lifecycle around four distinct layers of evidence:
-
Declared / Mandated Intent: What the application proposed (
network,asset,amount,recipient, optionalresource) and the caller-supplied structured policy (max_amount, allowed networks/assets, expected recipient). -
Policy Decision: The deterministic preflight evaluation (
ALLOW,REQUIRE_APPROVAL, orBLOCK) recorded before the application invokes its payment executor. - Reported / Executed Claims: What the executor, wallet provider, or merchant HTTP response claimed happened—preserving whether a claim is caller-reported or a cryptographically signed provider webhook.
- Independently Observed Settlement: What an independent observer can establish from a supported blockchain (such as canonical Base USDC or Solana mainnet USDC) under explicit finality rules.
The architectural boundary: Your external wallet or payment provider holds the keys, enforces its own authorization rules, and signs the payment. OCD never custodies funds or broadcasts transactions; it evaluates preflight policy, observes supported settlement independently, and reconciles the evidence.
Evaluating Policy Preflight in TypeScript (@onchaindiligence/sdk@0.10.0)
You can test the preflight and evidence lifecycle in TypeScript without funding an OCD fee wallet or executing a live merchant payment. Authenticated workspaces include 100 completed free payment preflight evaluations per UTC month on canonical Base USDC (eip155:8453) and Solana mainnet USDC (solana:mainnet).
Install the SDK (Node.js 22+):
npm install @onchaindiligence/sdk@0.10.0
Using a workspace API key (OCD_API_KEY), you can open an operation, run a free-mode preflight check, and verify the returned preflight receipt:
import {
createCommerceClient,
BASE_USDC,
} from '@onchaindiligence/sdk/commerce'
import { NodeFileRecoveryStore } from '@onchaindiligence/sdk/commerce/node'
if (!process.env.OCD_API_KEY) {
throw new Error('Set OCD_API_KEY first')
}
const ocd = createCommerceClient({
accountApiKey: process.env.OCD_API_KEY,
preflightMode: 'free',
recovery: new NodeFileRecoveryStore('./ocd-recovery'),
})
const operation = await ocd.open({
action: {
kind: 'PAYMENT',
resource: null,
network: 'eip155:8453',
asset: BASE_USDC,
amount: '0.001',
sender: null,
recipient: '0x000000000000000000000000000000000000dEaD',
},
policy: {
max_amount: '0.01',
},
})
const evaluation = await operation.preflight()
if (!('receipt' in evaluation)) {
throw new Error('Preflight incomplete: ' + evaluation.kind)
}
const decision = evaluation.receipt.receipt.decision.status
const proof = await ocd.verifyReceipt(evaluation.receipt)
console.log('Policy decision:', decision)
console.log('Receipt verification:', proof)
// Stop here. No payment is executed.
How durable recovery helps when responses are lost
Notice NodeFileRecoveryStore in the client configuration above (for multi-instance or serverless deployments, a database-backed CommerceRecoveryStore should be used).
When a workflow moves from preflight to external execution and finalization, a timeout between submission and acknowledgment leaves the outcome ambiguous. Durable recovery preserves the original OCD operation identity and credentials across restarts so the application can inspect or finalize the existing attempt rather than blindly opening a new OCD operation. (Avoiding duplicate onchain transfers also depends on your executor's own recovery and payment idempotency handling.) When an execution outcome remains unresolved, it is surfaced as Needs attention / OUTCOME_UNKNOWN for investigation rather than treated as safe to re-send.
Inspecting a Real Base USDC Receipt
To see how these fields look after an external x402 payment settles on Base, you can inspect a real public receipt (OCD-RCP-NB51-QG4S-VCAN-Y57F) here:
https://onchaindiligence.com/r/OCD-RCP-NB51-QG4S-VCAN-Y57F
Each field in the receipt has a bounded meaning:
-
Proposed payment:
0.001 USDCon Base (eip155:8453). -
Preflight decision:
ALLOW(copied from the earlier signed preflight evaluation). -
Execution provider reference:
x402. -
Settlement:
CONFIRMED— OCD independently observed the supported transfer on Base and matched the network, canonical USDC asset, recipient, and amount against the preflighted proposal. -
Receipt signature:
VALIDunder the Ed25519 verifier contract. -
Service delivery:
NOT_CHECKED— OCD independently observed the recorded settlement, while theVALIDresult establishes receipt integrity and authenticity. Neither establishes that the API delivered the purchased service.
For teams building autonomous payment flows, keeping declared intent, executor claims, and independently observed settlement distinct makes post-timeout investigation concrete—before an agent retries an ambiguous call.
Technical documentation and the autonomous payment reference are available at onchaindiligence.com/developers.
Top comments (0)