Search by

grazulex / laravel-api-throttle-smart

Grazulex

Intelligent, plan-aware rate limiting for Laravel APIs - Built for SaaS, multi-tenant, and enterprise applications

Package info

github.com/Grazulex/laravel-api-throttle-smart

Homepage

Issues

Documentation

pkg:composer/grazulex/laravel-api-throttle-smart

Fund package maintenance!

Grazulex

Statistics

Installs: 16

Dependents: 0

Suggesters: 0

Stars: 3

v0.2.0 2026-09-17 00:47 UTC

This package is auto-updated.

Last update: 2026-09-18 16:12:52 UTC


README

Intelligent, plan-aware rate limiting for Laravel APIs - Multi-algorithm, multi-tenant, quota management

Tip

What Laravel API Throttle Smart does for you โ€” Give your Free, Pro and Enterprise customers different API limits and quotas without writing custom rate limiting for each plan. One config, standard headers, and your API stays fair and predictable under load.

This package is free and maintained on my own time. If it saves you hours, a small contribution helps me keep it going: ๐Ÿ’– GitHub Sponsors ยท โ˜• Buy Me a Coffee ยท PayPal

Latest Version on Packagist Tests Total Downloads License

Features

  • Plan-Based Limits - Define different rate limits per subscription plan (Free, Pro, Enterprise)
  • Multiple Algorithms - Fixed Window, Sliding Window, or Token Bucket
  • Multi-Window Limits - Per-second, minute, hour, day, and month limits
  • Quota Management - Daily/monthly API quota with alerts and top-ups
  • Multi-Tenant Scoping - Scope by user, team, tenant, or IP
  • Multiple Storage Drivers - Cache, Redis, or Database
  • RFC 7231 Compliant - Standard rate limit headers
  • Burst Handling - Token bucket algorithm for controlled bursts
  • Artisan Commands - Status, analytics, cleanup, and management tools
  • Testing Helpers - Fluent testing API with ThrottleSmartFake

Requirements

  • PHP 8.3+
  • Laravel 12.x or 13.x

Installation

composer require grazulex/laravel-api-throttle-smart

Publish the configuration:

php artisan vendor:publish --tag="throttle-smart-config"

For database driver, publish migrations:

php artisan vendor:publish --tag="throttle-smart-migrations"
php artisan migrate

Quick Start

Apply the middleware to routes:

// routes/api.php
Route::middleware(['auth:sanctum', 'throttle.smart'])->group(function () {
    Route::get('/users', [UserController::class, 'index']);
    Route::post('/orders', [OrderController::class, 'store']);
});

The middleware automatically:

  • Resolves the user's plan from the plan attribute
  • Applies plan-specific rate limits
  • Adds standard rate limit headers
  • Returns 429 when limits exceeded

Response Headers

HTTP/1.1 200 OK
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1706835600
X-RateLimit-Policy: 60;w=60
X-RateLimit-Plan: pro
X-Quota-Limit: 1000000
X-Quota-Remaining: 999542
X-Quota-Reset: 1709251200

When rate limited:

HTTP/1.1 429 Too Many Requests
Retry-After: 45
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1706835600

Plan Configuration

// config/throttle-smart.php
'plans' => [
    'free' => [
        'label' => 'Free Plan',
        'requests_per_minute' => 60,
        'requests_per_hour' => 500,
        'requests_per_day' => 5000,
        'requests_per_month' => 100000,
        'burst_size' => 10,
        'burst_refill_rate' => 1,
    ],

    'pro' => [
        'label' => 'Pro Plan',
        'requests_per_minute' => 300,
        'requests_per_hour' => 5000,
        'requests_per_day' => 50000,
        'requests_per_month' => 1000000,
        'burst_size' => 50,
        'burst_refill_rate' => 5,
    ],

    'enterprise' => [
        'label' => 'Enterprise Plan',
        'requests_per_minute' => 1000,
        'requests_per_hour' => 20000,
        'requests_per_day' => 200000,
        'requests_per_month' => null, // Unlimited
        'burst_size' => 200,
        'burst_refill_rate' => 20,
    ],
],

PHP Attributes

use Grazulex\ThrottleSmart\Attributes\RateLimit;
use Grazulex\ThrottleSmart\Attributes\QuotaCost;

