PHPackages                             truschery/idem - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. truschery/idem

ActiveLibrary[Queues &amp; Workers](/categories/queues)

truschery/idem
==============

Idempotency for HTTP requests, queued jobs, and arbitrary operations

v1.1.0(2mo ago)110MITPHPPHP &gt;=8.2

Since May 21Pushed 1mo agoCompare

[ Source](https://github.com/truschery/idem)[ Packagist](https://packagist.org/packages/truschery/idem)[ RSS](/packages/truschery-idem/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (5)Dependencies (10)Versions (7)Used By (0)

[![Laravel](https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg)](https://raw.githubusercontent.com/laravel/art/master/logo-lockup/5%20SVG/2%20CMYK/1%20Full%20Color/laravel-logolockup-cmyk-red.svg)Laravel Idempotency
===================

[](#laravel-idempotency)

**Idempotency for HTTP requests, queued jobs, and arbitrary operations**

[![Latest Version on Packagist](https://camo.githubusercontent.com/178895fbba527e83cb8ddc8279b40ab8e85c6058aeaf38df1d853ccc180203d8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7472757363686572792f6964656d2e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/truschery/idem)[![PHP Version](https://camo.githubusercontent.com/074222e0a3638b5a49cfb83132a87bf74c33c88485955358673cd65d9b754036/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d626c75653f7374796c653d666c61742d737175617265)](https://php.net)[![Laravel](https://camo.githubusercontent.com/95ab9270d0b5151c57d95bcc15098b1b34f72693dd76d50e42c82a422190ee61/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3130253230253743253230313125323025374325323031322d7265643f7374796c653d666c61742d737175617265)](https://laravel.com)[![License](https://camo.githubusercontent.com/d5ed0c3cd1f0c18693743459566949dcd7ac58b29423ce01a55914603525331d/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f7472757363686572792f6964656d3f7374796c653d666c61742d737175617265)](LICENSE)

---

Ensures that repeating the same operation always produces the same result with no side effects. Essential for payment systems, APIs, and any operation where duplication is unacceptable.

Full documentation is available at [idem.truschery.dev](https://idem.truschery.dev)

Features
--------

[](#features)

- **`Idempotent`** — HTTP middleware: a repeated request with the same `Idempotency-Key` returns the cached response
- **`EnsureIdempotent`** — Job middleware: a queued job is executed only once, even if dispatched multiple times
- **`Once::do()`** — facade for arbitrary operations: any callable runs exactly once per key
- **Two storage drivers**: `cache` and `database`

Installation
------------

[](#installation)

```
composer require truschery/idem
```

Publish the configuration file:

```
php artisan vendor:publish --tag=idem-config
```

If you plan to use the `database` driver, publish and run the migrations:

```
php artisan vendor:publish --tag=idem-migrations
php artisan migrate
```

Usage
-----

[](#usage)

### HTTP Requests — `Idempotent`

[](#http-requests--idempotent)

Register the middleware alias and apply it to a route or group:

```
// Routes
Route::post('/payments', [PaymentController::class, 'store'])
    ->middleware('idempotent');
```

The client sends a unique key in the request header:

```
POST /payments HTTP/1.1
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json

{"amount": 1000, "currency": "USD"}
```

A repeated request with the same key returns the stored response without re-executing the handler.

> If the `Idempotency-Key` header is absent, the request is processed normally — no error is thrown.

---

### Queued Jobs — `EnsureIdempotent`

[](#queued-jobs--ensureidempotent)

Pass the idempotency key directly to the middleware constructor:

```
use Truschery\Idem\Middleware\EnsureIdempotent;

class ProcessPaymentJob implements ShouldQueue
{
    public function __construct(private string $paymentId) {}

    public function middleware(): array
    {
        return [new EnsureIdempotent($this->paymentId)];
    }

    public function handle(): void
    {
        // Runs only once, even if the job is dispatched multiple times
        Payment::process($this->paymentId);
    }
}
```

---

### Arbitrary Operations — `Once::do()`

[](#arbitrary-operations--oncedo)

```
use Truschery\Idem\Once;

$result = Once::do('send-welcome-email:' . $user->id, function () use ($user) {
    return Mail::to($user)->send(new WelcomeMail($user));
});
```

A repeated call with the same key returns the cached result of the first execution.

`Once::do()` works in any context — HTTP requests, queued jobs, Artisan commands.

Roadmap
-------

[](#roadmap)

- HTTP Middleware (`Idempotent`)
- Job Middleware (`EnsureIdempotent`)
- `Once::do()` facade
- `cache` and `database` drivers
- Artisan command `idem:prune` — removes expired records from the database
- Extended tests for Job middleware and `Once::do()`

License
-------

[](#license)

MIT — see [LICENSE](LICENSE) for details.

###  Health Score

40

—

FairBetter than 86% of packages

Maintenance88

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

6

Last Release

59d ago

PHP version history (2 changes)v1.0.0PHP ^8.2|^8.3|^8.4

v1.0.1PHP &gt;=8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/466e6c0a3aa52012890dc8fed8ffa8ec1f94eeb49da030eff3c0784e60bf57be?d=identicon)[truschery](/maintainers/truschery)

---

Top Contributors

[![truschery](https://avatars.githubusercontent.com/u/204706577?v=4)](https://github.com/truschery "truschery (36 commits)")

---

Tags

idempotencyidempotentlaravellaravel-frameworkmiddlewarequeuemiddlewarelaravelqueueidempotencyidempotent

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/truschery-idem/health.svg)

```
[![Health](https://phpackages.com/badges/truschery-idem/health.svg)](https://phpackages.com/packages/truschery-idem)
```

###  Alternatives

[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M136](/packages/laravel-pulse)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M133](/packages/roots-acorn)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k55.0M632](/packages/laravel-scout)[mike-bronner/laravel-model-caching

Automatic caching for Eloquent models.

2.4k96.5k1](/packages/mike-bronner-laravel-model-caching)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
