The throttle middleware took its limits as route parameters, so a limit that depended on the user or the plan had to be a custom middleware.
// RouteServiceProvider
RateLimiter::for('api', function (Request $request) {
return $request->user()?->isPremium()
? Limit::perMinute(1000)->by($request->user()->id)
: Limit::perMinute(60)->by($request->ip());
});
// Route::middleware('throttle:api')
// and several limits at once
return [Limit::perMinute(60), Limit::perDay(1000)];
The by key is the part that decides fairness: keying on the IP means an office behind one address is one client, which is a support ticket waiting. Returning an array applies every limit and the strictest one that trips wins, which covers the burst-and-sustained case that a single limit cannot. Limit::none() for an internal caller is cleaner than excluding the route.