most of your code uses route rate limiting (https://laravel.com/docs/12.x/routing#rate-limiting), the by() method indeed uses a $key to segment rate limits by a value. but this is (for good reasons) not the $key under which the value is stored in redis (or other cache you use for rate limit storage). it internally translates to some hash like e9b6cc1432541b9ceebf113eee05eeba (https://github.com/illuminate/routing/blob/12.x/Middleware/ThrottleRequests.php#L131).
so when you use the RateLimiter class (https://laravel.com/docs/12.x/rate-limiting#basic-usage), you get "full remaining attempts" because you check something else (different keys in cache). same same but different:)
but there is a $headers array in the callback you could use. just get the remaining value from there
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(6)->by(optional($request->user())->id ?: $request->ip())->response(function (Request $request, array $headers) {
return response()->json([
'message' => "Too many requests. Remaining attempts: {$headers['X-RateLimit-Remaining']}. Try again in {$headers['Retry-After']} seconds.",
], 429, $headers);
});
});
but the remaining attempts will be always 0 in the case you return the "Too many requests" response, so... you know.