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

Webhook Sequence Diagram

Setting Up Webhooks

Configure Organization Webhook

  1. Navigate to SettingsDeveloper
  2. Enter your webhook URL (e.g., https://your-app.com/webhooks/docgenlab)
  3. Click Test Webhook to verify
  4. Click Save Webhook URL
tip

Use a tool like webhook.site to test and inspect webhook payloads during development.

Webhook Payload

When a document completes, DocGenLab sends a POST request:

{
"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 download_url is a signed URL that:

  • Is valid for 24 hours
  • Allows direct download without authentication
  • Bypasses API rate limits

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
doc_url = payload['download_url']
response = requests.get(doc_url)

# Save or process the file
with open(f"document_{payload['job_id']}.pdf", 'wb') as f:
f.write(response.content)

# Send notification, update database, etc.
print(f"Document {payload['job_id']} ready!")

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) => {
const payload = req.body;

if (payload.status === 'completed') {
// Download the document
const response = await axios.get(payload.download_url, {
responseType: 'arraybuffer'
});

// Save the file
fs.writeFileSync(`document_${payload.job_id}.pdf`, response.data);

console.log(`Document ${payload.job_id} ready!`);
}

res.status(200).json({ status: 'ok' });
});

app.listen(3000);

Best Practices

Security

1. Validate the Webhook

Always validate that the webhook came from DocGenLab:

# Option 1: IP Whitelist
DOCGENLAB_IPS = ['34.123.45.67']

if request.remote_addr not in DOCGENLAB_IPS:
return jsonify({'error': 'unauthorized'}), 403

2. Use HTTPS

Always use HTTPS endpoints:

  • Correct: https://your-app.com/webhooks/docgenlab
  • Incorrect: http://your-app.com/webhooks/docgenlab

Reliability

1. Return 200 Quickly

Process webhooks asynchronously:

@app.route('/webhooks/docgenlab', methods=['POST'])
def handle_webhook():
payload = request.json

# Queue for background processing
queue.enqueue(process_document, payload)

# Return immediately
return jsonify({'status': 'ok'}), 200

def process_document(payload):
# Download and process in background
pass

2. Handle Retries

DocGenLab retries failed webhooks:

  • 1st retry: after 1 minute
  • 2nd retry: after 5 minutes
  • 3rd retry: after 15 minutes

Make your endpoint idempotent (safe to call multiple times):

def handle_webhook():
payload = request.json
job_id = payload['job_id']

# Check if already processed
if redis.exists(f'processed:{job_id}'):
return jsonify({'status': 'already_processed'}), 200

# Process...

# Mark as processed
redis.set(f'processed:{job_id}', 1, ex=86400)

return jsonify({'status': 'ok'}), 200

Testing Webhooks

Test Button

Use the Test Webhook button in Settings to send a test payload:

{
"event": "webhook.test",
"message": "This is a test webhook from DocGenLab"
}

Local Development

Use ngrok to expose your local server:

ngrok http 3000
# Use the ngrok URL in DocGenLab settings
# Example: https://abc123.ngrok.io/webhooks/docgenlab

FAQ

Q: When are webhooks triggered?

Only for API-generated documents, not UI-generated. This prevents unnecessary webhook calls during manual testing.

Q: What if my webhook endpoint is down?

DocGenLab retries up to 3 times. After that, the webhook is dropped (but the document is still available via API).

Q: Can I use different webhooks for different templates?

Yes! Pass webhook_url in the API request to override the org-level setting (coming soon).

Next Steps