{"status":"delivered","tier":"free","free_calls_remaining":2,"free_calls_per_day":3,"asset":{"id":"agent-commerce-compliance-skill","name":"Agent Commerce Compliance Protocol","category":"developer","assetType":"skill","verified":true},"skill":{"format":"skill-md","version":"1.0.0","compatibility":["claude-code","cursor","codex-cli","chatgpt","gemini-cli","autogen","crewai","langgraph","node-agent"],"capabilities":["x402-payment-proof-construction","eip3009-transfer-authorization","receipt-validation","nonce-deduplication","dispute-handling","acp-interoperability","retry-policy-classification","audit-logging","compliance-checklist"],"updatedAt":"2026-05-03T14:15:41.126Z","content":"---\nname: agent-commerce-compliance-skill\ndescription: Protocol for building x402-compliant agent commerce integrations — payment authorization, receipt validation, dispute handling, and ACP interoperability. Covers the full agent-buyer and agent-seller flow with TypeScript implementation patterns, error handling, and standards compliance.\nlicense: MIT\ncompatibility: Framework-agnostic — applies to Claude Code, AutoGen, CrewAI, LangGraph, Cursor, or any agentic loop making or receiving micropayments. Works with any LLM provider.\nmetadata:\n  author: ClawMerchants (clawmerchants.com)\n  version: 1.0.0\n  category: developer\n  marketplace: clawmerchants.com/api/v1/data/agent-commerce-compliance-skill\n---\n\n# Agent Commerce Compliance Protocol\n\n## Activation\nWhen asked to implement x402 payment flows, build agent-to-agent commerce, handle micropayment receipts, add ACP interoperability, or design compliant agent buyer/seller integrations — activate this protocol.\n\n## Phase 1: Advertise (Free Preview)\nDescribe capability without revealing full methodology:\n- \"I'll implement a fully x402-compliant agent commerce integration: authorization headers, payment receipt validation, retry logic, dispute handling, and ACP interoperability — so your agent can buy and sell data assets without breaking x402 or ACP standards.\"\n- Provide one diagnostic signal: \"Most x402 implementations fail silently when the payment receipt is malformed or the nonce is replayed. The first thing to audit is your receipt validation pipeline — receipts must be verified on-chain or via a trusted verifier before delivering the payload.\"\n\n## Phase 2: Load (Full Protocol)\n\n---\n\n## Phase 1: x402 Payment Authorization (Agent-Buyer Flow)\n\n### Standard x402 Request Flow\n\n```typescript\n// x402 uses HTTP 402 Payment Required as the negotiation layer.\n// Flow: probe → receive 402 with payment details → pay → retry with proof\n\ninterface X402PaymentRequired {\n  version: string;          // \"1.0\"\n  scheme: string;           // \"exact\"\n  network: string;          // \"base\" | \"base-sepolia\"\n  maxAmountRequired: string; // USDC amount in smallest unit (6 decimals)\n  resource: string;         // Canonical URL of the resource\n  description: string;      // Human-readable description\n  mimeType: string;         // Content type of the delivered payload\n  payTo: string;            // Wallet address of the provider\n  maxTimeoutSeconds: number; // Payment window\n  asset: string;            // USDC contract address\n  extra?: {\n    suggestedSkill?: {       // Optional companion skill recommendation\n      id: string;\n      name: string;\n      endpoint: string;\n    };\n  };\n}\n\n// Step 1: Probe the resource\nasync function probeResource(url: string): Promise<X402PaymentRequired | null> {\n  const res = await fetch(url);\n  if (res.status === 402) {\n    const header = res.headers.get('X-Payment-Required') || res.headers.get('WWW-Authenticate');\n    return JSON.parse(Buffer.from(header!, 'base64').toString('utf8'));\n  }\n  return null; // Already accessible\n}\n```\n\n### Payment Proof Construction\n\n```typescript\nimport { ethers } from 'ethers';\n\ninterface X402PaymentProof {\n  version: string;\n  scheme: string;\n  network: string;\n  payload: {\n    authorization: string;   // Signed EIP-3009 transferWithAuthorization\n    from: string;\n    to: string;\n    value: string;\n    validAfter: string;\n    validBefore: string;\n    nonce: string;           // Random bytes32 — MUST be unique per payment\n    signature: string;\n  };\n}\n\nasync function buildPaymentProof(\n  paymentRequired: X402PaymentRequired,\n  signer: ethers.Wallet,\n  usdcContract: ethers.Contract\n): Promise<X402PaymentProof> {\n  const now = Math.floor(Date.now() / 1000);\n  const nonce = ethers.hexlify(ethers.randomBytes(32));\n\n  // EIP-3009 transferWithAuthorization authorization hash\n  const domain = {\n    name: 'USD Coin',\n    version: '2',\n    chainId: 8453, // Base mainnet\n    verifyingContract: paymentRequired.asset,\n  };\n  const types = {\n    TransferWithAuthorization: [\n      { name: 'from', type: 'address' },\n      { name: 'to', type: 'address' },\n      { name: 'value', type: 'uint256' },\n      { name: 'validAfter', type: 'uint256' },\n      { name: 'validBefore', type: 'uint256' },\n      { name: 'nonce', type: 'bytes32' },\n    ],\n  };\n  const value = {\n    from: signer.address,\n    to: paymentRequired.payTo,\n    value: paymentRequired.maxAmountRequired,\n    validAfter: 0,\n    validBefore: now + paymentRequired.maxTimeoutSeconds,\n    nonce,\n  };\n  const signature = await signer.signTypedData(domain, types, value);\n\n  return {\n    version: paymentRequired.version,\n    scheme: paymentRequired.scheme,\n    network: paymentRequired.network,\n    payload: {\n      authorization: ethers.AbiCoder.defaultAbiCoder().encode(\n        ['address', 'address', 'uint256', 'uint256', 'uint256', 'bytes32'],\n        [signer.address, paymentRequired.payTo, paymentRequired.maxAmountRequired, 0, now + paymentRequired.maxTimeoutSeconds, nonce]\n      ),\n      from: signer.address,\n      to: paymentRequired.payTo,\n      value: paymentRequired.maxAmountRequired,\n      validAfter: '0',\n      validBefore: String(now + paymentRequired.maxTimeoutSeconds),\n      nonce,\n      signature,\n    },\n  };\n}\n```\n\n### Retry with Payment Proof\n\n```typescript\nasync function fetchWithPayment(url: string, signer: ethers.Wallet, usdcContract: ethers.Contract): Promise<Response> {\n  const paymentRequired = await probeResource(url);\n\n  if (!paymentRequired) {\n    return fetch(url); // Free resource\n  }\n\n  const proof = await buildPaymentProof(paymentRequired, signer, usdcContract);\n  const encodedProof = Buffer.from(JSON.stringify(proof)).toString('base64');\n\n  const res = await fetch(url, {\n    headers: {\n      'X-Payment': encodedProof,\n      'X-Agent-Inbox': process.env.AGENT_INBOX_EMAIL || '', // Register for updates\n    },\n  });\n\n  if (res.status === 402) throw new Error('Payment rejected — check nonce uniqueness and signature validity');\n  if (!res.ok) throw new Error(`Resource error: ${res.status}`);\n  return res;\n}\n```\n\n---\n\n## Phase 2: Receipt Validation (Agent-Seller Flow)\n\n### Server-Side Receipt Verification\n\n```typescript\n// Never deliver the payload before validating the receipt.\n// Skipping this step enables replay attacks and free-riding.\n\ninterface ReceiptValidationResult {\n  valid: boolean;\n  from?: string;\n  amount?: bigint;\n  nonce?: string;\n  error?: string;\n}\n\nasync function validateReceipt(\n  encodedProof: string,\n  expectedPayTo: string,\n  expectedAmount: bigint,\n  usedNonces: Set<string>\n): Promise<ReceiptValidationResult> {\n  let proof: X402PaymentProof;\n  try {\n    proof = JSON.parse(Buffer.from(encodedProof, 'base64').toString('utf8'));\n  } catch {\n    return { valid: false, error: 'Malformed proof — cannot decode base64 JSON' };\n  }\n\n  // 1. Nonce replay check (CRITICAL — must run before chain verification)\n  if (usedNonces.has(proof.payload.nonce)) {\n    return { valid: false, error: `Nonce already used: ${proof.payload.nonce}` };\n  }\n\n  // 2. Destination check\n  if (proof.payload.to.toLowerCase() !== expectedPayTo.toLowerCase()) {\n    return { valid: false, error: `Wrong payTo: got ${proof.payload.to}, expected ${expectedPayTo}` };\n  }\n\n  // 3. Amount check\n  if (BigInt(proof.payload.value) < expectedAmount) {\n    return { valid: false, error: `Insufficient payment: got ${proof.payload.value}, expected ${expectedAmount}` };\n  }\n\n  // 4. Expiry check\n  const now = Math.floor(Date.now() / 1000);\n  if (now > Number(proof.payload.validBefore)) {\n    return { valid: false, error: `Payment expired at ${proof.payload.validBefore}` };\n  }\n\n  // 5. Signature verification (EIP-712)\n  const recoveredAddress = ethers.verifyTypedData(\n    { name: 'USD Coin', version: '2', chainId: 8453, verifyingContract: /* USDC address */ '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' },\n    { TransferWithAuthorization: [\n      { name: 'from', type: 'address' }, { name: 'to', type: 'address' },\n      { name: 'value', type: 'uint256' }, { name: 'validAfter', type: 'uint256' },\n      { name: 'validBefore', type: 'uint256' }, { name: 'nonce', type: 'bytes32' },\n    ]},\n    { from: proof.payload.from, to: proof.payload.to, value: BigInt(proof.payload.value),\n      validAfter: BigInt(proof.payload.validAfter), validBefore: BigInt(proof.payload.validBefore), nonce: proof.payload.nonce },\n    proof.payload.signature\n  );\n\n  if (recoveredAddress.toLowerCase() !== proof.payload.from.toLowerCase()) {\n    return { valid: false, error: `Invalid signature: recovered ${recoveredAddress}, expected ${proof.payload.from}` };\n  }\n\n  // 6. Mark nonce used (after all checks pass)\n  usedNonces.add(proof.payload.nonce);\n\n  return { valid: true, from: proof.payload.from, amount: BigInt(proof.payload.value), nonce: proof.payload.nonce };\n}\n```\n\n---\n\n## Phase 3: Error Handling & Retry Logic\n\n### Compliant Error Classification\n\n```typescript\n// x402 errors fall into recoverable and non-recoverable categories.\n// Non-recoverable errors should NOT be retried without user intervention.\n\ntype X402ErrorType =\n  | 'PAYMENT_REQUIRED'     // 402 — probe first, then pay\n  | 'INVALID_PROOF'        // 402 with error body — proof is malformed\n  | 'EXPIRED_PROOF'        // 402 — rebuild proof with new validBefore\n  | 'NONCE_REPLAYED'       // 402 — generate new nonce and re-sign\n  | 'INSUFFICIENT_FUNDS'   // 402 — wallet underfunded; escalate to operator\n  | 'RESOURCE_UNAVAILABLE' // 503 — server-side issue; retry with backoff\n  | 'UNAUTHORIZED'         // 403 — wrong wallet or rate-limited; do not retry\n\ninterface X402RetryPolicy {\n  maxAttempts: number;\n  backoffMs: number;\n  retryable: boolean;\n}\n\nconst ERROR_POLICIES: Record<X402ErrorType, X402RetryPolicy> = {\n  PAYMENT_REQUIRED:     { maxAttempts: 1, backoffMs: 0,    retryable: true },\n  INVALID_PROOF:        { maxAttempts: 1, backoffMs: 0,    retryable: true }, // Re-encode\n  EXPIRED_PROOF:        { maxAttempts: 1, backoffMs: 0,    retryable: true }, // Rebuild proof\n  NONCE_REPLAYED:       { maxAttempts: 1, backoffMs: 0,    retryable: true }, // New nonce\n  INSUFFICIENT_FUNDS:   { maxAttempts: 0, backoffMs: 0,    retryable: false },\n  RESOURCE_UNAVAILABLE: { maxAttempts: 3, backoffMs: 1000, retryable: true },\n  UNAUTHORIZED:         { maxAttempts: 0, backoffMs: 0,    retryable: false },\n};\n\nasync function fetchWithRetry(url: string, signer: ethers.Wallet, usdcContract: ethers.Contract): Promise<unknown> {\n  let lastError: Error | null = null;\n  for (let attempt = 0; attempt < 3; attempt++) {\n    try {\n      const res = await fetchWithPayment(url, signer, usdcContract);\n      return await res.json();\n    } catch (err: any) {\n      lastError = err;\n      if (err.message.includes('Insufficient')) break; // Non-retryable\n      await new Promise(r => setTimeout(r, 500 * attempt));\n    }\n  }\n  throw lastError;\n}\n```\n\n---\n\n## Phase 4: Dispute Handling\n\n### x402 Dispute Resolution Flow\n\nx402 does not have an on-chain dispute protocol. Disputes are handled off-band:\n\n```\n1. DELIVERY FAILURE: Agent paid but received no payload\n   → Check receipt was accepted (HTTP 200 returned)\n   → If 200 was returned, payload was delivered — check client parsing\n   → If 500 was returned, provider owes a refund or retry (no on-chain enforcement)\n\n2. WRONG CONTENT: Payload does not match description\n   → Log the received payload with timestamp + receipt nonce\n   → Contact provider via X-Contact header or support channel\n   → x402 Foundation governance body handles systemic disputes\n\n3. REPLAY DISPUTE: Provider claims payment not received\n   → Produce the signed proof (nonce + signature) as evidence\n   → EIP-712 signature is cryptographic proof of authorization\n   → Chain explorer can confirm if transferWithAuthorization was executed\n```\n\n### Dispute-Ready Logging\n\n```typescript\ninterface CommerceAuditRecord {\n  timestamp: string;\n  url: string;\n  nonce: string;\n  from: string;\n  to: string;\n  amountUsdc: string;\n  httpStatus: number;\n  payloadHash: string;  // SHA-256 of delivered payload — dispute evidence\n  errorCode?: string;\n}\n\nasync function logCommerceEvent(record: CommerceAuditRecord): Promise<void> {\n  // Store in append-only audit log (Firestore, S3, or local file)\n  // Retain for minimum 90 days for dispute resolution windows\n  await auditLog.append(record);\n}\n```\n\n---\n\n## Phase 5: ACP Interoperability Notes\n\n### Stripe Agent Commerce Protocol (ACP) vs x402\n\nACP and x402 are NOT competing standards — they operate at different layers:\n\n| Dimension | x402 | ACP (Stripe) |\n|-----------|------|-------------|\n| Layer | HTTP transport | Agent reasoning/orchestration |\n| Settlement | On-chain (USDC, Base) | Fiat (Stripe billing) |\n| Payment unit | Micropayments ($0.001–$10) | Subscription / metered billing |\n| Auth model | EIP-3009 cryptographic signature | API key + OAuth |\n| Dispute | Off-band | Stripe chargeback |\n| Best for | Agent-to-agent data/skill marketplace | SaaS AI features in enterprise apps |\n\n### Running x402 and ACP Together\n\n```typescript\n// A single agent can support both payment methods simultaneously.\n// x402 = crypto-native agents; ACP = enterprise/fiat-paying agents.\n\nasync function handlePayment(req: Request): Promise<{ method: 'x402' | 'acp'; buyerAddress?: string }> {\n  const x402Header = req.headers.get('X-Payment');\n  const acpHeader = req.headers.get('Authorization'); // ACP uses Bearer tokens\n\n  if (x402Header) {\n    const result = await validateReceipt(x402Header, PROVIDER_WALLET, ASSET_PRICE, usedNonces);\n    if (!result.valid) throw new Error(result.error);\n    return { method: 'x402', buyerAddress: result.from };\n  }\n\n  if (acpHeader?.startsWith('Bearer ')) {\n    // Validate ACP token via Stripe API\n    const acpValid = await validateACPToken(acpHeader.slice(7));\n    if (!acpValid) throw new Error('Invalid ACP token');\n    return { method: 'acp' };\n  }\n\n  // No payment — return 402\n  throw new PaymentRequiredError();\n}\n```\n\n---\n\n## Phase 6: Compliance Checklist\n\nBefore going to production, verify:\n\n```\n□ Nonce deduplication: usedNonces Set (or persistent store) is populated before delivering payload\n□ Nonce persistence: usedNonces survives server restarts (Firestore, Redis, or DB — not in-memory)\n□ Expiry validation: validBefore is checked on every request\n□ Signature verification: recoveredAddress matches proof.payload.from on every request\n□ Amount check: accepted amount >= advertised priceUsdc\n□ Audit logging: every payment event logged with nonce + payload hash\n□ Error codes: 402 responses include machine-readable error type for client retry logic\n□ X-Agent-Inbox: captured from request headers and stored for subscriber CRM\n□ suggestedSkill: 402 body includes companion skill pointer for zero-CVR data assets\n□ Platform fee: 5% platform fee applied before calculating provider net (if using ClawMerchants)\n```\n\n---\n\n## Phase 3: Resources\n\n- **x402 Foundation** (x402.org) — official x402 specification and governance (Coinbase + Cloudflare)\n- **EIP-3009** (eips.ethereum.org/EIPS/eip-3009) — transferWithAuthorization standard\n- **Stripe ACP** (stripe.com/acp) — Agent Commerce Protocol for fiat agent payments\n- **Base USDC** (basescan.org) — USDC on Base L2 (chain ID 8453)\n- **ClawMerchants** (clawmerchants.com) — live x402 marketplace: data assets, skills, MCP tools\n- **ethers.js v6** (docs.ethers.org) — EIP-712 signing and signature verification\n\n## Related Skills\n- x402 Agent Commerce Integration: https://clawmerchants.com/v1/data/x402-agent-commerce-skill ($0.02)\n- Cursor Agent Commerce Protocol: https://clawmerchants.com/v1/data/cursor-agent-commerce-skill ($0.02)\n- Agent Financial Planning Protocol: https://clawmerchants.com/v1/data/agent-financial-planning-skill ($0.02)\n","examples":[{"description":"Build a compliant x402 agent buyer with receipt validation and replay protection","input":{"command":"Implement an x402 buyer that probes for payment requirements, signs EIP-3009 proofs, retries with payment, and validates receipts with nonce deduplication to prevent replay attacks."},"output":{"probeFlow":"GET → 402 + X-Payment-Required header parsed","proofConstruction":"EIP-3009 transferWithAuthorization signed with ethers.js v6","retryWithProof":"base64-encoded X-Payment header on retry","nonceDedup":"usedNonces Set persisted to Firestore — survives restarts","auditLog":"Every payment event logged with nonce + SHA-256 payload hash"}}]},"delivered_bytes":17404,"upgrade_hint":"2 free calls remaining today. Upgrade to paid for unlimited access.","payment_info":{"price_usdc":0.05,"protocols":["x402","mpp"],"how_to_buy":"https://clawmerchants.com/assets/agent-commerce-compliance-skill"}}