Named limiter profiles
Define reusable limits once in config/http-client-rate-limits.php and reference them by name from anywhere:
// config/http-client-rate-limits.php
'limiters' => [
'github' => ['rate' => 5, 'per' => 'second'],
'billing' => ['rate' => 100, 'per' => 'minute', 'by' => 'tenant-1', 'jitter' => 50],
],use RoundlyConsulting\HttpClientRateLimits\Facades\RateLimits;
Http::rateLimit('github')->get('https://api.github.com/user');
// Re-key a profile per owner at the call site:
Http::rateLimit('github', by: 'acct-1')->get('https://api.github.com/user');
// The same profile outside the HTTP client:
$limit = RateLimits::profile('github');
$limit->remaining();Referencing a name that isn’t defined throws UnknownLimiterProfileException.
Profile keys
Each profile array accepts rate and per, plus the optional by, trim, max_wait, jitter and adaptive keys. A key that is not set — omitted, null or blank ('', whitespace) — falls back to these defaults:
| Key | Default | Purpose |
|---|---|---|
rate | 1 | Requests allowed in the window. |
per | minute | Window: second, minute, hour or day. |
by | null (global) | Owner key the budget is tracked under. |
trim | false | Drop the owner’s hits older than the window after each allowed request. |
max_wait | null | Max wait in ms; a longer wait throws RateLimitExceededException. |
jitter | 0 | Up to this many ms of random extra wait — never shortens a wait. |
adaptive | false | Self-tune from Retry-After / X-RateLimit-* response headers. |
A profile using every key:
'limiters' => [
'openai' => [
'rate' => 60, // requests allowed in the window
'per' => 'minute', // second | minute | hour | day
'by' => 'openai', // owner key
'trim' => true, // drop hits older than the window after each request
'max_wait' => 10_000, // ms: throw RateLimitExceededException above this wait
'jitter' => 100, // ms: up to this much random extra wait
'adaptive' => true, // honour Retry-After / X-RateLimit-* response headers
],
],Strict values
Every profile value is read strictly when the profile is resolved, never guessed at:
- rate, max_wait and jitter take an integer or an integer string ('5'); 'five', '5.5' or '1e3' throws InvalidConfigurationException, and so does a negative max_wait or jitter. A rate below 1 throws InvalidLimitException.
- per takes second, minute, hour or day (exact) or a Timespan; a typo such as minutes, or an unsupported week, throws InvalidTimespanException.
- by takes a string; a non-string throws InvalidConfigurationException.
- trim and adaptive take true/false, 1/0, on/off or yes/no; anything else throws InvalidConfigurationException.
Every error names the full key, e.g. http-client-rate-limits.limiters.github.adaptive. A key that is not set uses its default from the table above — so a blank max_wait means no ceiling, never a 0 ms fail-fast one.
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.