Open source
HTTP Client Rate Limits for Laravel
composer require roundly-consulting/http-client-rate-limits-for-laravelOverview
Rate limit outgoing requests made with Laravel’s HTTP client. Declare a budget — per second, minute, hour or day — and a small Guzzle middleware paces your calls, waiting exactly as long as needed when the limit is reached, so you never blow past a third-party API’s quota. Every limit comes from one RateLimits facade, so the configured store — or a test fake — applies everywhere. Named profiles, compound windows, per-owner budgets, header-driven adaptive backoff and shared cache, Redis or database stores are built in. MIT-licensed and dependency-light: only official Laravel components plus two small Roundly packages.
What you get
One-line throttling
Http::rateLimit(30) on any request, or build limits with the RateLimits facade or an injected manager. It waits exactly as long as needed, then sends.
Profiles & compound windows
Define limits once in config and reference them by name. Enforce 5/sec and 100/min at once — the strictest window wins.
Shared stores
In-memory, any Laravel cache, Redis or the database — each checks and records a request in one atomic step, so workers sharing a budget never overshoot it.
Adaptive backoff
Reads Retry-After and X-RateLimit-* response headers and makes the next call wait exactly as long as the server asked.
Fail fast, jitter & queues
Cap the wait with a typed exception, spread wake-ups with jitter, or release queued jobs instead of blocking workers.
Events & testing fake
RequestDeferred, RequestAllowed and RateLimitReset events, plus a recording RateLimits::fake() with deferred, allowed and reset assertions.
Documentation
Installation
Install via Composer, optionally publish the config, and publish the migration only if you use the DatabaseStore.
Configuration
Every config key, its default and env variable — limiter profiles, default store and deferrer, cache, Redis, database and events.
The RateLimits facade
The one entry point for building limits — per-window factories, profiles, compound limits, store and deferrer overrides, Retry-After, the fake.
DI and actions
Inject RateLimitManager instead of calling the facade, or wire a RateLimit by hand — the package has no action classes.
Rate limiting requests
Throttle Laravel HTTP client calls with the Http::rateLimit() macro or the RateLimit Guzzle middleware, from per-second to per-day.
Per-owner budgets
Scope a limit to an owner — an account, tenant, API key or outbound IP — so independent callers never share a budget.
Named limiter profiles
Define reusable limits once in config and reference them by name — Http::rateLimit('github') — with every option available.
Compound limits
Enforce several windows on one request — 5 per second and 100 per minute — where the strictest window decides the wait.
Max wait & fail fast
Cap how long a call may wait; above the ceiling it throws RateLimitExceededException instead of blocking.
Jitter
Add random extra wait so a fleet of workers doesn’t wake up in lockstep — never less than the real wait; inject the randomness for tests.
Adaptive limiting
Honour the server’s own budget — read Retry-After and X-RateLimit-* headers and back off exactly as long as asked.
Retry-After & 429 retries
Combine the limiter with Laravel’s retry() and RateLimits::retryAfter() to honour 429 Too Many Requests responses.
Pre-flight inspection
Ask how many requests remain and how long until the next is allowed — without recording a hit — and reset a key’s budget.
Stores
Where request timestamps live — memory, any Laravel cache, Redis or the database — how each stays atomic, and how to write your own.
Deferrers & queued jobs
How the wait is performed — a millisecond sleep by default, or releasing a queued job back onto the queue.
Defaults & overrides
Set the default store and deferrer in config, override them per call site with RateLimits::usingStore() / usingDeferrer(), or per instance.
Events
RequestDeferred, RequestAllowed and RateLimitReset events to log, chart or alert on throttling — or switch them off for zero overhead.
Exceptions
Every typed exception the package throws, when it happens, and one base class to catch them all.
Timespan enum
The Timespan enum behind every window — second to day — with the full enums-for-laravel toolkit for labels, options and validation.
Testing
Swap in RateLimits::fake() to assert deferred, allowed and reset limits without real sleeps or Redis, or fake Laravel’s Sleep.
Requirements
PHP 8.4+ and Laravel 12 or 13; Redis only for the RedisStore, two database tables only for the DatabaseStore.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.