Receive real-time notifications when flags change — delivery, signatures, retry logic, and verification
Webhooks
Webhooks notify your systems when flag events occur. Flaggr delivers signed HTTP POST requests to your endpoint with the event payload.
Events
| Event | Trigger |
|---|---|
flag.created | A new flag is created |
flag.updated | A flag's configuration changes |
flag.deleted | A flag is removed |
flag.toggled | A flag's enabled state is flipped |
Registering a Webhook
POST /api/webhooks
Content-Type: application/json
Authorization: Bearer flg_your_token
{
"url": "https://your-app.com/webhooks/flaggr",
"secret": "whsec_your_signing_secret",
"events": ["flag.created", "flag.updated", "flag.deleted", "flag.toggled"],
"active": true
}Store your secret securely — you'll use it to verify incoming signatures.
Payload Format
Every webhook delivery is an HTTP POST with Content-Type: application/json:
{
"event": "flag.updated",
"timestamp": "2025-07-20T10:30:00Z",
"data": {
"flagKey": "checkout-v2",
"projectId": "proj-1",
"serviceId": "web-app",
"changes": {
"enabled": { "from": false, "to": true }
}
}
}Signature Verification
Every delivery includes an X-Flaggr-Signature header containing an HMAC-SHA256 signature of the raw request body.
Header format:
X-Flaggr-Signature: sha256=a1b2c3d4e5f6...
Verifying in Node.js
import crypto from 'crypto'
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
}
// In your webhook handler
app.post('/webhooks/flaggr', (req, res) => {
const signature = req.headers['x-flaggr-signature']
const rawBody = req.body // Must be raw string, not parsed JSON
if (!verifyWebhook(rawBody, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' })
}
const event = JSON.parse(rawBody)
console.log(`Flag ${event.data.flagKey}: ${event.event}`)
res.status(200).json({ received: true })
})Verifying with the SDK
import { verifySignature } from '@flaggr/sdk'
const isValid = verifySignature(rawBody, secret, signatureHeader)Important: Always verify signatures using timing-safe comparison to prevent timing attacks.
Delivery & Retry
Flaggr uses exponential backoff for failed deliveries:
| Attempt | Delay | Total Elapsed |
|---|---|---|
| 1st | Immediate | 0s |
| 2nd | 1 second | 1s |
| 3rd | 2 seconds | 3s |
| 4th (final) | 4 seconds | 7s |
Timeout: Each attempt has a 10-second timeout.
Retry conditions:
5xxresponses — retried (server error)429responses — retried (rate limited)- Timeouts — retried
4xxresponses (except 429) — not retried (client error, fix your endpoint)
After all retry attempts are exhausted, the delivery is marked as failed.
Best Practices
Return 200 quickly
Process webhook payloads asynchronously. Return 200 OK immediately and handle the event in a background job:
app.post('/webhooks/flaggr', async (req, res) => {
// Verify signature first
if (!verifyWebhook(req.body, req.headers['x-flaggr-signature'], secret)) {
return res.status(401).end()
}
// Acknowledge immediately
res.status(200).json({ received: true })
// Process asynchronously
await queue.add('process-flag-event', JSON.parse(req.body))
})Handle duplicate deliveries
Network issues can cause the same event to be delivered more than once. Use the event + timestamp + data.flagKey combination as an idempotency key:
const idempotencyKey = `${event.event}:${event.data.flagKey}:${event.timestamp}`
if (await cache.has(idempotencyKey)) return
await cache.set(idempotencyKey, true, { ttl: 3600 })Use HTTPS endpoints
Always use HTTPS URLs for production webhooks. HTTP endpoints are accepted for local development but are not recommended.
Managing Webhooks
Update a webhook
PATCH /api/webhooks/{id}
{
"events": ["flag.toggled"],
"active": false
}Delete a webhook
DELETE /api/webhooks/{id}Disable temporarily
Set active: false to pause deliveries without deleting the webhook configuration:
PATCH /api/webhooks/{id}
{ "active": false }Use Cases
- Cache invalidation — Bust your application cache when a flag changes
- Audit trail — Feed flag changes into your own audit system
- Slack notifications — Alert your team when production flags are toggled
- CI/CD triggers — Kick off deploys when feature flags are updated
- Analytics — Track flag change frequency and patterns
Related
- REST API Reference — Webhook management endpoints
- Audit Logging — Built-in audit trail