Shablonix

Webhooks

Receive real-time notifications when events occur in your Shablonix account.

Overview

Webhooks POST to your HTTPS URL when a PDF generation finishes or fails. Configure them once in Settings or via the SDK. They fire even when POST /v1/generate already returned the completed file in the same response.

Use them 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 SettingsWebhooks 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 on a generate call for an unsigned callback on that job only. Account webhooks stay signed and still fire.

curl -sS -X POST https://api.shablonix.online/v1/generate \
  -H "Authorization: Bearer tf_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "meridian-invoice",
    "data": { "invoice": { "number": "INV-001" } },
    "async": true,
    "webhook_url": "https://your-app.com/webhooks/generation"
  }'
Per-request callbacks use event names like generation.completed and are not HMAC-signed. Verify account webhooks with constructWebhookEvent.

3. API Configuration

Configure account-level webhooks programmatically using the API:

MethodEndpointDescription
POST/v1/webhooks/settingsConfigure webhook endpoint
GET/v1/webhooks/settingsGet current webhook configuration
DELETE/v1/webhooks/settingsRemove webhook configuration
POST/v1/webhooks/settings/testSend a test webhook event
import { Shablonix } from '@shablonix/sdk';

const client = new Shablonix(process.env.SHABLONIX_API_KEY!);

const config = await client.configureWebhook({
  url: 'https://your-app.com/webhooks/shablonix',
  events: ['document.completed', 'document.failed', 'batch.completed'],
});

console.log(config.secret);

Requires the webhooks:read and webhooks:write API key scopes.

4. Zapier and Make REST hooks

Account settings keep one URL per user. Zapier and Make subscribe through POST /v1/hooks instead, so turning on a Zap does not overwrite the production webhook. Events fan out to both.

MethodEndpointDescription
POST/v1/hooksRegister an extra destination (source: zapier or make)
DELETE/v1/hooks/:idRemove that destination (idempotent)
Private Zapier and Make apps live in integrations/. They POST template_id / format / async: true to https://api.shablonix.online. Status values are lowercase (completed, not COMPLETED).

Use with async generate

Typical production pattern: enqueue a PDF with async: true, then wait for document.completed instead of holding the generate HTTP call. Polling status_url still works if you cannot receive POSTs. Full enqueue, poll, and download examples (cURL, Node, SDK) are on Generate PDF → Async generation.

  1. 1. POST /v1/webhooks/settings once.
  2. 2. POST /v1/generate with async: true. Store the id.
  3. 3. On document.completed, GET the payload file_url with the same API key (or downloadGenerationBytes(id) in the SDK).
# 1. Account webhook (once)
curl -sS -X POST https://api.shablonix.online/v1/webhooks/settings \
  -H "Authorization: Bearer tf_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example/webhooks/shablonix",
    "events": ["document.completed", "document.failed"]
  }'

# 2. Enqueue
curl -sS -X POST https://api.shablonix.online/v1/generate \
  -H "Authorization: Bearer tf_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "meridian-invoice",
    "data": { "invoice": { "number": "INV-001" } },
    "async": true
  }'

# 3. After the webhook: download with the generation id
curl -sS https://api.shablonix.online/v1/generate/GENERATION_ID/download \
  -H "Authorization: Bearer tf_live_your_api_key" \
  --output invoice.pdf

Payload Format

Webhook payloads are sent as JSON via HTTP POST requests:

{
  "id": "evt_abc123xyz",
  "type": "document.completed",
  "created_at": "2026-08-25T10:30:00Z",
  "api_version": "2024-01-01",
  "data": {
    "id": "a1b2c3d4",
    "status": "completed",
    "template_id": "meridian-invoice",
    "file_url": "/v1/generate/a1b2c3d4/download",
    "status_url": "/v1/generate/a1b2c3d4",
    "file_size": 142857,
    "render_time_ms": 234
  }
}

HTTP Headers

Each webhook request includes these headers:

HeaderDescription
Content-TypeAlways application/json
X-Shablonix-SignatureHMAC-SHA256 signature for verification
X-Shablonix-TimestampUnix timestamp when the webhook was sent
X-Shablonix-EventEvent type (e.g., document.completed)
X-Shablonix-Delivery-IDUnique ID for this delivery attempt

Event Types

Subscribe to specific events based on your needs:

Document Events

EventDescription
document.completedPDF generated successfully. Includes file_url.
document.failedDocument generation failed

Batch Events

EventDescription
batch.progressPeriodic progress while a batch is running
batch.completedBatch finished (some items may have failed)
batch.failedEvery item in the batch failed

Signature Verification

Always verify webhook signatures to ensure requests are from Shablonix and haven't been tampered with.

Verification Steps

  1. 1 Extract the signature from the X-Shablonix-Signature header
  2. 2 Get the timestamp from the X-Shablonix-Timestamp header
  3. 3 Concatenate the timestamp and raw request body: {timestamp}.{body}
  4. 4 Compute HMAC-SHA256 using your webhook secret
  5. 5 Compare signatures using constant-time comparison

Code Examples

import { Shablonix, constructWebhookEvent } from '@shablonix/sdk';
import express from 'express';

const client = new Shablonix(process.env.SHABLONIX_API_KEY!);
const app = express();

app.post(
  '/webhooks/shablonix',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    const event = await constructWebhookEvent(
      req.body,
      req.headers,
      process.env.SHABLONIX_WEBHOOK_SECRET!,
    );

    if (event.type === 'document.completed') {
      const pdf = await client.downloadGenerationBytes(event.data.id);
      console.log('stored', pdf.byteLength, 'bytes');
    }

    res.status(200).json({ received: true });
  },
);

Retry Policy

Shablonix automatically retries failed webhook deliveries with exponential backoff.

Retry Schedule

AttemptDelayCumulative Time
1 (initial)Immediate0
21 minute1 minute
35 minutes6 minutes
430 minutes36 minutes
52 hours~2.5 hours
68 hours~10.5 hours
7 (final)24 hours~34.5 hours

Success Criteria

A webhook delivery is considered successful when your endpoint:

  • - Returns a 2xx status code
  • - Responds within 30 seconds
If your endpoint does not respond within 30 seconds, the request is considered failed and will be retried.

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.

Always download generated files as soon as you receive the webhook notification. After expiration, files are permanently deleted and cannot be recovered. See the Data Retention page for full details and best practices.

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.