class ApiController extends Controller
{
    #[RateLimit(perMinute: 10, perHour: 100)]
    public function sensitiveEndpoint(Request $request)
    {
        // Custom limits for this endpoint
    }

    #[QuotaCost(5)]
    public function expensiveOperation(Request $request)
    {
        // Costs 5 quota units instead of 1
    }
}

Programmatic Usage

use Grazulex\ThrottleSmart\Facades\ThrottleSmart;

// Get rate limits for a user
$limits = ThrottleSmart::getLimits($user);
$limits->minute['remaining']; // 58
$limits->isLimited; // false

// Get quota information
$quota = ThrottleSmart::getQuota($user);
$quota->monthly['remaining']; // 999542
$quota->percentageUsed; // 0.05

// Check without consuming
if (ThrottleSmart::wouldLimit($request)) {
    return response()->json(['message' => 'Please slow down'], 429);
}

// Manually consume quota
ThrottleSmart::consume(5); // Consume 5 units

// Reset limits for a user
ThrottleSmart::reset("user:{$user->id}");

// Grant bonus quota
ThrottleSmart::addQuota($user, 10000, 'Customer support bonus');

Rate Limiting Algorithms

Fixed Window (Default)

Simple counter-based limiting with discrete time windows.

Sliding Window

Weighted average across windows for smoother rate limiting.

'sliding_window' => [
    'enabled' => true,
    'precision' => 1,
],

Token Bucket

Allows controlled bursts while maintaining average rate.

'token_bucket' => [
    'enabled' => true,
    'initial_tokens' => null, // Start with full bucket
],

Artisan Commands

# View rate limit status
php artisan throttle:status

# Check specific user
php artisan throttle:user --user=123

# View analytics
php artisan throttle:analytics --period=day

# Reset user limits
php artisan throttle:reset --user=123

# Reset user quota
php artisan throttle:reset-quota --user=123

# Grant bonus quota
php artisan throttle:grant-quota --user=123 --amount=10000 --reason="Support"

# Cleanup old data
php artisan throttle:cleanup --days=90

Events

use Grazulex\ThrottleSmart\Events\RateLimitExceeded;
use Grazulex\ThrottleSmart\Events\RateLimitApproaching;
use Grazulex\ThrottleSmart\Events\QuotaExceeded;
use Grazulex\ThrottleSmart\Events\QuotaThresholdReached;

// In EventServiceProvider
protected $listen = [
    RateLimitExceeded::class => [
        SendRateLimitNotification::class,
    ],
    QuotaThresholdReached::class => [
        SendQuotaWarningEmail::class,
    ],
];

Testing

use Grazulex\ThrottleSmart\Facades\ThrottleSmart;

public function test_rate_limiting(): void
{
    ThrottleSmart::fake();

    // Make requests...

    ThrottleSmart::assertLimitExceeded('user:123');
    ThrottleSmart::assertNotLimited('user:456');
    ThrottleSmart::assertQuotaConsumed(150);
}

Integration testing:

public function test_api_is_rate_limited(): void
{
    $user = User::factory()->create(['plan' => 'free']);

    // Make 61 requests (free plan allows 60/min)
    for ($i = 0; $i < 61; $i++) {
        $response = $this->actingAs($user)
            ->getJson('/api/users');
    }

    $response->assertStatus(429)
        ->assertHeader('X-RateLimit-Remaining', '0')
        ->assertJsonPath('error.code', 'RATE_LIMIT_EXCEEDED');
}

Quality Tools

# Run tests
composer test

# Code style (Laravel Pint)
composer pint

# Static analysis (PHPStan Level 5)
composer analyse

Error Responses

Code Status Description
RATE_LIMIT_EXCEEDED 429 Rate limit exceeded for time window
QUOTA_EXCEEDED 429 Monthly/daily quota exceeded

Changelog

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

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security-related issues, please email security@grazulex.dev instead of using the issue tracker.

Credits

Support This Package

Laravel API Throttle Smart is free, open source and maintained on my own time. If it saves you hours, here is how you can give back:

  • โญ Star the repository โ€” it helps other developers find it
  • ๐Ÿฆ Share it with your team and network
  • ๐Ÿ’– Sponsor on GitHub, buy me a coffee or donate via PayPal โ€” every contribution funds maintenance, new features and Laravel upgrades

License

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

See Also