Skip to main content

Node.js / TypeScript Examples

Complete examples for using the DocGenLab API with axios.

npm install axios

Setup

import axios from 'axios';
import fs from 'fs';

const API_KEY = process.env.DOCGENLAB_API_KEY!; // dgl_...
const BASE_URL = 'https://api.docgenlab.com/api/v1';

const client = axios.create({
baseURL: BASE_URL,
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json',
},
});

TypeScript Types

interface TokenDefinition {
key: string; // e.g. "invoice_number"
label: string; // human-readable label
type: 'string' | 'list' | 'image' | 'date';
required?: boolean;
children?: TokenDefinition[]; // child keys for list tokens
}

interface Template {
id: string;
name: string;
description?: string;
tokens_json: TokenDefinition[];
source_type: 'docx' | 'html';
is_uat: boolean;
created_at: string;
}

interface Document {
id: string;
template_id: string;
status: 'queued' | 'rendering' | 'ready' | 'failed';
output_pdf_path?: string;
output_docx_path?: string;
error_message?: string;
created_at: string;
}

Example 1: Generate a Document

async function generateDocument(
templateId: string,
inputData: Record<string, any>,
outputFormat: 'pdf' | 'docx' | 'both' = 'pdf'
): Promise<Document> {
const { data } = await client.post<Document>('/documents/', {
template_id: templateId,
input_json: inputData,
output_format: outputFormat,
});
return data;
}


const doc = await generateDocument(
'your-template-uuid',
{
invoice_number: 'INV-001',
client_name: 'Acme Corp',
amount: 1250.00,
// Pass arrays for {% for %} loops in the template
line_items: [
{ name: 'Consulting', qty: 10, price: 100 },
{ name: 'Support', qty: 5, price: 50 },
],
}
);

console.log(`Document ID : ${doc.id}`);
console.log(`Status : ${doc.status}`);

Example 2: Poll Until Ready and Download

async function waitForDocument(documentId: string, pollMs = 2000, timeoutMs = 120_000): Promise<Document> {
const deadline = Date.now() + timeoutMs;

while (Date.now() < deadline) {
const { data } = await client.get<Document>(`/documents/${documentId}`);

if (data.status === 'ready') return data;
if (data.status === 'failed') throw new Error(`Generation failed: ${data.error_message}`);

await new Promise(r => setTimeout(r, pollMs));
}
throw new Error(`Document ${documentId} not ready after ${timeoutMs}ms`);
}

async function downloadDocument(documentId: string, outputPath: string, format = 'pdf') {
const { data } = await client.get(`/documents/${documentId}/download`, {
params: { format },
responseType: 'arraybuffer',
});
fs.writeFileSync(outputPath, data);
}


// Full workflow
const doc = await generateDocument('your-template-uuid', { name: 'John Doe' });
const ready = await waitForDocument(doc.id);
await downloadDocument(ready.id, 'output.pdf');
console.log('Saved output.pdf');

Example 3: Idempotency Key

Prevents duplicate documents when requests are retried:

async function generateIdempotent(
templateId: string,
inputData: Record<string, any>,
idempotencyKey: string
): Promise<Document> {
const { data } = await client.post<Document>(
'/documents/',
{ template_id: templateId, input_json: inputData, output_format: 'pdf' },
{ headers: { 'X-Idempotency-Key': idempotencyKey } }
);
return data;
}


const doc = await generateIdempotent(
'your-template-uuid',
{ invoice_number: 'INV-001', client_name: 'Acme Corp' },
'invoice-INV-001-acme' // unique per business event
);

Example 4: Express Webhook Handler

import express from 'express';

const app = express();
app.use(express.json());

app.post('/webhooks/docgenlab', async (req, res) => {
// Always respond immediately
res.status(200).json({ status: 'ok' });

const { status, download_url, job_id } = req.body;

if (status === 'completed') {
const { data } = await axios.get(download_url, { responseType: 'arraybuffer' });
fs.writeFileSync(`document_${job_id}.pdf`, data);
console.log(`Saved document_${job_id}.pdf`);
}
});

app.listen(3000);

Example 5: List Templates

async function listTemplates(isUat = false): Promise<Template[]> {
const { data } = await client.get<Template[]>('/templates/', {
params: { is_uat: isUat },
});
return data;
}


const templates = await listTemplates(false); // Production templates

templates.forEach(t => {
const tokenKeys = t.tokens_json.map(tok => tok.key); // field is 'key', not 'name'
console.log(`${t.name} (${t.id})`);
console.log(` Tokens: ${tokenKeys.join(', ')}`);
});

Example 6: Retry with Exponential Backoff

async function generateWithRetry(
templateId: string,
inputData: Record<string, any>,
maxRetries = 3
): Promise<Document> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await generateDocument(templateId, inputData);
} catch (err: any) {
if (err.response?.status === 429) {
const wait = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
console.log(`Rate limited — retrying in ${wait / 1000}s...`);
await new Promise(r => setTimeout(r, wait));
} else {
throw err;
}
}
}
throw new Error('Max retries exceeded');
}

Example 7: Parallel Generation

async function generateMany(templateId: string, rows: Record<string, any>[]) {
const promises = rows.map(row => generateDocument(templateId, row));
const docs = await Promise.all(promises);
docs.forEach(d => console.log(`${d.id}${d.status}`));
return docs;
}


const rows = Array.from({ length: 10 }, (_, i) => ({
customer_name: `Customer ${i + 1}`,
amount: (i + 1) * 100,
}));

await generateMany('your-template-uuid', rows);

Next Steps