wendelladriel/laravel-idempotency

HTTP Idempotency Middleware for Laravel applications
25,248 160
Install
composer require wendelladriel/laravel-idempotency
Latest Version:v1.5.0
PHP:^8.3
License:MIT
Last Updated:Sep 7, 2026
Links: GitHub  ·  Packagist
Maintainer: wendell_adriel

Installation

You can install the package via composer:

composer require wendelladriel/laravel-idempotency

You can publish the config file with:

php artisan vendor:publish --tag="idempotency"

Usage

Attach the middleware to routes that create or update data:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use WendellAdriel\Idempotency\Http\Middleware\Idempotent;

Route::post('/orders', function (Request $request) {
    return response()->json([
        'id' => 1,
        'item' => $request->input('item'),
    ], 201);
})->middleware(Idempotent::class);

By default, the middleware reads the key from the Idempotency-Key header or the _idempotency_key request input. This allows standard HTML forms to include the key in a hidden input. When both values are present, the header takes precedence.

Use the @idempotency Blade directive to render the hidden input with a generated key:

<form method="POST" action="/orders">
    @csrf
    @idempotency

    <!-- ... -->
</form>

You may pass an existing key with @idempotency($key).

When the same key is sent again with the same request data, the package replays the original response instead of executing your route again.

The HTTP middleware requires a cache driver that supports atomic locks. In multi-server deployments, every application server must use the same shared cache backend. The array driver is only suitable for tests or single-process development. See Laravel's atomic lock documentation for supported deployment options.

Streamed and binary file responses cannot be captured safely, so they are not cached. A repeated request with the same key executes the route again, and the response does not include an Idempotency-Replayed header.

Customize a single route with Idempotent::using:

use WendellAdriel\Idempotency\Enums\IdempotencyScope;
use WendellAdriel\Idempotency\Http\Middleware\Idempotent;

Route::post('/payments', ChargePaymentController::class)->middleware(
    Idempotent::using(
        ttl: 600,
        required: false,
        scope: IdempotencyScope::Ip,
        header: 'X-Idempotency-Key',
        lockTimeout: 30,
        cacheStatuses: ['client_error' => false],
    )
);

The cacheStatuses option controls which response categories are stored: informational, success, redirection, client_error, and server_error. All are enabled by default; disabling one leaves the key free for a retry instead of replaying a stored failure.

You may also use the idempotent middleware alias:

Route::post('/orders', StoreOrderController::class)->middleware('idempotent');

If you prefer attributes, use the package's #[Idempotent] attribute on a controller class or method:

use Symfony\Component\HttpFoundation\Response;
use WendellAdriel\Idempotency\Attributes\Idempotent;

#[Idempotent]
class OrderController
{
    public function store(): Response
    {
        // ...
    }
}

Generate a key in application code when needed:

use WendellAdriel\Idempotency\Idempotency;

$key = Idempotency::key();

Inspect and prune cached entries with the included Artisan commands:

php artisan idempotency:list
php artisan idempotency:forget --key=checkout-1 --force

Access the full documentation here.

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Thank you for considering contributing to Laravel Idempotency! You can read the contribution guide here.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

Laravel Idempotency is open-sourced software licensed under the MIT license.

Related Packages

webrek/laravel-idempotency

Safe request retries for Laravel APIs via the Idempotency-Key header.

1,035 0
rap2hpoutre/jacky

Opinionated REST JSON HTTP API client for laravel

4,407 17
vinelab/http

An http library developed for the laravel framework. aliases itself as HttpClien...

306,989 57
remic/guzzlecache

Laravel 5 package for caching Guzzle's GET requests.

9,258 17

Version History

Version Released PHP Laravel License
v1.5.0 ^8.3 ^13.0 MIT
v1.4.0 ^8.3 ^13.0 MIT
v1.3.1 ^8.3 ^13.0 MIT
v1.3.0 ^8.3 ^13.0 MIT
v1.2.0 ^8.3 ^13.0 MIT