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

  1. Go to your project in the dashboard
  2. Navigate to the Webhooks tab
  3. Enter your webhook endpoint URL
  4. 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