Skip to main content

Webhook Integration

FireBackup can send HTTP webhooks to notify your systems about backup events in real-time. Use webhooks to integrate with monitoring systems, trigger automation workflows, or build custom notification systems.

Overview

Webhooks provide:

  • Real-time notifications for all backup events
  • Customizable payloads with template variables
  • Retry logic for failed deliveries
  • HMAC signatures for payload verification
  • Delivery history for debugging

Quick Start

Create a Webhook

Using the Dashboard:

  1. Go to SettingsWebhooks
  2. Click Add Webhook
  3. Enter your endpoint URL
  4. Select events to monitor
  5. Click Save

Using the API:

curl -X POST https://api.firebackup.io/api/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "My Webhook",
"url": "https://your-server.com/webhooks/firebackup",
"events": ["backup.completed", "backup.failed"],
"secret": "your-webhook-secret"
}'

Webhook Events

Available Events

EventDescriptionTrigger
backup.startedBackup job initiatedImmediate
backup.progressBackup progress updateEvery 10%
backup.completedBackup finished successfullyOn completion
backup.failedBackup encountered an errorOn failure
restore.startedRestore operation initiatedImmediate
restore.progressRestore progress updateEvery 10%
restore.completedRestore finished successfullyOn completion
restore.failedRestore encountered an errorOn failure
pitr.enabledPITR enabled for projectOn change
pitr.disabledPITR disabled for projectOn change
pitr.change_capturedNew PITR changes recordedBatched
schedule.createdNew schedule createdOn creation
schedule.updatedSchedule modifiedOn update
schedule.deletedSchedule removedOn deletion
schedule.triggeredScheduled backup startedOn trigger
schedule.failedScheduled backup missedOn miss
storage.connectedStorage destination addedOn creation
storage.errorStorage connectivity issueOn error
project.createdNew project addedOn creation
project.deletedProject removedOn deletion

Subscribing to Events

Subscribe to specific events or use wildcards:

{
"events": ["backup.completed", "backup.failed"]
}
{
"events": ["backup.*"]
}
{
"events": ["*"]
}

Webhook Payload

Standard Payload Format

{
"id": "evt_abc123def456",
"type": "backup.completed",
"timestamp": "2024-01-15T10:30:45.123Z",
"data": {
"backup": {
"id": "bkp_xyz789",
"projectId": "proj_abc123",
"type": "full",
"status": "completed",
"size": 131072000,
"sizeFormatted": "125 MB",
"duration": 272000,
"durationFormatted": "4m 32s",
"storageDestination": {
"id": "stor_def456",
"name": "Production S3",
"type": "s3"
},
"collections": ["users", "orders", "products"],
"documentCount": 125000,
"createdAt": "2024-01-15T10:26:13.000Z",
"completedAt": "2024-01-15T10:30:45.123Z"
},
"project": {
"id": "proj_abc123",
"name": "Production App",
"firebaseProjectId": "my-app-prod"
},
"organization": {
"id": "org_abc123",
"name": "Acme Corp"
}
},
"metadata": {
"trigger": "scheduled",
"scheduleId": "sch_abc123",
"attempt": 1,
"deliveryId": "del_abc123"
}
}

Event-Specific Payloads

backup.failed:

{
"id": "evt_abc123def456",
"type": "backup.failed",
"timestamp": "2024-01-15T10:30:45.123Z",
"data": {
"backup": {
"id": "bkp_xyz789",
"status": "failed",
"error": {
"code": "FIREBASE_AUTH_ERROR",
"message": "Failed to authenticate with Firebase",
"details": "Token expired or invalid"
}
},
"project": { ... },
"organization": { ... }
},
"metadata": {
"trigger": "scheduled",
"attempt": 3,
"maxAttempts": 3,
"willRetry": false
}
}

pitr.change_captured:

{
"id": "evt_abc123def456",
"type": "pitr.change_captured",
"timestamp": "2024-01-15T10:30:45.123Z",
"data": {
"project": {
"id": "proj_abc123",
"name": "Production App"
},
"changes": {
"count": 150,
"fromTimestamp": "2024-01-15T10:25:00.000Z",
"toTimestamp": "2024-01-15T10:30:00.000Z",
"collections": ["users", "orders"]
}
}
}

Security

HMAC Signature Verification

FireBackup signs all webhook payloads with HMAC-SHA256. Verify signatures to ensure authenticity:

Headers sent with each request:

X-FireBackup-Signature: sha256=abc123...
X-FireBackup-Timestamp: 1705315845
X-FireBackup-Delivery-Id: del_abc123

Verification process:

const crypto = require('crypto');

function verifyWebhook(payload, signature, timestamp, secret) {
// Check timestamp is recent (within 5 minutes)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
return false;
}

// Compute expected signature
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');

// Compare signatures
const expected = `sha256=${expectedSignature}`;
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}

