Webhooks Guide
Get real-time notifications when documents are generated.
What are Webhooks?
Webhooks are HTTP callbacks that DocGenLab sends to your server when a document generation completes. Perfect for:
- Asynchronous workflows
- Integration with other systems
- Real-time notifications
- Event-driven architectures
How Webhooks Work
- You submit a document generation request via API.
- DocGenLab processes the document asynchronously.
- When complete, DocGenLab POSTs a JSON payload to your webhook URL.
- Your server receives the payload and processes it (downloads the file, updates your DB, etc.).
Setting Up Webhooks
Option 1 — Organisation-level webhook (default for all API requests)
- Navigate to Settings → Developer
- Enter your webhook URL (e.g.,
https://your-app.com/webhooks/docgenlab) - Click Save Webhook URL
Option 2 — Per-request webhook (overrides org setting)
Pass webhook_url in any document generation request to use a different URL for that job:
{
"template_id": "abc-123",
"input_json": { "name": "John" },
"output_format": "pdf",
"webhook_url": "https://your-app.com/webhooks/specific-flow"
}
Use webhook.site to inspect live webhook payloads during development without setting up a server.
Webhook Payload
When a document completes, DocGenLab sends a POST request with this body:
{
"event": "document.generated",
"job_id": "abc-123-def-456",
"status": "completed",
"download_url": "https://storage.googleapis.com/...",
"metadata": {
"template_id": "template-xyz",
"created_at": "2024-01-15T10:30:00Z",
"error_message": null
}
}
download_url
The signed URL is:
- Valid for 24 hours
- Allows direct download without authentication
- Works with any HTTP client (
curl,requests,axios, etc.)
Implementing a Webhook Handler
Python (Flask)
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
@app.route('/webhooks/docgenlab', methods=['POST'])
def handle_webhook():
payload = request.json
if payload['status'] == 'completed':
# Download the document via the signed URL
response = requests.get(payload['download_url'])
with open(f"document_{payload['job_id']}.pdf", 'wb') as f:
f.write(response.content)
print(f"Document {payload['job_id']} saved!")
return jsonify({'status': 'ok'}), 200
Node.js (Express)
const express = require('express');
const axios = require('axios');
const fs = require('fs');
const app = express();
app.use(express.json());
app.post('/webhooks/docgenlab', async (req, res) => {
// Respond immediately — process in the background
res.status(200).json({ status: 'ok' });
const { status, download_url, job_id } = req.body;
if (status === 'completed') {
const response = await axios.get(download_url, { responseType: 'arraybuffer' });
fs.writeFileSync(`document_${job_id}.pdf`, response.data);
console.log(`Document ${job_id} saved!`);
}
});
app.listen(3000);
Best Practices
Security — use HTTPS
DocGenLab only delivers webhooks to HTTPS endpoints. HTTP URLs are rejected.
✅ https://your-app.com/webhooks/docgenlab
❌ http://your-app.com/webhooks/docgenlab
Respond quickly (under 5 seconds)
Return 200 OK immediately, then process asynchronously. Long-running handlers risk timeouts.
@app.route('/webhooks/docgenlab', methods=['POST'])
def handle_webhook():
payload = request.json
queue.enqueue(process_document, payload) # background task
return jsonify({'status': 'ok'}), 200 # respond immediately
Make your handler idempotent
DocGenLab retries failed webhook deliveries up to 3 times with short backoff (a few seconds between attempts). Your handler may be called more than once for the same job — guard against duplicate processing:
def handle_webhook():
job_id = request.json['job_id']
if redis.exists(f'processed:{job_id}'):
return jsonify({'status': 'already_processed'}), 200
# ... process ...
redis.set(f'processed:{job_id}', 1, ex=86400) # remember for 24h
return jsonify({'status': 'ok'}), 200
Testing
Local development with ngrok
ngrok http 3000
# Copy the https URL shown, e.g. https://abc123.ngrok.io
# Paste it into Settings → Developer → Webhook URL
Test payload button
Use the Test Webhook button in Settings → Developer to send a test payload:
{
"event": "webhook.test",
"message": "This is a test webhook from DocGenLab"
}
FAQ
Q: When are webhooks triggered? Only for documents generated via the API. Documents generated manually through the UI do not fire webhooks.
Q: What if my endpoint is down? DocGenLab retries up to 3 times. After that the webhook is dropped, but the document is still available to download via the API using the document ID.
Q: Can I use a different webhook for each template?
Yes — pass webhook_url in the API request body (see Option 2 above).