Webhooks
Receive real-time notifications when events occur in your Shablonix account.
Overview
Webhooks allow you to receive HTTP callbacks when specific events occur, such as when a document is generated or a template is updated. This enables you to:
- Build async workflows for document generation
- Sync generated documents to your storage
- Send notifications when documents are ready
- Track document generation analytics
Webhook Setup
You can configure webhooks in two ways:
1. Dashboard Configuration
Navigate to Settings → Webhooks in your dashboard to:
- - Add webhook endpoints
- - Select which events to subscribe to
- - View delivery logs and retry failed deliveries
- - Manage webhook secrets
2. Per-Request Webhooks
Include a webhook_url in your API request to
receive a callback for that specific operation:
{
"template_id": "tpl_invoice_basic",
"data": { ... },
"webhook_url": "https://your-app.com/webhooks/shablonix",
"webhook_secret": "your_webhook_secret"
}
3. API Configuration
Configure account-level webhooks programmatically using the API:
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/webhooks/settings | Configure webhook endpoint |
GET | /v1/webhooks/settings | Get current webhook configuration |
DELETE | /v1/webhooks/settings | Remove webhook configuration |
POST | /v1/webhooks/settings/test | Send a test webhook event |
# Configure account webhook
curl -X POST https://api.shablonix.com/v1/webhooks/settings \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/shablonix",
"events": ["document.completed", "document.failed", "batch.completed"]
}'
# Response includes auto-generated secret if not provided:
# {
# "configured": true,
# "url": "https://your-app.com/webhooks/shablonix",
# "secret": "a1b2c3d4...",
# "events": ["document.completed", "document.failed", "batch.completed"],
# "created_at": "2024-01-15T10:00:00.000Z",
# "updated_at": "2024-01-15T10:00:00.000Z"
# }
Requires the webhooks:read and webhooks:write API key scopes.
Payload Format
Webhook payloads are sent as JSON via HTTP POST requests:
{
"id": "evt_abc123xyz",
"type": "document.completed",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"id": "doc_7f3k9x2m1n",
"object": "document",
"status": "completed",
"template_id": "tpl_invoice_basic",
"pdf_url": "https://cdn.shablonix.com/docs/doc_7f3k9x2m1n.pdf",
"pdf_size": 142857,
"page_count": 2,
"created_at": "2024-01-15T10:30:00Z",
"expires_at": "2024-01-16T10:30:00Z",
"metadata": {
"render_time_ms": 234,
"request_id": "req_xyz789"
}
},
"api_version": "2024-01-01"
}
HTTP Headers
Each webhook request includes these headers:
| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Shablonix-Signature | HMAC-SHA256 signature for verification |
X-Shablonix-Timestamp | Unix timestamp when the webhook was sent |
X-Shablonix-Event | Event type (e.g., document.completed) |
X-Shablonix-Delivery-ID | Unique ID for this delivery attempt |
Event Types
Subscribe to specific events based on your needs:
Document Events
| Event | Description |
|---|---|
document.processing | Document generation has started |
document.completed | Document generated successfully |
document.failed | Document generation failed |
Template Events
| Event | Description |
|---|---|
template.created | New template created |
template.updated | Template updated (new version) |
template.deleted | Template deleted |
Signature Verification
Always verify webhook signatures to ensure requests are from Shablonix and haven't been tampered with.
Verification Steps
- 1 Extract the signature from the
X-Shablonix-Signatureheader - 2 Get the timestamp from the
X-Shablonix-Timestampheader - 3 Concatenate the timestamp and raw request body:
{timestamp}.{body} - 4 Compute HMAC-SHA256 using your webhook secret
- 5 Compare signatures using constant-time comparison
Code Examples
import crypto from 'crypto';
function verifyWebhookSignature(payload, headers, secret) {
const signature = headers['x-shablonix-signature'];
const timestamp = headers['x-shablonix-timestamp'];
// Check timestamp to prevent replay attacks (5 min tolerance)
const currentTime = Math.floor(Date.now() / 1000);
if (Math.abs(currentTime - parseInt(timestamp)) > 300) {
throw new Error('Webhook timestamp too old');
}
// Compute expected signature
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Constant-time comparison
const signatureBuffer = Buffer.from(signature, 'hex');
const expectedBuffer = Buffer.from(expectedSignature, 'hex');
if (!crypto.timingSafeEqual(signatureBuffer, expectedBuffer)) {
throw new Error('Invalid webhook signature');
}
return true;
}
// Express.js example
app.post('/webhooks/shablonix', express.raw({ type: 'application/json' }), (req, res) => {
try {
verifyWebhookSignature(
req.body.toString(),
req.headers,
process.env.SHABLONIX_WEBHOOK_SECRET
);
const event = JSON.parse(req.body);
switch (event.type) {
case 'document.completed':
console.log('Document ready:', event.data.pdf_url);
break;
case 'document.failed':
console.error('Generation failed:', event.data.error);
break;
}
res.status(200).json({ received: true });
} catch (error) {
console.error('Webhook error:', error.message);
res.status(400).json({ error: error.message });
}
});
Retry Policy
Shablonix automatically retries failed webhook deliveries with exponential backoff.
Retry Schedule
| Attempt | Delay | Cumulative Time |
|---|---|---|
| 1 (initial) | Immediate | 0 |
| 2 | 1 minute | 1 minute |
| 3 | 5 minutes | 6 minutes |
| 4 | 30 minutes | 36 minutes |
| 5 | 2 hours | ~2.5 hours |
| 6 | 8 hours | ~10.5 hours |
| 7 (final) | 24 hours | ~34.5 hours |
Success Criteria
A webhook delivery is considered successful when your endpoint:
- - Returns a
2xxstatus code - - Responds within 30 seconds
Data Retention
Generated documents are automatically deleted after 24 hours. Webhook
payloads for completed documents include an expires_at field so your system knows when
the file will no longer be available for download.
Best Practices
1. Respond Quickly
Return a 200 response immediately after receiving the webhook. Process the event asynchronously using a job queue to avoid timeouts.
2. Handle Duplicates
Webhooks may be delivered multiple times. Use the event id to deduplicate.
// Store processed event IDs
const processedEvents = new Set();
app.post('/webhooks/shablonix', (req, res) => {
const event = req.body;
if (processedEvents.has(event.id)) {
return res.status(200).json({ received: true, duplicate: true });
}
processedEvents.add(event.id);
// Process event...
res.status(200).json({ received: true });
});
3. Always Verify Signatures
Never skip signature verification, even in development. This protects against webhook spoofing attacks.
4. Use HTTPS
Webhook endpoints must use HTTPS. HTTP endpoints are rejected in production environments.
5. Monitor Failures
Set up alerts for webhook failures in your dashboard. Repeated failures may indicate issues with your endpoint.
6. Log Webhook Payloads
Log incoming webhooks for debugging. Include the delivery ID and timestamp for easier troubleshooting.