PHP code example of sandermuller / laravel-x402

1. Go to this page and download the library: Download sandermuller/laravel-x402 library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

sandermuller / laravel-x402 example snippets


use X402\Laravel\Http\Middleware\RequirePaymentFromBots;

// Free for humans, 0.001 USDC for AI agents.
Route::get('/articles/{article}', ArticleController::class)
    ->middleware(RequirePaymentFromBots::using('0.001'));

use X402\Laravel\Http\Middleware\RequirePayment;

Route::get('/premium', PremiumController::class)
    ->middleware(RequirePayment::using('0.01'));        // 0.01 USDC on Base

Route::get('/premium', PremiumController::class)
    ->middleware(
        RequirePayment::using('0.01')
            ->payTo('0xRouteSpecificRecipient')
            ->onNetwork('polygon')
            ->describing('Premium API call')
            ->skipWhen(fn (Request $r) => $r->user()?->isPro() === true)
    );

use X402\Laravel\Contracts\Priceable;

class Article extends Model implements Priceable
{
    public function x402Price(): string
    {
        return $this->premium ? '0.10' : '0.01';
    }
}

Route::get('/articles/{article}', ArticleController::class)
    ->middleware(RequirePayment::using('0.01'));        // base price

use X402\Laravel\Http\Middleware\RequirePaymentFromBots;

Route::get('/articles/{article}', ArticleController::class)
    ->middleware(RequirePaymentFromBots::using('0.001'));

'bots' => [
    // 'patterns' => ['ExactList', 'Of', 'Bots'],   // null = use defaults
    'extra_patterns' => ['MyResearchBot'],
],

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use X402\Laravel\Facades\X402;

X402::enforceWhen(fn (Request $r) =>
    ! Cache::has("x402:paid:{$r->ip()}:{$r->path()}")
);

Route::get('/premium', function (Request $request) {
    $settle = $request->x402Settle();   // ?\X402\Facilitator\SettleResult

    return response()->json([
        'tx' => $settle?->transaction,
        'payer' => $settle?->payer,
    ]);
})->middleware(RequirePayment::using('0.01'));

Route::get('/premium', PremiumController::class)
    ->middleware(['throttle:x402', RequirePayment::using('0.01')]);

RateLimiter::for('x402', fn (Request $r) => Limit::perMinute(120)->by($r->ip()));

$response = Http::withX402()->get('https://api.example.com/data');

use X402\Laravel\Client\WalletResolver;

$this->app->bind(WalletResolver::class, MyTenantWalletResolver::class);

Http::withX402(context: $tenantId)->post('https://api.example.com/...');

// .env (AWS KMS)
X402_WALLET_DRIVER=kms
X402_WALLET_KMS_PROVIDER=aws
X402_WALLET_AWS_REGION=us-east-1
X402_WALLET_AWS_KEY_ID=arn:aws:kms:us-east-1:123:key/abc...

use Aws\Kms\KmsClient;
use X402\Laravel\Client\WalletResolver;
use X402\Laravel\Wallet\Resolvers\TenantKmsWalletResolver;

$this->app->bind(WalletResolver::class, fn ($app) => new TenantKmsWalletResolver(
    kms: $app->make(KmsClient::class),
    keyIdByTenant: [
        'acme'   => 'arn:aws:kms:us-east-1:123:key/acme...',
        'globex' => 'arn:aws:kms:us-east-1:123:key/globex...',
    ],
));

use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Events\Dispatcher;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use X402\Facilitator\CoinbaseFacilitator;
use X402\Facilitator\FacilitatorClient;
use X402\Laravel\Facilitator\DispatchingFacilitatorFactory;
use X402\Laravel\Facilitator\FacilitatorResolver;
use X402\Laravel\Support\PaymentContextRegistry;

