Receive real-time notifications when events occur in your organization. Webhooks allow you to build reactive integrations that respond immediately to QR code scans and other events.
Get notified instantly when events occur, no polling required
HMAC signatures verify that webhooks come from iloveQR
Automatic retries with exponential backoff for failed deliveries
Configure webhooks through the dashboard or API to start receiving events.
Set up an HTTPS endpoint on your server to receive webhook payloads.
Add your endpoint URL and select which events to subscribe to.
Implement signature verification to ensure payloads are authentic.
curl -X POST \
"https://api.iloveqr.com/api/v1/organizations/org_abc123/webhooks" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/iloveqr",
"events": ["qr.scanned", "qr.created", "qr.updated"],
"secret": "your_webhook_secret"
}'Subscribe to the events you need. Each event type has a specific payload structure.
qr.createdA new QR code was createdqr.updatedA QR code was updatedqr.deletedA QR code was deletedqr.scannedA QR code was scannedqr.archivedA QR code was archivedqr.restoredA QR code was restored from archivesubscription.createdA new subscription was createdsubscription.updatedA subscription was updatedsubscription.cancelledA subscription was cancelledsubscription.payment_succeededA payment was successfulsubscription.payment_failedA payment failedmember.joinedA member joined the organizationmember.leftA member left the organizationmember.role_changedA member's role was changedAll webhook payloads follow a consistent structure with event metadata and data.
{
"id": "evt_1a2b3c4d5e6f",
"event": "qr.scanned",
"createdAt": "2024-01-15T14:30:00Z",
"organizationId": "org_abc123",
"data": {
"qrCodeId": "qr_xyz789",
"qrCodeName": "Product Landing Page",
"shortCode": "xyz789",
"destinationUrl": "https://example.com/product",
"scan": {
"id": "scan_123abc",
"timestamp": "2024-01-15T14:30:00Z",
"location": {
"country": "US",
"city": "New York",
"latitude": 40.7128,
"longitude": -74.0060
},
"device": {
"type": "mobile",
"os": "iOS",
"browser": "Safari"
},
"isUnique": true
}
}
}{
"id": "evt_7g8h9i0j1k2l",
"event": "qr.created",
"createdAt": "2024-01-15T10:00:00Z",
"organizationId": "org_abc123",
"data": {
"qrCode": {
"id": "qr_newcode",
"type": "URL",
"name": "New Campaign QR",
"shortUrl": "https://ilqr.co/newcode",
"destinationUrl": "https://example.com/campaign",
"createdBy": "user_abc123"
}
}
}Always verify webhook signatures to ensure the payload came from iloveQR and wasn't tampered with in transit.
Each webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 signature of the request body.
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler
app.post('/webhooks/iloveqr', (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook
const event = req.body;
console.log('Received event:', event.event);
res.status(200).send('OK');
});import hmac
import hashlib
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your Flask handler
@app.route('/webhooks/iloveqr', 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()
print(f"Received event: {event['event']}")
return 'OK', 200Return a 2xx response within 5 seconds. Process webhooks asynchronously if your handling takes longer.
Store the event ID and check for duplicates. Webhooks may be delivered more than once in rare cases.
Always use HTTPS endpoints. We don't deliver webhooks to HTTP URLs.
Set up monitoring for webhook delivery failures. Check the webhook logs in the dashboard for debugging.
If your endpoint returns an error or doesn't respond, we automatically retry delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry (final) | 24 hours |
Note: After 5 failed attempts, the webhook is marked as failed and we stop retrying. You'll receive an email notification about the failure.
Ready to get started? Explore more resources: