What Is Laravel MPP?
Laravel MPP (square1/laravel-mpp) is a middleware package that implements the Machine Payments Protocol (MPP). Instead of blocking unauthorized requests with a 401 or 403, it returns an HTTP 402 Payment Required response containing an HMAC-signed challenge. An AI agent that understands MPP fulfills the challenge over a supported payment rail and retries the request — no human in the loop required.
The package is currently at v1.1.0, MIT licensed, and both MPP and the Stripe SPT APIs it relies on are still in preview.
Gating a Route
Attaching the mpp middleware to any route is all it takes to enable payment enforcement:
Route::get('/resource', MyPaidResource::class)
->middleware('mpp:0.50,USD');
You can also declare pricing declaratively with the RequiresPayment PHP attribute on a controller method and enable automatic enforcement via an environment variable:
#[RequiresPayment(amount: '5.00', currency: 'USD', grants: 10)]
public function report()
{
// ...
}
Route::get('/report', ReportController::class)->middleware('mpp');
Set MPP_ATTRIBUTES_ENABLED=true in your .env and the middleware reads the attribute automatically.
Metered Sessions
When grants is greater than one, a single payment covers multiple accesses. The successful response includes a Payment-Session header:
Payment-Session: id="sess_...", remaining="9", scope="report.basic", expiresAt="..."
Subsequent requests replay the session ID instead of paying again:
curl -si https://your-host/report \
-H 'Authorization: Payment method="stripe", session="sess_..."'
Sessions default to the cache driver but can be persisted to the database:
MPP_SESSION_DRIVER=database
MPP_SESSION_CACHE_STORE=redis
Run php artisan vendor:publish --tag=mpp-migrations && php artisan migrate when using the database driver.
Preconditions
Preconditions are named checks that run before the payment gate, so you can reject ineligible requests without asking an agent to pay first. Register them in config/mpp.php:
'preconditions' => [
'checks' => [
'postexists' => [\App\Mpp\Checks\PostExists::class, 'check'],
],
'global' => ['usernotblocked'],
],
A check returns null to pass or a Response to short-circuit:
public function check(Request $request, PaymentSpec $spec): ?Response
{
return Post::find($request->route('post'))
? null
: response()->json(['error' => 'No such post.'], 404);
}
Attach a precondition per route with the middleware parameter:
Route::get('/posts/{post}', ShowPost::class)
->middleware('mpp:1.00,USD,preconditions=postexists');
Payment Rails
The package ships with two built-in rails:
- Stripe — uses Shared Payment Tokens (SPTs); configure
STRIPE_SECRET_KEY,STRIPE_NETWORK_ID, andSTRIPE_API_VERSION. - Tempo — settles in pathUSD on-chain; select it per route with
method=tempo.
You can accept multiple rails on one route (methods=stripe|acme) and register a custom rail by implementing the Verifier interface.
Installation
composer require square1/laravel-mpp
php artisan vendor:publish --tag=mpp-config
Key Takeaways
- Attach
mppmiddleware to any route to gate it behind an HTTP 402 payment challenge. - Supports Stripe SPTs and Tempo pathUSD out of the box; custom rails are possible via the
Verifierinterface. - Metered sessions let one payment cover multiple requests, tracked atomically in cache or database.
- Preconditions let you reject ineligible requests before the payment gate runs.
- Pricing can be declared inline in the middleware string or via the
RequiresPaymentPHP attribute. - The package is in preview (v1.1.0, MIT); the underlying Stripe SPT API may change.
Source: Laravel News — Laravel MPP: Charge AI Agents for API Access with 402 Payment Required