Webhooks
Webhooks notify your application when important events occur, such as when a user revokes access or deletes their account.
Setup
- Go to your application settings in the Developer Dashboard
- Enter your Webhook URL and save
- Click “Rotate Secret” to generate a Webhook Secret
- Copy the secret immediately (it won’t be shown again)
- Click “Send Test Webhook” to verify your setup
Payload Format
All webhook payloads follow this format:
{
"event": "event.type",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
...
}
}
Signature Verification
All webhooks include a signature header to verify authenticity:
X-Webhook-Signature: sha256=<hex-encoded-hmac>
To verify:
- Get the raw request body (before parsing JSON)
- Compute HMAC-SHA256 using your Webhook Secret as the key
- Compare with the signature in the header
Example (Node.js/Express):
const crypto = require('crypto');
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-webhook-signature'];
if (!signature) return res.status(401).send('Missing signature');
const expected = 'sha256=' + crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (signature !== expected) return res.status(401).send('Invalid signature');
const payload = JSON.parse(req.body);
// Reject old webhooks to prevent replay attacks
const timestamp = new Date(payload.timestamp);
const age = Date.now() - timestamp.getTime();
if (age > 5 * 60 * 1000) return res.status(401).send('Webhook too old');
// Process the webhook...
res.status(200).send('OK');
});
Important: Always verify the signature before processing webhooks.
Note: Use express.raw() instead of express.json() to get the unparsed body. The signature is computed over the exact bytes sent - if Express parses and re-serializes the JSON, whitespace differences will cause signature mismatches.
Events
user.unlinked
Sent when a user’s connection to your application is severed.
Triggers:
- User revokes your application’s access
- User deletes their account
- Application banned and user connections cleaned up (after 1 year)
Payload:
{
"event": "user.unlinked",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"user_id": "derived-user-uuid"
}
}
Action: Delete all user data from your system. The user has revoked access to their data. They can reconnect later if they wish, but you must not retain their data after receiving this event.
test
A test webhook to verify your endpoint is working correctly.
Triggers:
- Developer clicks “Send Test Webhook” in the Dashboard
Payload:
{
"event": "test",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"message": "This is a test webhook from Fabi-SC ID"
}
}
Action: Return HTTP 200 to confirm receipt. No other action needed.
Delivery & Retry
- Webhooks are delivered via HTTP POST
- Your endpoint should return HTTP 2xx within 10 seconds
- Failed deliveries are retried up to 5 times with exponential backoff:
- 1st retry: 1 minute
- 2nd retry: 5 minutes
- 3rd retry: 30 minutes
- 4th retry: 2 hours
- 5th retry: 12 hours
- After 5 failed attempts, the webhook is marked as failed
Security
Your Webhook URL must:
- Use HTTPS (required)
- Use a domain name (IP addresses are not allowed)
- Be publicly accessible
These restrictions prevent Server-Side Request Forgery (SSRF) attacks.
Best Practices
- Always verify signatures - Never process unverified webhooks
- Check the timestamp - Reject webhooks with timestamps older than 5 minutes to prevent replay attacks
- Respond quickly - Return 200 immediately, then process asynchronously
- Be idempotent - The same webhook might be delivered multiple times
- Handle unknown events - Ignore event types you don’t recognize (for forward compatibility)
Testing
Use the “Send Test Webhook” button in your application settings to:
- Verify your endpoint is reachable
- Confirm signature verification is working
- Test your webhook handling logic