DEV Community

Cover image for Building Scalable Document Pipelines: Mastering Autype API for Bulk Rendering and Webhooks
Kevin
Kevin

Posted on • Originally published at autype.com

Building Scalable Document Pipelines: Mastering Autype API for Bulk Rendering and Webhooks

Enterprise document workflows share a common challenge: generating hundreds or thousands of personalized documents without creating a maintenance nightmare. Invoice batches, quarterly reports, personalized contracts, compliance certificates, each requires unique data merged into a consistent template.

The Autype API solves this with a dedicated bulk rendering endpoint that processes up to 100 documents per job in parallel, with webhook callbacks for real-time completion notifications. This guide shows you how to architect production-ready document pipelines that scale.

The Architecture: How Bulk Rendering Works

Autype separates job submission from rendering. When you submit a bulk render job, it enters a queue and processes asynchronously. Each document in the batch renders independently, and the API collects all outputs into a single ZIP file.

Bulk Rendering Workflow

This architecture means your application never blocks waiting for renders. You submit the job, receive a job ID, and continue processing other tasks. When rendering completes, Autype either calls your webhook or you poll for status.

Setting Up Your Environment

Before making API calls, you need an API key from your Autype dashboard (Settings → API Keys). All requests use the X-API-Key header for authentication.

# Store your API key as an environment variable
export AUTYPE_API_KEY="your-api-key-here"

# Base URL for all API calls
BASE_URL="https://api.autype.com/api/v1/dev"
Enter fullscreen mode Exit fullscreen mode

Understanding Template Variables

The bulk rendering system relies on template variables defined in your document. Variables are placeholders that get replaced with actual data at render time. Autype supports several variable types.

Simple Text Variables

The most common use case is text substitution. In your document template, use {{variableName}} syntax:

# Invoice for {{clientName}}

Date: {{invoiceDate}}
Due: {{dueDate}}

Total: {{currency}}{{totalAmount}}
Enter fullscreen mode Exit fullscreen mode

When rendering, you provide the values:

{
  "clientName": "Acme Corporation",
  "invoiceDate": "2024-01-15",
  "dueDate": "2024-02-15",
  "currency": "€",
  "totalAmount": "12,500.00"
}
Enter fullscreen mode Exit fullscreen mode

Complex Variable Types

For more sophisticated templates, Autype supports structured variable types:

List Variables for dynamic bullet points:

