API Middleware
The Meerkat API uses one middleware group for public reads and another for moderation routes. Their defaults are in config/meerkat.php:
1'api' => [
2 'middleware' => [
3 'public' => ['throttle:60,1'],
4 'privileged' => ['throttle:30,1', 'auth', 'can:view comments'],
5 ],
6],
Public reads allow 60 requests per client each minute. Moderation routes require authentication and the view comments permission, and allow 30 requests per minute.
Laravel registers these groups as:
public→meerkat-api-publicprivileged→meerkat-api-privileged
#Change the defaults
Publish the config, then edit config/meerkat.php:
1php artisan vendor:publish --tag=meerkat-config
1'middleware' => [
2 'public' => ['throttle:60,1'],
3 'privileged' => ['auth', 'can:view comments', 'throttle:300,1'],
4],
These values replace the defaults. Keep auth and can:view comments to protect moderation routes.
#Add middleware from a service provider
From any service provider's boot():
1use Illuminate\Support\Facades\Route;
2
3public function boot()
4{
5 Route::pushMiddlewareToGroup('meerkat-api-public', \App\Http\Middleware\RecaptchaGate::class);
6 Route::pushMiddlewareToGroup('meerkat-api-privileged', \App\Http\Middleware\AuditApiCall::class);
7}
pushMiddlewareToGroup adds your middleware after Meerkat's defaults without replacing them.
Call it from a service provider's boot() method. Route files and request hooks run too late.
#Change request limits
Change the throttle:max,minutes value for each group. Use custom middleware when individual routes need different limits.
#Use Sanctum authentication
For Sanctum authentication, replace auth in the privileged group:
1'middleware' => [
2 'public' => [],
3 'privileged' => ['auth:sanctum', 'can:view comments'],
4],
#Add logging, metrics, or CORS
Add logging, metrics, CORS, request tracking, or similar middleware in the same way:
1Route::pushMiddlewareToGroup('meerkat-api-public', LogApiRequests::class);
2Route::pushMiddlewareToGroup('meerkat-api-public', TraceApiRequest::class);
#Protect comment submissions
The POST /!/meerkat/comments submission route uses its own middleware group from meerkat.form.middleware:
1'form' => [
2 'middleware' => ['throttle:30,1'],
3],
Add middleware to the meerkat-form-submit group with:
1Route::pushMiddlewareToGroup('meerkat-form-submit', \App\Http\Middleware\TurnstileGate::class);
Submission middleware runs before Meerkat's rate limiter, spam guards, and database writes.
#Add Cloudflare Turnstile
Create app/Http/Middleware/TurnstileGate.php:
1namespace App\Http\Middleware;
2
3use Closure;
4use Illuminate\Http\Request;
5use Illuminate\Support\Facades\Http;
6
7class TurnstileGate
8{
9 public function handle(Request $request, Closure $next)
10 {
11 $token = $request->input('cf-turnstile-response');
12
13 $verified = Http::asForm()->post(
14 'https://challenges.cloudflare.com/turnstile/v0/siteverify',
15 [
16 'secret' => config('services.turnstile.secret'),
17 'response' => $token,
18 'remoteip' => $request->ip(),
19 ]
20 )->json('success', false);
21
22 if (! $verified) {
23 return back()
24 ->withInput()
25 ->withErrors(['cf-turnstile-response' => 'Captcha verification failed.'], 'meerkat');
26 }
27
28 return $next($request);
29 }
30}
Register from your AppServiceProvider::boot():
1Route::pushMiddlewareToGroup('meerkat-form-submit', \App\Http\Middleware\TurnstileGate::class);
Render the Turnstile widget inside {{ meerkat:form }}.
#Captcha addons that use Statamic events
Some captcha addons listen for Statamic form events instead of using middleware. Meerkat fires FormSubmitted with the meerkat form handle and SubmissionCreated after a successful save. Route middleware runs earlier. See Statamic form events.