ComposeIt LogoComposeIt

Batch Document Generation

High-throughput asynchronous document rendering and webhook notifications for high-volume workflows.

Generate dozens or thousands of documents in parallel using the ComposeIt Batch API. Batch processing is designed for high-throughput workflows such as monthly billing runs, bulk certificate generation, or mass mailing campaigns.

Plan Availability

Batch document generation is exclusively available on Premium and Enterprise plans. Overages are permitted, so batch requests are not blocked by merge balances.


How Batch Generation Works

Batch document generation follows an asynchronous, queue-driven pipeline:

sequenceDiagram
    autonumber
    actor Client as API Client / Integration
    participant API as ComposeIt Batch API
    participant DB as Database
    participant Queue as GCP Cloud Tasks
    participant Worker as Export Engine
    participant Svix as Svix Webhooks

    Client->>API: POST /api/export/batch (with items)
    API->>DB: Bulk insert documents (status: "queued")
    API->>Queue: Push tasks for each item
    API-->>Client: Return 202 Accepted (batchId & queued docs)

    loop For each task
        Queue->>Worker: Call /api/export with HMAC signature
        Worker->>DB: Update status: "rendering"
        alt Successful Render
            Worker->>DB: Update status: "succeeded" + outputs
            Worker->>Svix: Dispatch document.succeeded
        else Rendering Failure
            alt Retries remaining (< 3)
                Worker->>DB: Mark isRetrying: true
                Worker->>Queue: Re-enqueue task
            else Max retries reached
                Worker->>DB: Update status: "failed" + error
                Worker->>Svix: Dispatch document.failed
            end
        else Document Expired
            Worker->>DB: Update status: "expired"
            Worker->>Svix: Dispatch document.expired
        end
        Worker->>DB: Check if all batch documents are terminal
        opt All documents finished & none retrying
            Worker->>Svix: Dispatch documents.completed
        end
    end

Document States

Each document created via batch moves through the following state machine:

StatusDescription
queuedThe document has been created and enqueued for background processing.
renderingThe document is currently actively being compiled and rendered by the engine.
succeededGeneration completed successfully. Output files (PDF, HTML, images) are ready.
failedGeneration failed after all retries (default 3 retries) were exhausted.
expiredThe document surpassed its expiresAt timestamp before completion.

Endpoints

1. Standard Batch Export

Generate multiple documents from a template using an array of data payloads.

  • Endpoint: POST /api/export/batch
  • Authentication: x-api-key header (requires documents:write permission)
  • Status Code: 202 Accepted

Request Body Schema

FieldTypeRequiredDescription
templateIdStringYesID of the template to generate documents from.
templateVersionNumberNoSpecific version snapshot number (defaults to latest active).
formatsArrayYesOutput formats to generate: ["pdf"], ["html"], ["image"], ["mjml"].
itemsArrayYesArray of items to generate (minimum 1 item). Alias: documents.
items[].dataObjectNoDynamic JSON data mapped to template variables for this document.
items[].metadataObjectNoCustom key-value pairs stored on the document record.
items[].expiresAtString / DateNoCustom ISO timestamp when this specific document expires.
items[].formatsArrayNoOverride output formats for this specific item.
imageTypeStringNoImage format if image format requested: "png" or "jpg".
renderOptionsObjectNoOptional rendering settings (margins, scale, paper size, etc.).
expiresAtString / DateNoDefault expiration timestamp for all documents in this batch.
sendForSignatureBooleanNoSend generated PDF to DocuSeal for e-signature.
docusealConnectionStringNoSaved DocuSeal integration connection ID.

Test Documents Not Allowed

Batch document generation cannot be run in test mode (isTest: true). Batch requests containing isTest: true will be rejected with 400 Bad Request.

Request Example

curl -X POST "https://app.composeit.app/api/export/batch" \
  -H "Content-Type: application/json" \
  -H "x-api-key: your_api_key_here" \
  -d '{
    "templateId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "formats": ["pdf"],
    "items": [
      {
        "data": {
          "invoiceNumber": "INV-2026-001",
          "customerName": "Acme Corp",
          "total": 1250.00
        },
        "metadata": { "orderId": "ord_101" }
      },
      {
        "data": {
          "invoiceNumber": "INV-2026-002",
          "customerName": "Globex Inc",
          "total": 3400.50
        },
        "metadata": { "orderId": "ord_102" }
      }
    ]
  }'

Response Format (202 Accepted)

Documents are returned immediately in queued status:

