Webhooks
Webhooks allow your application to receive real-time notifications when flags change. This is faster than polling and ensures your app always has the latest flag configurations.
Setting Up Webhooks
- Go to your project in the dashboard
- Navigate to the Webhooks tab
- Enter your webhook endpoint URL
- Copy the generated webhook secret
Webhook Events
| Event | Description |
|---|---|
flag.created |
A new flag was created |
flag.updated |
A flag's name or metadata changed |
flag.deleted |
A flag was deleted |
flag.toggled |
A flag was enabled or disabled in an environment |
flag.rules_updated |
Targeting rules, rollout percentage, or default value changed |
Payload Format
All webhook payloads share a common structure:
{
"event": "flag.toggled",
"timestamp": "2025-11-29T14:30:00Z",
"project_id": "01JDNVQ3K2...",
"flag": "new-checkout",
"flag_id": "01JDNVQ3K2..."
}
flag.created
{
"event": "flag.created",
"timestamp": "2025-11-29T14:30:00Z",
"project_id": "01JDNVQ3K2...",
"flag": "new-checkout",
"flag_id": "01JDNVQ3K2...",
"name": "New Checkout Flow",
"type": "boolean"
}
flag.toggled
{
"event": "flag.toggled",
"timestamp": "2025-11-29T14:30:00Z",
"project_id": "01JDNVQ3K2...",
"flag": "new-checkout",
"flag_id": "01JDNVQ3K2...",
"environment": "production",
"environment_id": "01JDNVQ3K2...",
"enabled": true
}
flag.rules_updated
{
"event": "flag.rules_updated",
"timestamp": "2025-11-29T14:30:00Z",
"project_id": "01JDNVQ3K2...",
"flag": "new-checkout",
"flag_id": "01JDNVQ3K2...",
"environment": "production",
"environment_id": "01JDNVQ3K2..."
}
Verifying Signatures
Each webhook request includes an X-Webhook-Signature header. Always verify this signature to ensure the request came from FeatureFlags.
// In your webhook controller
public function handle(Request $request)
{
$payload = $request->getContent();
$signature = $request->header('X-Webhook-Signature');
$secret = config('services.featureflags.webhook_secret');
$expected = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature)) {
abort(401, 'Invalid signature');
}
$event = $request->input('event');
$flagKey = $request->input('flag');
// Handle the webhook...
match($event) {
'flag.toggled', 'flag.rules_updated' => $this->refreshCache(),
'flag.deleted' => $this->removeFromCache($flagKey),
default => null,
};
return response()->json(['ok' => true]);
}
Laravel Package Integration
The Laravel package handles webhooks automatically. Just configure it:
// config/featureflags.php
'webhook' => [
'enabled' => true,
'path' => '/webhooks/feature-flags',
'secret' => env('FEATURE_FLAGS_WEBHOOK_SECRET'),
],
Then register the webhook route:
// routes/web.php
Route::featureFlagsWebhook();
The package will automatically:
- Verify the webhook signature
- Invalidate the local flag cache
- Fetch fresh flag configurations
Retry Policy
If your endpoint returns a 5xx error, we'll retry the webhook:
- 1st retry: after 10 seconds
- 2nd retry: after 1 minute
- 3rd retry: after 5 minutes
After 3 failed attempts, the webhook is dropped. 4xx errors are not retried.
Testing Webhooks
Use tools like webhook.site or ngrok during development to inspect webhook payloads.
Security Best Practices
- Always verify signatures - Never trust webhook data without verification
- Use HTTPS - Webhook URLs must use HTTPS in production
- Keep secrets secure - Store webhook secrets in environment variables
- Respond quickly - Return a 2xx response within 10 seconds
- Process async - Queue long-running tasks instead of blocking the response