Skip to main content

Overview

The /verify endpoint confirms that a payment has been authorized and is valid. Servers should call this endpoint before delivering services to ensure payment has been received.

Endpoint

POST https://open.x402.host/verify

When to Use

  • Before delivering services - Always verify payment first
  • Payment validation - Confirm transaction authenticity
  • Authorization checks - Ensure payment meets requirements

Request

Headers

HeaderValueRequired
Content-Typeapplication/jsonYes

Body Parameters

ParameterTypeDescriptionRequired
proofstringPayment authorization proofYes
networkstringBlockchain networkYes
txHashstringTransaction hash (optional)No

Example Request

const response = await fetch('https://open.x402.host/verify', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    proof: paymentProof,
    network: 'base'
  })
});

const result = await response.json();
if (result.valid) {
  // Payment is valid, deliver service
}

Response

Success Response

{
  "valid": true,
  "transactionId": "tx_abc123",
  "amount": "1.00",
  "network": "base",
  "timestamp": 1699564800,
  "status": "confirmed"
}

Invalid Payment Response

{
  "valid": false,
  "error": "Payment not found",
  "code": "PAYMENT_NOT_FOUND"
}

Response Fields

FieldTypeDescription
validbooleanWhether payment is valid
transactionIdstringUnique transaction identifier
amountstringPayment amount in USDC
networkstringBlockchain network used
timestampnumberUnix timestamp of payment
statusstringPayment status
errorstringError message (if invalid)
codestringError code (if invalid)

Error Codes

CodeDescription
PAYMENT_NOT_FOUNDPayment proof not recognized
INSUFFICIENT_AMOUNTPayment amount too low
EXPIREDPayment authorization expired
INVALID_NETWORKNetwork not supported
ALREADY_USEDPayment already redeemed

Complete Integration Example

// Express.js middleware example
async function verifyPaymentMiddleware(req, res, next) {
  const paymentProof = req.headers['x-402-payment'];

  if (!paymentProof) {
    return res.status(402).json({
      error: 'Payment required',
      facilitator: 'https://open.x402.host'
    });
  }

  try {
    const response = await fetch('https://open.x402.host/verify', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        proof: paymentProof,
        network: 'base'
      }),
      timeout: 5000
    });

    const result = await response.json();

    if (!result.valid) {
      return res.status(402).json({
        error: 'Invalid payment',
        details: result.error
      });
    }

    // Store transaction info for settlement
    req.paymentInfo = {
      transactionId: result.transactionId,
      amount: result.amount,
      network: result.network
    };

    next(); // Payment verified, proceed

  } catch (error) {
    console.error('Payment verification error:', error);
    return res.status(500).json({
      error: 'Payment verification failed'
    });
  }
}

// Use in your routes
app.post('/api/premium-data', verifyPaymentMiddleware, (req, res) => {
  // Payment is verified, deliver content
  res.json({
    data: 'Your premium content',
    transactionId: req.paymentInfo.transactionId
  });
});

Best Practices

  1. Always verify before delivery - Never trust client-side payment claims
  2. Cache verification results - Avoid redundant API calls
  3. Set timeouts - Don’t let verification hang
  4. Log all attempts - Track payment attempts for debugging
  5. Handle errors gracefully - Provide clear feedback

Caching Verifications

const verificationCache = new Map();
const CACHE_TTL = 60000; // 1 minute

async function verifyWithCache(proof, network) {
  const cacheKey = `${network}:${proof}`;

  // Check cache
  const cached = verificationCache.get(cacheKey);
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.result;
  }

  // Verify with API
  const result = await fetch('https://open.x402.host/verify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ proof, network })
  }).then(r => r.json());

  // Cache result
  verificationCache.set(cacheKey, {
    result,
    timestamp: Date.now()
  });

  return result;
}

Rate Limiting

  • 500 requests per minute per IP
  • Use caching to reduce API calls
  • Exceeding limits returns 429 Too Many Requests
  • /settle - Finalize transaction settlement
  • /open - Production payment endpoint
  • /test - Development endpoint
  • /supported - Check supported networks