{
  "batchId": "batch_91a0b3f81e3a47",
  "totalCount": 2,
  "status": "queued",
  "documents": [
    {
      "id": "doc_a1b2c3d4",
      "organizationId": "org_123456789",
      "templateId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
      "createdById": "user_123456789",
      "status": "queued",
      "outputs": [],
      "metadata": {
        "batchId": "batch_91a0b3f81e3a47",
        "batchIndex": 0,
        "totalCount": 2,
        "orderId": "ord_101"
      },
      "expiresAt": "2026-10-08T12:00:00.000Z",
      "createdAt": "2026-10-07T12:00:00.000Z"
    },
    {
      "id": "doc_e5f6g7h8",
      "organizationId": "org_123456789",
      "templateId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
      "createdById": "user_123456789",
      "status": "queued",
      "outputs": [],
      "metadata": {
        "batchId": "batch_91a0b3f81e3a47",
        "batchIndex": 1,
        "totalCount": 2,
        "orderId": "ord_102"
      },
      "expiresAt": "2026-10-08T12:00:00.000Z",
      "createdAt": "2026-10-07T12:00:00.000Z"
    }
  ]
}

2. Platform Batch Export

Batch generate documents directly from external datasources (Airtable, Notion, Baserow, Fibery, NocoDB, etc.) across multiple records.

  • Endpoint: POST /api/export/batch/:platform (e.g. /api/export/batch/airtable)
  • Authentication: x-api-key header or encrypted link token
  • Status Code: 202 Accepted

Request Body Schema

FieldTypeRequiredDescription
templateIdStringYesID of the template connected to the platform data source.
recordIdsArrayYesList of record IDs in the platform table to merge into documents.
baseIdStringNoPlatform base or database identifier (if applicable).
tableIdStringNoPlatform table identifier.
formatsArrayNoOutput formats (defaults to ["pdf"]).
attachmentFieldStringNoField name in the platform where the generated file should be saved.
overwriteExistingBooleanNoWhether to overwrite existing files in the attachment field.

Request Example

curl -X POST "https://app.composeit.app/api/export/batch/airtable" \
  -H "Content-Type: application/json" \
  -H "x-api-key: your_api_key_here" \
  -d '{
    "templateId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
    "recordIds": ["rec_111111", "rec_222222", "rec_333333"],
    "formats": ["pdf"]
  }'

Webhooks

ComposeIt delivers secure, signed, and reliable webhook notifications directly to your application endpoints as batch documents progress through the rendering pipeline.

Supported Events

Event TypeTrigger Description
document.succeededFired each time an individual document finishes rendering successfully.
document.failedFired when a document rendering permanently fails after all retries.
document.expiredFired if a document expires before completion.
documents.completedFired once all documents in a batch have reached a terminal state and no documents are retrying.

Event Payloads

document.succeeded

{
  "documentId": "doc_a1b2c3d4",
  "batchId": "batch_91a0b3f81e3a47",
  "organizationId": "org_123456789",
  "status": "succeeded",
  "outputs": [
    {
      "label": "pdf",
      "storageKey": "exports/doc_a1b2c3d4.pdf",
      "url": "https://storage.composeit.website/outputs/doc_a1b2c3d4.pdf",
      "mimeType": "application/pdf",
      "sizeBytes": 145020,
      "checksum": "8f14e45fceea167a5a36dedd4bea2543"
    }
  ],
  "metadata": {
    "documentName": "Invoice INV-2026-001",
    "orderId": "ord_101"
  },
  "completedAt": "2026-10-07T12:00:03.142Z"
}

document.failed

{
  "documentId": "doc_e5f6g7h8",
  "batchId": "batch_91a0b3f81e3a47",
  "organizationId": "org_123456789",
  "status": "failed",
  "error": "Image asset URL timed out after 30000ms",
  "metadata": {
    "orderId": "ord_102"
  },
  "completedAt": "2026-10-07T12:00:35.890Z"
}

document.expired

{
  "documentId": "doc_e5f6g7h8",
  "batchId": "batch_91a0b3f81e3a47",
  "organizationId": "org_123456789",
  "status": "failed",
  "error": "Image asset URL timed out after 30000ms",
  "metadata": {
    "orderId": "ord_102"
  },
  "completedAt": "2026-10-07T12:00:35.890Z"
}

documents.completed

Sent when all documents in the batch have reached a final status (succeeded, failed, or expired) and no documents are in retry:

{
  "batchId": "batch_91a0b3f81e3a47",
  "organizationId": "org_123456789",
  "totalDocuments": 100,
  "succeededCount": 98,
  "failedCount": 2,
  "expiredCount": 0,
  "completedAt": "2026-10-07T12:01:15.512Z"
}

We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our privacy policy.