// Express middleware example
app.post('/webhooks/firebackup', (req, res) => {
const signature = req.headers['x-firebackup-signature'];
const timestamp = req.headers['x-firebackup-timestamp'];
const payload = JSON.stringify(req.body);

if (!verifyWebhook(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}

// Process webhook
handleWebhookEvent(req.body);
res.status(200).json({ received: true });
});

Python example:

import hmac
import hashlib
import time

def verify_webhook(payload, signature, timestamp, secret):
# Check timestamp
now = int(time.time())
if abs(now - int(timestamp)) > 300:
return False

# Compute signature
signed_payload = f"{timestamp}.{payload}"
expected = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()

return hmac.compare_digest(f"sha256={expected}", signature)

Delivery & Retries

Retry Policy

Failed webhook deliveries are retried with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

After 5 failed attempts, the delivery is marked as failed.

Success Criteria

A webhook is considered successful when:

  • HTTP status code is 2xx (200-299)
  • Response is received within 30 seconds

Viewing Delivery History

curl -X GET "https://api.firebackup.io/api/v1/webhooks/whk_abc123/deliveries" \
-H "Authorization: Bearer YOUR_API_KEY"

Response:

{
"deliveries": [
{
"id": "del_abc123",
"eventType": "backup.completed",
"status": "delivered",
"statusCode": 200,
"timestamp": "2024-01-15T10:30:45Z",
"duration": 245,
"attempts": 1
},
{
"id": "del_def456",
"eventType": "backup.failed",
"status": "failed",
"statusCode": 500,
"timestamp": "2024-01-15T09:15:30Z",
"duration": 5000,
"attempts": 5,
"lastError": "Connection timeout"
}
]
}

Retry a Delivery

curl -X POST "https://api.firebackup.io/api/v1/webhooks/whk_abc123/deliveries/del_abc123/retry" \
-H "Authorization: Bearer YOUR_API_KEY"

Configuration

Webhook Settings

SettingTypeDescriptionDefault
namestringDisplay nameRequired
urlstringEndpoint URLRequired
eventsarrayEvents to subscribeRequired
secretstringHMAC signing secretAuto-generated
enabledbooleanEnable/disabletrue
headersobjectCustom headers{}
timeoutnumberRequest timeout (ms)30000
retryEnabledbooleanEnable retriestrue

Custom Headers

Add custom headers to webhook requests:

curl -X PATCH https://api.firebackup.io/api/v1/webhooks/whk_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"headers": {
"X-Custom-Header": "my-value",
"Authorization": "Bearer my-service-token"
}
}'

Filters

Filter events by project or other criteria:

curl -X PATCH https://api.firebackup.io/api/v1/webhooks/whk_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"filters": {
"projects": ["proj_abc123", "proj_def456"],
"trigger": ["scheduled"],
"excludeTrigger": ["manual"]
}
}'

Integration Examples

AWS Lambda

// Lambda handler
exports.handler = async (event) => {
const body = JSON.parse(event.body);

// Verify signature
if (!verifySignature(event)) {
return { statusCode: 401 };
}

// Handle event
switch (body.type) {
case 'backup.completed':
await notifySlack(body.data);
break;
case 'backup.failed':
await createPagerDutyIncident(body.data);
break;
}

return { statusCode: 200 };
};

Google Cloud Functions

const functions = require('@google-cloud/functions-framework');

functions.http('firebackupWebhook', async (req, res) => {
if (!verifySignature(req)) {
return res.status(401).send('Unauthorized');
}

const event = req.body;

if (event.type === 'backup.failed') {
await sendAlertToCloudMonitoring(event.data);
}

res.status(200).send('OK');
});

Zapier

Create a Zapier integration:

  1. Create a new Zap
  2. Choose "Webhooks by Zapier" as trigger
  3. Select "Catch Hook"
  4. Copy the webhook URL
  5. Add to FireBackup as a webhook
  6. Configure Zapier actions (email, Slack, etc.)

Make (Integromat)

  1. Create a new scenario
  2. Add "Webhooks" module → "Custom webhook"
  3. Copy the webhook URL
  4. Add to FireBackup
  5. Build your automation flow

Testing

Test Endpoint

Send a test webhook to verify your endpoint:

curl -X POST https://api.firebackup.io/api/v1/webhooks/whk_abc123/test \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"event": "backup.completed"
}'

Local Development

Use ngrok or similar tools to test webhooks locally:

# Start ngrok
ngrok http 3000

# Use the ngrok URL as your webhook endpoint
# https://abc123.ngrok.io/webhooks/firebackup

Webhook Debugging

View raw request details:

curl -X GET "https://api.firebackup.io/api/v1/webhooks/whk_abc123/deliveries/del_abc123/request" \
-H "Authorization: Bearer YOUR_API_KEY"

Best Practices

Do's

  • Respond quickly - Return 200 within 5 seconds, process async
  • Verify signatures - Always validate HMAC signatures
  • Handle duplicates - Use deliveryId for idempotency
  • Log everything - Keep records for debugging
  • Use HTTPS - Never use HTTP for webhooks

Don'ts

  • Don't trust payload - Validate even with signatures
  • Don't block - Process webhooks asynchronously
  • Don't ignore retries - Handle duplicate deliveries
  • Don't hardcode secrets - Use environment variables

Idempotency

Use the delivery ID to prevent duplicate processing:

const processedDeliveries = new Set();

async function handleWebhook(event, deliveryId) {
if (processedDeliveries.has(deliveryId)) {
console.log('Duplicate delivery, skipping');
return;
}

processedDeliveries.add(deliveryId);

// Process the event
await processEvent(event);
}

Troubleshooting

Webhook Not Receiving Events

  1. Check webhook is enabled in dashboard
  2. Verify URL is correct and accessible
  3. Check event subscription matches expected events
  4. Review firewall rules - allow FireBackup IPs

Signature Verification Failing

  1. Check secret matches webhook configuration
  2. Verify payload isn't modified by middleware
  3. Check timestamp is within 5 minutes

Timeouts

  1. Return 200 immediately and process async
  2. Increase timeout if needed (max 60 seconds)
  3. Check endpoint performance