Webhooks
Webhooks notify your application in real-time when events occur in FLXBL. Build integrations, trigger workflows, and keep external systems in sync.
How Webhooks Work
When an entity is created, updated, or deleted, FLXBL sends an HTTP POST request to your configured endpoint with details about the event.
Event Types
FLXBL can send notifications for these entity lifecycle events:
| Event Type | Description | When Triggered |
|---|---|---|
entity.created | A new entity record was created | POST to /api/v1/dynamic/{Entity} |
entity.updated | An existing record was modified | PUT or PATCH to /api/v1/dynamic/{Entity}/:id |
entity.deleted | A record was deleted | DELETE to /api/v1/dynamic/{Entity}/:id |
Creating Webhooks
Via REST API
// Create a webhook via REST API
POST /api/v1/webhooks
{
"targetUrl": "https://your-app.com/webhooks/flxbl",
"eventTypes": ["entity.created", "entity.updated"],
"entityNames": ["Order", "Customer"], // Optional filter
"schemaName": "production"
}
// Response
{
"id": "wh_abc123",
"targetUrl": "https://your-app.com/webhooks/flxbl",
"eventTypes": ["entity.created", "entity.updated"],
"entityNames": ["Order", "Customer"],
"signingSecret": "whsec_abc123def456...", // Store securely!
"isActive": true,
"createdAt": "2025-01-15T10:30:00Z"
} Important: Store the signingSecret securely.
You'll need it to verify webhook signatures. It's only shown at creation time.
Via MCP (AI Assistant)
// Using the FLXBL MCP tool
// In Cursor/Windsurf, ask the AI:
"Create a webhook to notify my app when
Orders are created or updated"
// The AI will use manage_webhooks with:
{
"action": "create",
"targetUrl": "https://your-app.com/webhooks/orders",
"eventTypes": ["entity.created", "entity.updated"],
"entityNames": ["Order"],
"schemaName": "production"
}Webhook Payload
Each webhook delivery includes the event details and the full entity record:
// Webhook payload structure
{
"id": "evt_xyz789",
"type": "entity.created",
"timestamp": "2025-01-15T10:30:00Z",
"data": {
"entityName": "Order",
"entityId": "node_abc123",
"record": {
"id": "node_abc123",
"customerId": "node_customer_456",
"total": 299.99,
"status": "pending",
"createdAt": "2025-01-15T10:30:00Z"
}
},
"tenant": {
"id": "tenant_xyz",
"name": "Acme Corp"
}
}Signature Verification
FLXBL signs every webhook payload with your signing secret. Always verify signatures to ensure the request came from FLXBL.
The signature is sent in the X-Webhook-Signature header:
X-Webhook-Signature: sha256=abc123def456... Node.js / TypeScript
// Verify webhook signature (Node.js example)
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
const providedSig = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature),
Buffer.from(providedSig)
);
}
// Express webhook handler
app.post('/webhooks/flxbl', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
// Process the webhook
switch (event.type) {
case 'entity.created':
handleEntityCreated(event.data);
break;
case 'entity.updated':
handleEntityUpdated(event.data);
break;
case 'entity.deleted':
handleEntityDeleted(event.data);
break;
}
res.status(200).send('OK');
});Python
# Verify webhook signature (Python example)
import hmac
import hashlib
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
provided = signature.replace('sha256=', '')
return hmac.compare_digest(expected, provided)
# Flask webhook handler
@app.route('/webhooks/flxbl', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Webhook-Signature')
payload = request.get_data()
if not verify_webhook_signature(payload, signature, WEBHOOK_SECRET):
return 'Invalid signature', 401
event = request.get_json()
if event['type'] == 'entity.created':
handle_entity_created(event['data'])
# ... handle other events
return 'OK', 200Managing Webhooks
List Webhooks
// List all webhooks
GET /api/v1/webhooks
// Response
{
"webhooks": [
{
"id": "wh_abc123",
"targetUrl": "https://your-app.com/webhooks/flxbl",
"eventTypes": ["entity.created", "entity.updated"],
"entityNames": ["Order", "Customer"],
"isActive": true,
"lastTriggered": "2025-01-16T14:22:00Z",
"successRate": 0.98
}
]
}Update and Delete
// Update a webhook
PATCH /api/v1/webhooks/wh_abc123
{
"isActive": false // Temporarily disable
}
// Delete a webhook
DELETE /api/v1/webhooks/wh_abc123Use Cases
Send Notifications
Trigger email, SMS, or push notifications when records are created:
- Email customer when their order status changes
- Notify team when a new support ticket is created
- Send welcome email when user signs up
Sync External Systems
Keep data in sync across your stack:
- Update search index when products change
- Sync customer data to CRM
- Push events to analytics platform
Trigger Workflows
Automate business processes:
- Start fulfillment when order is placed
- Generate invoice when subscription renews
- Archive data when record is deleted
Best Practices
Security
- Always verify signatures - Never trust unverified payloads
- Use HTTPS - Webhook URLs must use TLS
- Store secrets securely - Use environment variables or secret management
Reliability
- Respond quickly - Return 2xx within 5 seconds
- Process asynchronously - Queue heavy processing for later
- Handle duplicates - Webhooks may be retried; make handlers idempotent
Filtering
- Use entity filters - Only receive events for entities you care about
- Subscribe to specific events - Don't process events you don't need
Retry Policy
If your endpoint returns a non-2xx status code or times out, FLXBL retries delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 8 hours |
After 5 failed attempts, the webhook is marked as failed and no further retries occur.
Troubleshooting
"Webhook not receiving events"
- Verify the webhook is active (
isActive: true) - Check that your endpoint is publicly accessible
- Ensure your firewall allows FLXBL's IP addresses
- Check the webhook's event types and entity filters
"Signature verification failing"
- Verify you're using the correct signing secret
- Ensure you're hashing the raw request body (not parsed JSON)
- Check for encoding issues - payload must be UTF-8
Next Steps
- API Keys - Secure your webhook endpoints
- API Reference - Complete REST API documentation
- MCP Integration - Manage webhooks with AI assistants