PHP implementation of x402 protocol
x402-php is an early-stage PHP project in the AI payments / x402 ecosystem. It currently has 2 GitHub stars and 0 forks.
PHP implementation of the x402 payments protocol - a modern, internet-native payment standard for digital commerce.
x402 is an open standard for HTTP-based payments that enables:
composer require mondb-dev/x402-php
<?php
use X402\Facilitator\FacilitatorClient;
use X402\Middleware\PaymentHandler;
// Option 1: Use PayAI Facilitator (default, recommended)
$facilitator = FacilitatorClient::payai(
apiKey: getenv('FACILITATOR_API_KEY') // Optional for testing
);
// Option 2: Use Coinbase Facilitator
$facilitator = FacilitatorClient::coinbase(
apiKey: getenv('COINBASE_FACILITATOR_API_KEY')
);
// Option 3: Use environment variables
$facilitator = FacilitatorClient::fromEnvironment();
// Option 4: Custom facilitator
$facilitator = new FacilitatorClient('https://your-facilitator.example.com');
// Initialize payment handler
$handler = new PaymentHandler($facilitator, autoSettle: true);
// Define what you're selling
$requirements = $handler->createPaymentRequirements(
payTo: '0xYourAddress',
amount: '1000000', // 1 USDC (6 decimals)
resource: 'https://api.example.com/data',
description: 'Premium API access',
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
network: 'base-mainnet',
extra: [
'name' => 'USD Coin', // Required for EIP-712 signature verification
'version' => '2' // Required for EIP-712 signature verification
],
id: 'payment-' . uniqid() // Optional but recommended for Coinbase
// Process incoming request
$result = $handler->processPayment($_SERVER, $requirements);
if ($result['verified']) {
// Payment successful - serve content
echo json_encode(['data' => 'Your premium content']);
// Include settlement info in response header
if ($result['settlement']) {
header('X-Payment-Response: ' .
$handler->createPaymentResponseHeader($result['settlement']));
}
} else {
// Payment required
$paymentRequiredResponse = $handler->createPaymentRequiredResponse($requirements);
$paymentRequiredResponse->send();
}
For production deployments, enable all security features:
use X402\Facilitator\FacilitatorClient;
use X402\Middleware\PaymentHandler;
use X402\Nonce\RedisNonceTracker;
use X402\RateLimit\RedisRateLimiter;
use Monolog\Logger;
use Monolog\Handler\RotatingFileHandler;
// Configure Redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
// Configure facilitator
$facilitator = FacilitatorClient::payai(apiKey: getenv('FACILITATOR_API_KEY'));
// Configure nonce tracker (prevents replay attacks)
$nonceTracker = new RedisNonceTracker($redis, 'myapp');
// Configure rate limiter (prevents DoS)
$rateLimiter = new RedisRateLimiter($redis, maxAttempts: 10, decaySeconds: 60);
// Configure logger
$logger = new Logger('x402');
$logger->pushHandler(new RotatingFileHandler('/var/log/x402/payments.log', 30));
// Create secure payment handler
$handler = new PaymentHandler(
facilitator: $facilitator,
autoSettle: true,
validBeforeBufferSeconds: 6,
nonceTracker: $nonceTracker,
rateLimiter: $rateLimiter,
logger: $logger
);
Required Environment Variables:
# Facilitator (REQUIRED)
FACILITATOR_BASE_URL=https://facilitator.payai.network
FACILITATOR_API_KEY=your_api_key_here
APP_ENV=production
# Redis (REQUIRED for nonce tracking)
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_password
# Rate Limiting (RECOMMENDED)
RATE_LIMIT_ENABLED=true
RATE_LIMIT_MAX_ATTEMPTS=10
RATE_LIMIT_DECAY_SECONDS=60
See examples/production-setup.php for a complete working example with all security features.
Before deploying, run the production validator:
php bin/validate-production.php
This checks:
See SECURITY_CHECKLIST.md for complete production deployment guidelines.
The library consists of several key components:
PaymentRequirements: Defines what payment is required for a resourcePaymentPayload: Contains the payment information from the clientPaymentRequiredResponse: 402 response sent to clientsVerifyResponse: Result of payment verificationSettleResponse: Result of payment settlementThe FacilitatorClient handles communication with x402 facilitator servers:
The PaymentHandler provides high-level middleware functionality:
For the exact scheme on EVM networks (Base, Ethereum), the extra field must contain the ERC-20 token's name and version fields. These are required for EIP-712 signature verification:
$requirements = $handler->createPaymentRequirements(
// ... other parameters ...
extra: [
'name' => 'USD Coin', // Token name from ERC-20 contract
'version' => '2' // Token version from ERC-20 contract
]
);
Common values for USDC:
name: "USD Coin", version: "2"Omitting the extra field or missing name/version will cause signature verification to fail.
// Get supported configuration from facilitator
$config = $facilitator->getSupported();
// Check if specific network is supported
if ($config->supportsNetwork('base-mainnet')) {
$network = $config->getNetwork('base-mainnet');
echo "Chain ID: {$network->chainId}\n";
echo "Explorer: {$network->explorerUrl}\n";
}
// Check if specific payment scheme is supported
if ($config->supportsScheme('exact')) {
echo "Facilitator supports exact payment scheme\n";
}
use X402\Validation\Validator;
use X402\Exceptions\ValidationException;
// Validate Ethereum address
if (!Validator::isValidEthereumAddress($address)) {
throw new ValidationException('Invalid address');
}
// Validate amount format
if (!Validator::isValidUintString($amount)) {
throw new ValidationException('Invalid amount');
}
// Sanitize user input
$safe = Validator::sanitizeString($userInput);
// Extract payment header
$paymentHeader = $handler->extractPaymentHeader($_SERVER);
if ($paymentHeader !== null) {
try {
// Verify payment
$payload = $handler->verifyPayment($paymentHeader, $requirements);
// Manually settle if needed
$settlement = $handler->settlePayment($payload, $requirements);
echo "Transaction: " . $settlement['transaction'];
} catch (PaymentRequiredException $e) {
echo "Payment verification failed: " . $e->getMessage();
}
}
// Base Mainnet
$requirements = $handler->createPaymentRequirements(
payTo: $yourAddress,
amount: '1000000',
resource: $resourceUrl,
description: $description,
asset: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC
network: 'base-mainnet',
extra: [
'name' => 'USD Coin',
'version' => '2'
]
);
// Base Sepolia (Testnet)
$requirements = $handler->createPaymentRequirements(
payTo: $yourAddress,
amount: '1000000',
resource: $resourceUrl,
description: $description,
asset: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', // USDC
network: 'base-sepolia',
extra: [
'name' => 'USD Coin',
'version' => '2'
]
);
Problem: PHP automatically changes HTTP 402 to 401 when WWW-Authenticate header is set after the status code.
Solution: Always use the send() method or set headers before status code:
// ❌ WRONG - Returns 401 instead of 402
http_response_code(402);
header('WWW-Authenticate: X-Payment');
echo json_encode($response);
// ✅ CORRECT - Returns 402
header('WWW-Authenticate: X-Payment');
http_response_code(402);
echo json_encode($response);
// ✅ BEST - Use send() method
$paymentRequired->send(); // Handles this automatically
Why it matters: Clients expect HTTP 402 for payment requirements. If they receive 401, they'll treat it as an authentication error, breaking the x402 protocol.
Test your responses:
curl -I https://your-api.com/endpoint
# Should return: HTTP/1.1 402 Payment Required
# NOT: HTTP/1.1 401 Unauthorized
Run the test suite:
composer install
./vendor/bin/phpunit
Run PHPStan for static analysis:
./vendor/bin/phpstan analyse src --level=8
Run PHP CS Fixer for code style:
./vendor/bin/php-cs-fixer fix
See the examples/ directory for complete working examples:
basic-usage.php: Simple payment-required endpointproduction-setup.php: Production-ready setup with all security featurescoinbase-facilitator.php: Using Coinbase facilitatorsolana-usage.php: Solana (SVM) payment exampleThis library implements comprehensive enterprise-grade security measures:
This library delegates cryptographic signature verification to the facilitator server.
For EVM (Ethereum/Base) payments:
For production use:
https://facilitator.x402.org)This library requires a facilitator for Solana (SVM) transaction validation.
For Solana payments:
The facilitator verifies:
payTomaxAmountRequiredasset addressFor production use:
// ✅ SECURE: Use facilitator for production
$facilitator = new FacilitatorClient('https://facilitator.x402.org');
$handler = new PaymentHandler($facilitator, autoSettle: true);
// ❌ INSECURE: Do not use without facilitator in production
$handler = new PaymentHandler(); // Missing facilitator!
Different blockchain networks have different block times. Configure timing buffers appropriately:
// EVM L2 (Base, Optimism, Arbitrum): ~2s blocks
$handler = new PaymentHandler($facilitator, autoSettle: true, validBeforeBufferSeconds: 6);
// Ethereum mainnet: ~12s blocks
$handler = new PaymentHandler($facilitator, autoSettle: true, validBeforeBufferSeconds: 36);
// Solana: ~0.4s slots
$handler = new PaymentHandler($facilitator, autoSettle: true, validBeforeBufferSeconds: 2);
bin/validate-production.php)Before deploying to production, review SECURITY_CHECKLIST.md which covers:
Please report security vulnerabilities according to SECURITY.md.
Contributions are welcome! Please follow these guidelines:
Apache-2.0 License - see LICENSE file for details
This project follows Semantic Versioning 2.0.0:
Current Version: See VERSION file or GitHub Releases
See CHANGELOG.md for a detailed history of changes.
@deprecated tagsWe welcome contributions! Please see our Contributing Guide for details.
git checkout -b feature/amazing-feature)git push origin feature/amazing-feature)# Clone your fork
git clone https://github.com/YOUR_USERNAME/x402-php.git
cd x402-php
# Install dependencies
composer install
# Run tests
./vendor/bin/phpunit
# Check code style
./vendor/bin/php-cs-fixer fix --dry-run
# Run static analysis
./vendor/bin/phpstan analyse --level=8
See CONTRIBUTING.md for complete guidelines.
Be respectful and inclusive. We're building the future of payments together! 🚀
If you're using AI coding assistants (GitHub Copilot, Cursor, Claude, GPT, etc.) to work on this project, please read AI_GUIDELINES.md first. This document ensures:
Key reminders for AI assistants:
exact scheme is currently in the x402 specificationextra field is mandatory for EVM networksFor issues and questions:
Made with ❤️ for the future of internet payments
Your AI trading terminal assistant for US stocks, commodities, forex, and crypto.
The agent-native LLM router for autonomous agents. 55+ models (8 free), <1ms local routing, USDC payments on Base & Solana via x402.
A payments protocol for the internet. Built on HTTP.
A local-first AI agent with persistent memory, emotional intelligence, and a peer-to-peer skills economy.
The trust layer for agent-to-agent commerce — natural-language mandates, ERC-7710 delegated permissions, x402 payments, escrow, and dispute resolution as one open, catch-all Agent Skill / Claude Code plugin.
The AI agent with a wallet — spends USDC autonomously to get real work done. Apache-2.0, TypeScript.