Skip to main content

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

  1. You submit a document generation request via API.
  2. DocGenLab processes the document asynchronously.
  3. When complete, DocGenLab POSTs a JSON payload to your webhook URL.
  4. 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)

  1. Navigate to Settings → Developer
  2. Enter your webhook URL (e.g., https://your-app.com/webhooks/docgenlab)
  3. 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"
}
Testing

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).


Next Steps