{
  "services": {
    "type": "list",
    "items": ["Consulting", "Implementation", "Training"],
    "ordered": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Table Variables for invoice line items or product catalogs:

{
  "lineItems": {
    "type": "table",
    "columns": ["Description", "Quantity", "Unit Price", "Total"],
    "data": [
      ["Consulting Hours", "40", "€150", "€6,000"],
      ["Software License", "1", "€5,000", "€5,000"],
      ["Support Package", "12", "€125", "€1,500"]
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Image Variables for logos and signatures:

{
  "companyLogo": {
    "type": "image",
    "src": "https://your-cdn.com/logo.png",
    "width": 200,
    "align": "center"
  }
}
Enter fullscreen mode Exit fullscreen mode

Creating a Bulk Render Job

The POST /bulk-render endpoint accepts a JSON payload with your template document ID, output format, and an array of variable sets.

Basic Bulk Render Request

curl -X POST "https://api.autype.com/api/v1/dev/bulk-render" \
  -H "X-API-Key: $AUTYPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "documentId": "550e8400-e29b-41d4-a716-446655440000",
    "format": "PDF",
    "items": [
      {
        "clientName": "Acme Corporation",
        "invoiceDate": "2024-01-15",
        "totalAmount": "€12,500.00"
      },
      {
        "clientName": "Beta Industries",
        "invoiceDate": "2024-01-15",
        "totalAmount": "€8,750.00"
      },
      {
        "clientName": "Gamma Solutions",
        "invoiceDate": "2024-01-15",
        "totalAmount": "€15,200.00"
      }
    ]
  }'
Enter fullscreen mode Exit fullscreen mode

The response includes a bulkJobId for tracking:

{
  "bulkJobId": "bulk_abc123def456",
  "status": "PENDING",
  "format": "PDF",
  "totalItems": 3,
  "completedItems": 0,
  "failedItems": 0,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
Enter fullscreen mode Exit fullscreen mode

Using Files for Bulk Data

For large batches, uploading a CSV or Excel file is more practical than embedding data in JSON. The POST /bulk-render/file endpoint accepts multipart form data:

curl -X POST "https://api.autype.com/api/v1/dev/bulk-render/file" \
  -H "X-API-Key: $AUTYPE_API_KEY" \
  -F "file=@invoices.csv" \
  -F "documentId=550e8400-e29b-41d4-a716-446655440000" \
  -F "format=PDF"
Enter fullscreen mode Exit fullscreen mode

Your CSV file should have column headers matching your variable names:

clientName,invoiceDate,totalAmount
Acme Corporation,2024-01-15,€12,500.00
Beta Industries,2024-01-15,€8,750.00
Gamma Solutions,2024-01-15,€15,200.00
Enter fullscreen mode Exit fullscreen mode

Implementing Webhook Callbacks

Polling works for small batches, but webhooks are essential for production systems. When you include a webhook configuration, Autype sends a POST request to your URL when the job completes or fails.

Webhook Configuration

Add the webhook object to your bulk render request:

curl -X POST "https://api.autype.com/api/v1/dev/bulk-render" \
  -H "X-API-Key: $AUTYPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "documentId": "550e8400-e29b-41d4-a716-446655440000",
    "format": "PDF",
    "items": [...],
    "webhook": {
      "url": "https://your-app.com/webhooks/autype/bulk-complete",
      "headers": {
        "X-Webhook-Secret": "your-webhook-secret"
      }
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Handling Webhook Payloads

Your webhook endpoint receives a POST with the job status:

{
  "bulkJobId": "bulk_abc123def456",
  "status": "COMPLETED",
  "format": "PDF",
  "totalItems": 100,
  "completedItems": 98,
  "failedItems": 2,
  "downloadUrl": "https://api.autype.com/api/v1/dev/bulk-render/bulk_abc123def456/download?token=signed-token",
  "completedAt": "2024-01-15T10:35:22.000Z"
}
Enter fullscreen mode Exit fullscreen mode

A typical webhook handler in Node.js:

// Express.js webhook handler
app.post('/webhooks/autype/bulk-complete', async (req, res) => {
  const { bulkJobId, status, downloadUrl, completedItems, failedItems } = req.body;

  // Verify webhook secret
  const secret = req.headers['x-webhook-secret'];
  if (secret !== process.env.WEBHOOK_SECRET) {
    return res.status(401).send('Invalid secret');
  }

  if (status === 'COMPLETED') {
    console.log(`Bulk job ${bulkJobId} completed: ${completedItems} successful, ${failedItems} failed`);

    // Download the ZIP file
    const response = await fetch(downloadUrl);
    const buffer = await response.buffer();

    // Process the ZIP (store in S3, send to users, etc.)
    await storeDocuments(bulkJobId, buffer);

    // Trigger next workflow step
    await notifyComplete(bulkJobId, completedItems, failedItems);
  } else if (status === 'FAILED') {
    console.error(`Bulk job ${bulkJobId} failed`);
    await alertTeam(bulkJobId);
  }

  res.status(200).send('OK');
});
Enter fullscreen mode Exit fullscreen mode

Polling for Job Status

If webhooks are not an option, poll the status endpoint:

curl "https://api.autype.com/api/v1/dev/bulk-render/bulk_abc123def456" \
  -H "X-API-Key: $AUTYPE_API_KEY"
Enter fullscreen mode Exit fullscreen mode

Response when processing:

{
  "bulkJobId": "bulk_abc123def456",
  "status": "PROCESSING",
  "format": "PDF",
  "totalItems": 100,
  "completedItems": 45,
  "failedItems": 0,
  "createdAt": "2024-01-15T10:30:00.000Z"
}
Enter fullscreen mode Exit fullscreen mode

Response when complete:

{
  "bulkJobId": "bulk_abc123def456",
  "status": "COMPLETED",
  "format": "PDF",
  "totalItems": 100,
  "completedItems": 100,
  "failedItems": 0,
  "downloadUrl": "https://api.autype.com/api/v1/dev/bulk-render/bulk_abc123def456/download?token=...",
  "completedAt": "2024-01-15T10:35:22.000Z"
}
Enter fullscreen mode Exit fullscreen mode

Implementing Exponential Backoff Polling

For production systems, implement exponential backoff:

import time
import requests

def wait_for_bulk_job(bulk_job_id, api_key, max_wait_seconds=600):
    base_url = "https://api.autype.com/api/v1/dev"
    headers = {"X-API-Key": api_key}

    wait_time = 2  # Start with 2 seconds
    elapsed = 0

    while elapsed < max_wait_seconds:
        response = requests.get(
            f"{base_url}/bulk-render/{bulk_job_id}",
            headers=headers
        )
        data = response.json()

        if data["status"] == "COMPLETED":
            return data["downloadUrl"]
        elif data["status"] == "FAILED":
            raise Exception(f"Bulk job failed: {data.get('error')}")

        # Still processing, wait and retry
        time.sleep(wait_time)
        elapsed += wait_time
        wait_time = min(wait_time * 1.5, 30)  # Cap at 30 seconds

    raise TimeoutError(f"Bulk job did not complete within {max_wait_seconds} seconds")
Enter fullscreen mode Exit fullscreen mode

Downloading the Results

When a bulk job completes, download the ZIP file containing all rendered documents:

# Using the signed download URL (no API key needed)
curl -o batch.zip "https://api.autype.com/api/v1/dev/bulk-render/bulk_abc123def456/download?token=..."

# Or with API key authentication
curl -o batch.zip \
  -H "X-API-Key: $AUTYPE_API_KEY" \
  "https://api.autype.com/api/v1/dev/bulk-render/bulk_abc123def456/download"
Enter fullscreen mode Exit fullscreen mode

The ZIP file structure preserves order, with documents named by their index:

batch.zip
├── document_001.pdf
├── document_002.pdf
├── document_003.pdf
└── ...
Enter fullscreen mode Exit fullscreen mode

Error Handling and Retry Logic

Production pipelines need robust error handling. Bulk jobs can have partial failures where some documents succeed and others fail.

Handling Partial Failures

Check the failedItems count in the webhook payload or status response:

if (data.failedItems > 0) {
  // Log which items failed
  console.warn(`${data.failedItems} documents failed to render`);

  // Your retry logic here
  const failedIndices = await identifyFailedItems(data.bulkJobId);
  await retryFailedItems(failedIndices);
}
Enter fullscreen mode Exit fullscreen mode

Validation Before Submission

Use the validation endpoint to catch errors before submitting a bulk job:

curl -X POST "https://api.autype.com/api/v1/dev/render/validate" \
  -H "X-API-Key: $AUTYPE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "document": { "type": "pdf" },
      "variables": { "testVar": "value" },
      "sections": [...]
    }
  }'
Enter fullscreen mode Exit fullscreen mode

Response for invalid documents:

{
  "valid": false,
  "errors": [
    {
      "path": "sections.0.content.2.text",
      "message": "Variable {{undefinedVar}} not found in variables object",
      "code": "UNDEFINED_VARIABLE"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Performance Considerations

Bulk rendering performance depends on document complexity. For typical business documents:

Document Size Batch of 10 Batch of 50 Batch of 100
5 pages 4 seconds 15 seconds 28 seconds
20 pages 12 seconds 45 seconds 85 seconds
50 pages 25 seconds 90 seconds 180 seconds

Each bulk render item costs 4 credits (vs. 5 for single renders), making bulk rendering both faster and more cost-effective for batches.

Real-World Example: Monthly Invoice Generation

Here is a complete example generating monthly invoices from a CRM export:

import fs from 'fs';
import fetch from 'node-fetch';

const API_KEY = process.env.AUTYPE_API_KEY;
const BASE_URL = 'https://api.autype.com/api/v1/dev';

async function generateMonthlyInvoices(invoiceData, templateId) {
  // Submit bulk job
  const response = await fetch(`${BASE_URL}/bulk-render`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      documentId: templateId,
      format: 'PDF',
      items: invoiceData,
      webhook: {
        url: 'https://api.mycompany.com/webhooks/invoices/complete',
        headers: { 'X-Internal-Secret': process.env.INTERNAL_SECRET }
      }
    })
  });

  const job = await response.json();
  console.log(`Started bulk job ${job.bulkJobId} with ${job.totalItems} invoices`);

  return job.bulkJobId;
}

// Load invoice data from CSV export
const csvData = fs.readFileSync('./monthly_invoices.csv', 'utf8');
const invoices = parseCsv(csvData);

// Generate all invoices
generateMonthlyInvoices(invoices, '550e8400-e29b-41d4-a716-446655440000');
Enter fullscreen mode Exit fullscreen mode

Summary

Autype's bulk rendering API provides the foundation for scalable document automation. Key takeaways:

  1. Submit once, render in parallel - Jobs process asynchronously with up to 100 documents per batch
  2. Use webhooks - Eliminate polling in production; let Autype notify you when work completes
  3. Validate early - Catch template errors before submitting large batches
  4. Handle partial failures - Monitor failedItems and implement retry logic for failed documents
  5. Leverage file uploads - CSV and Excel support simplifies large batch submission

The combination of parallel processing, webhook notifications, and flexible variable types makes this API suitable for everything from monthly invoice runs to real-time contract generation in your sales pipeline.


For more details on the document JSON schema and variable types, see the Autype API documentation.

Top comments (0)