route('provider'); $clientIp = $request->ip(); // Rate limits per provider (requests per minute) $rateLimits = [ 'polar' => 60, // Polar: 60 requests per minute 'stripe' => 100, // Stripe: 100 requests per minute 'lemon_squeezy' => 60, // Lemon Squeezy: 60 requests per minute 'oxapay' => 30, // OxaPay: 30 requests per minute 'crypto' => 20, // Crypto: 20 requests per minute ]; $rateLimit = $rateLimits[$provider] ?? 30; // Default: 30 requests per minute // Cache key for rate limiting $key = "webhook_rate_limit:{$provider}:{$clientIp}"; // Use Laravel's Cache atomic increment for rate limiting $current = Cache::increment($key, 1, now()->addMinutes(1)); // Check if rate limit exceeded if ($current > $rateLimit) { // Log rate limit violation \Log::warning('Webhook rate limit exceeded', [ 'provider' => $provider, 'ip' => $clientIp, 'current' => $current, 'limit' => $rateLimit, 'user_agent' => $request->userAgent(), 'request_size' => strlen($request->getContent()), ]); return response()->json([ 'error' => 'Rate limit exceeded', 'message' => 'Too many webhook requests. Please try again later.', 'retry_after' => 60, ], 429)->header('Retry-After', 60); } // Add rate limit headers $response = $next($request); $response->headers->set('X-RateLimit-Limit', $rateLimit); $response->headers->set('X-RateLimit-Remaining', max(0, $rateLimit - $current)); return $response; } }