final readonly class TenantFacilitatorResolver implements FacilitatorResolver
{
    public function __construct(
        private FacilitatorClient $default,         // env-configured, already wrapped
        private TenantContext $tenants,
        private ClientInterface $http,
        private RequestFactoryInterface $requestFactory,
        private StreamFactoryInterface $streamFactory,
        private Dispatcher $events,
        private PaymentContextRegistry $context,
        private Container $container,
    ) {}

    public function resolve(mixed $context = null): FacilitatorClient
    {
        $tenant = $this->tenants->current();

        if ($tenant?->facilitator_url === null) {
            return $this->default;
        }

        return DispatchingFacilitatorFactory::wrap(
            inner: new CoinbaseFacilitator(
                http: $this->http,
                requestFactory: $this->requestFactory,
                streamFactory: $this->streamFactory,
                baseUrl: $tenant->facilitator_url,
                defaultHeaders: ['Authorization' => 'Bearer ' . $tenant->facilitator_token],
            ),
            events: $this->events,
            context: $this->context,
            container: $this->container,
        );
    }
}

$this->app->bind(FacilitatorResolver::class, TenantFacilitatorResolver::class);

// config/x402.php
'history' => [
    'enabled' => env('X402_HISTORY', true),
    'queue' => env('X402_HISTORY_QUEUE', null), // null = sync; set a queue name to defer
    'connection' => null,                        // separate analytics DB if you want one
    'table' => 'x402_payments',
],

use X402\Laravel\Models\Payment;

Payment::settled()->where('payer', '0xalice')->latest()->take(10)->get();
Payment::rejected()->whereBetween('created_at', [$from, $to])->count();

use Illuminate\Http\Request;
use X402\Laravel\Facades\X402;

X402::capturePaymentContext(fn (Request $r): array => [
    'user_id' => $r->user()?->id,
    'tenant_id' => $r->user()?->tenant_id,
    'request_id' => $r->headers->get('X-Request-Id'),
]);

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use X402\Laravel\Facades\X402;

X402::resourceFormatter(function (string $url): string {
    try {
        return Route::getRoutes()->match(Request::create($url))->getName() ?? $url;
    } catch (NotFoundHttpException) {
        return $url;
    }
});

$schedule->command('x402:prune --before=30days --status=rejected')->daily();

Route::middleware([
    'x402.cache',                    // cache lookup — short-circuits on hit
    RequirePayment::using('0.01'),   // payment enforcer (skipped on hit)
])->get('/premium', PremiumController::class);

// config/x402.php
'response_cache' => [
    // ... existing keys ...
    'response_headers' => [
        // Defaults the upstream library ships:
        'Content-Type', 'Content-Language', 'Content-Length',
        'Content-Disposition', 'Cache-Control', 'ETag', 'Last-Modified',
        'Location', 'X-PAYMENT-RESPONSE', 'PAYMENT-RESPONSE',
        // App-specific addition:
        'Access-Control-Expose-Headers',
    ],
],

use X402\Laravel\Events\PaymentSettled;

Event::listen(PaymentSettled::class, function (PaymentSettled $e): void {
    Log::info('paid', [
        'resource' => $e->resource,
        'tx' => $e->result->transaction,
        'payer' => $e->result->payer,
    ]);
});

use X402\Laravel\Events\PaymentSettled;
use X402\Laravel\Facades\X402;

it('charges and serves premium content', function (): void {
    Event::fake([PaymentSettled::class]);
    $fake = X402::fake();

    $this->withHeader('X-PAYMENT', $signedHeader)
        ->get('/premium')
        ->assertOk();

    $fake->assertSettled('https://localhost/premium');
    Event::assertDispatched(PaymentSettled::class);
});

// Drive failure paths:
X402::fake()->rejectVerify('insufficient-funds');
X402::fake()->failSettle('on-chain-revert');

// config/x402.php
'networks' => [
    'base' => 'eip155:8453',
    'zora' => 'eip155:7777777',
],

'assets' => [
    'USDC' => [
        'address' => '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
        'decimals' => 6,
        'eip712' => ['name' => 'USD Coin', 'version' => '2'],
    ],
    'PYUSD' => [
        'address' => '0x6c3ea9036406852006290770BEdFcAbA0e23A0e8',
        'decimals' => 6,
        'eip712' => ['name' => 'PayPal USD', 'version' => '1'],
    ],
],
bash
php artisan vendor:publish --tag=x402-config
bash
composer 
text
$ php artisan x402:verify-config
Wallet driver: kms (aws)
Wallet address: 0xabc…
x402 config OK.
bash
php artisan vendor:publish --tag=x402-migrations
php artisan migrate
bash
php artisan x402:prune --before=30days --status=rejected
php artisan x402:prune --before=2026-01-01 --status=settled
php artisan x402:prune --before=7days --dry-run