yashhingu2712/laravel-idempotency

An enterprise-grade Laravel Idempotency Package designed to prevent duplicate form submissions and API writes.

Maintainers

Package info

github.com/yashhingu2712/laravel-idempotency

pkg:composer/yashhingu2712/laravel-idempotency

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-06-24 10:49 UTC

This package is auto-updated.

Last update: 2026-06-24 10:55:54 UTC


README

Laravel Idempotency Logo

Laravel Idempotency

Latest Version on Packagist Tests Total Downloads

Laravel Idempotency is an enterprise-grade middleware package designed to prevent duplicate form submissions, double charges, and redundant API writes. It intercepts incoming requests using an X-Idempotency-Key header, relies on atomic locks to avoid race conditions, and safely replays cached responses for subsequent duplicate requests.

Why use this package?

In highly concurrent systems (e.g., payment processing or heavy API integrations), a client might accidentally send the exact same request twice (due to network retries, double-clicks, etc.). Without idempotency, your application might charge the customer twice or create duplicate records. This package solves the problem by ensuring a request with a specific key is only ever processed once.

Installation

You can install the package via Composer.

composer require yashhingu2712/laravel-idempotency

Note: Ensure your application is running PHP 8.2 or higher.

Configuration

You can publish the configuration file using the following Artisan command:

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

This will create a config/idempotency.php file in your application.

return [
    // The HTTP header name to inspect for the idempotency key
    'header_name' => 'X-Idempotency-Key',

    // Time to live (TTL) in seconds for cached responses (default: 24 hours)
    'ttl' => 86400,

    // Recommended: Use an atomic-lock-supported cache driver like redis, memcached, or array
    'cache_driver' => env('IDEMPOTENCY_CACHE_DRIVER', 'redis'),

    // Safe HTTP methods that naturally bypass the idempotency check
    'ignored_methods' => ['GET', 'HEAD', 'OPTIONS'],
];

Important: It is highly recommended to configure your cache driver to redis or memcached. File and database drivers might not support atomic locking out-of-the-box or handle concurrency as elegantly.

How It Works

  1. Identification: The middleware checks the incoming request for the X-Idempotency-Key header.
  2. Atomic Locking: If the header exists, the package tries to acquire a 10-second atomic cache lock. If another request is currently being processed with the same key, it immediately throws an HTTP 409 Conflict.
  3. Execution: If the lock is acquired, the request safely proceeds down the pipeline.
  4. Caching: Once a successful (or client-error) response is generated, it is fully serialized and stored in the cache.
  5. Replay: If a subsequent request arrives with the exact same idempotency key, the middleware intercepts it and instantly returns the cached response, appending an X-Cache-Lookup: HIT - Idempotent header.

Usage

Simply attach the idempotency middleware to the routes or groups you want to protect.

In routes/api.php or routes/web.php

use Illuminate\Support\Facades\Route;

Route::post('/payments/process', [PaymentController::class, 'process'])
    ->middleware('idempotency');

Or apply it to a group of routes:

Route::middleware(['auth:sanctum', 'idempotency'])->group(function () {
    Route::post('/orders', [OrderController::class, 'store']);
    Route::post('/webhooks/stripe', [StripeWebhookController::class, 'handle']);
});

Client-Side Implementation

When making requests to these protected endpoints, your frontend or API consumer must generate and append a unique key (UUIDv4 is highly recommended) via the headers.

// Example using Axios
import axios from 'axios';
import { v4 as uuidv4 } from 'uuid';

axios.post('/api/orders', {
    item_id: 123,
    quantity: 1
}, {
    headers: {
        'X-Idempotency-Key': uuidv4() // e.g., '10ba038e-48da-487b-96e8-8d3b99b6d18a'
    }
}).then(response => {
    console.log(response.data);
});

Testing

This package is fully tested using Pest PHP.

composer test

Security Vulnerabilities

If you discover any security-related issues, please email hinguyash2@gmail.com instead of using the issue tracker.

License

The MIT License (MIT). Please see License File for more information.