Documentation

x402 Integration Guide

Everything you need to integrate with MIRRO's x402 facilitator. Add payment verification to your API in under 5 minutes.

What is x402

HTTP 402 "Payment Required" has been a reserved status code since the beginning of HTTP. x402 is a protocol that finally puts it to use.

When an API returns 402, it tells the client: "This content costs money. Here's how to pay." The client sends a blockchain payment, proves it, and gets the content.

MIRRO's facilitator is the verification layer. Any agent on Arc can use it to verify that a USDC payment actually happened before delivering content.

Key Insight

Unlike Ethereum where verification takes 12+ seconds and costs gas, Arc settles in milliseconds and MIRRO verifies in ~180ms. Total latency: under 500ms.

How MIRRO's Facilitator Works

1
Client calls your API
2
Your API returns 402 with payment details
3
Client sends USDC on Arc to your address
4
Client sends txHash to your API
5
Your API calls MIRRO facilitator to verify
6
Facilitator: on-chain verification + replay protection
7
Returns valid: true in ~180ms
8
Your API delivers the content

Quick Start

server.ts
typescript
// 1. Return 402 if no payment proof
if (!req.headers['x-payment-proof']) {
  return res.status(402).json({
    error: "Payment Required",
    amount: 0.05,
    currency: "USDC",
    recipient: "YOUR_WALLET_ADDRESS",
    network: "Arc Testnet",
    facilitatorUrl: "https://mirro.xyz/api/facilitator/verify"
  });
}

// 2. If payment proof exists, verify it
const proof = JSON.parse(req.headers['x-payment-proof']);
const result = await fetch('https://mirro.xyz/api/facilitator/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    txHash: proof.txHash,
    expectedAmount: 0.05,
    expectedRecipient: "YOUR_WALLET_ADDRESS"
  })
}).then(r => r.json());

// 3. Deliver content if valid
if (result.valid) {
  return res.json({ data: "Your premium content here" });
} else {
  return res.status(402).json({ error: result.reason });
}

API Reference

POST/api/facilitator/verify

Verify a single USDC payment on Arc.

Request Body
{
  "txHash": "0x...",
  "expectedAmount": 0.05,
  "expectedRecipient": "0x..."
}
Response
{
  "valid": true,
  "executionMs": 180,
  "verificationId": "v_1234567890"
}
POST/api/facilitator/verify/batch

Verify up to 10 payments in parallel.

{
  "payments": [
    { "txHash": "0x...", "expectedAmount": 0.05, "expectedRecipient": "0x..." },
    { "txHash": "0x...", "expectedAmount": 0.10, "expectedRecipient": "0x..." }
  ]
}
GET/api/facilitator/health

Check facilitator status, uptime, and metrics.

GET/api/facilitator/status

Get detailed facilitator statistics including verification counts, latency, and revenue.

Code Examples

verify.ts
typescript
const res = await fetch('https://mirro.xyz/api/facilitator/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    txHash: '0x...',
    expectedAmount: 0.05,
    expectedRecipient: '0x...'
  })
});

const { valid, executionMs, verificationId } = await res.json();
console.log(`Verified: ${valid} in ${executionMs}ms`);
verify.py
python
import requests

result = requests.post('https://mirro.xyz/api/facilitator/verify', json={
    'txHash': '0x...',
    'expectedAmount': 0.05,
    'expectedRecipient': '0x...'
}).json()

if result['valid']:
    print(f"Verified in {result['executionMs']}ms")
    print(f"ID: {result['verificationId']}")
else:
    print(f"Failed: {result.get('reason', 'unknown')}")

Error Codes

ReasonDescription
Transaction not foundThe txHash doesn't exist on Arc
Transaction revertedThe transaction failed on-chain
Recipient mismatchPayment went to a different address
Amount insufficientPayment amount is less than expected
Replay attack preventedThis txHash has already been verified
Rate limit exceededToo many requests, try again later