How to generate documents with dynamic templates through the API

Generating documents with the Omnidocs Create API

Introduction

In this guide, you will learn how to generate documents with dynamic templates through the Omnidocs Create API.

Dynamic templates use a structured JSON payload to define the data that should be inserted into the document. Each field in the payload must match the expected node type in the template, such as text, number, date, group, element, select, repeat, or table.

You can use the same dynamic template schema in two different flows:

  • Prepare flow
    Use the prepare endpoint when you want Omnidocs Create to initialize the generation flow and return information needed to continue the process. This is useful when the integration needs to prepare the document generation before the final document is created.

  • Generate flow
    Use the generate endpoint when you want to generate the document directly from the provided payload.

Both endpoints use the same data schema, so the payload structure for text, number, date, group, element, select, repeat, and table nodes is identical in both flows.

Prerequisites

Before you begin, make sure you have:

  • Access to the Omnidocs Create API
  • A valid API token
  • A unitId
  • A templateId
  • Knowledge of the dynamic template schema used by the template

Endpoints

Prepare generation

Use the prepare endpoint to initialize a dynamic template generation flow:

POST /api/v1/units/{unitId}/generate/prepare

The request body contains the data required by the dynamic template.

Generate document

Use the generate endpoint to generate a document directly from a template:

POST /api/v1/units/{unitId}/recipes/{templateId}/generate

The request body uses the same schema as the prepare endpoint.

Basic request example

{
  "senderName": "Jane Doe",
  "recipientName": "John Doe",
  "amount": 1234.56,
  "date": "2025-10-10T00:00:00"
}

Each property in the payload must match a node key configured in the dynamic template.

Node types

Text node

Use a Text node when the template expects plain text.

{
  "senderName": "Jane Doe"
}

The value must be a JSON string.


Number node

Use a Number node when the template expects a numeric value.

{
  "amount": 1234.56
}

The value must be a JSON number.


Date node

Use a Date node when the template expects a date value.

{
  "startDate": "2025-10-10T00:00:00"
}

The value must be a string using the expected ISO 8601 datetime format.


Group node

Use a Group node when you need to send a nested object.

{
  "company": {
    "name": "Omnidocs",
    "address": "Wilders Plads 15A 1403 Copenhagen K Denmark",
    "cvr": 35679529
  }
}

Groups are useful for keeping related data together.


Element node

Use an Element node when the template expects inline content or a reference to another template.

{
  "employeeCard": {
    "referenceId": "000000000000",
    "data": {
      "firstName": "John",
      "lastName": "Doe"
    }
  }
}

If referenceId is omitted, the element uses the inline content configured in the template.


Select node

Use a Select node when the template contains predefined options.

The option property defines which element option should be selected.

You can reference the option in three ways:

  • By the name of the element
  • By index (0, 1, 2, etc.)
  • By an object value (reserved for future support)
⚠️

When using a string value, the option property references the name of the element — not the node key.

If the node is configured with "Use as visibility" it will insert all options and match the data of each option.

For example, if your template contains:

  • An element named Copenhagen Office
  • An element named New York Office

You can select the element by name like this:

{
  "office": {
    "option": "Copenhagen Office",
    "data": {
      "name": "Copenhagen Office",
      "location": "Wilders Plads 15A 1403 Copenhagen K Denmark",
      "agent": "John"
    }
  }
}

You can also select by index:

{
  "office": {
    "option": 0,
    "data": {
      "name": "Copenhagen Office",
      "location": "Wilders Plads 15A 1403 Copenhagen K Denmark",
      "agent": "John"
    }
  }
}

If the select node is configured to allow multiple selections, provide an array of option objects:

{
  "offices": [
    {
      "option": 0,
      "data": {
        "name": "Copenhagen Office"
      }
    },
    {
      "option": 2,
      "data": {
        "name": "New York Office"
      }
    }
  ]
}

Repeat node

Use a Repeat node when the same content should be generated multiple times with different data.

{
  "locations": [
    {
      "name": "Copenhagen Office",
      "location": "Wilders Plads 15A 1403 Copenhagen K Denmark",
      "cost": "$$$",
      "agent": "John"
    },
    {
      "name": "New York Office",
      "location": "World Trade Center",
      "cost": "$$$",
      "agent": "John"
    }
  ]
}

You can also provide a referenceId to repeat a referenced template:

{
  "locations": {
    "referenceId": "000000000000",
    "items": [
      {
        "name": "Copenhagen Office",
        "location": "Wilders Plads 15A 1403 Copenhagen K Denmark"
      },
      {
        "name": "New York Office",
        "location": "World Trade Center"
      }
    ]
  }
}

Table node

Use a Table node when the template should generate a table from structured data.

The simplest format is an array of row objects:

{
  "officesTable": [
    {
      "name": "Copenhagen Office",
      "location": "Wilders Plads 15A 1403 Copenhagen K Denmark",
      "cost": "$$$",
      "agent": "John"
    },
    {
      "name": "New York Office",
      "location": "World Trade Center",
      "cost": "$$$",
      "agent": "John"
    }
  ]
}

You can also define columns explicitly:

{
  "officesTable": {
    "columns": [
      {
        "title": "Name",
        "fraction": 1,
        "bindingConfiguration": {
          "bindingType": "text",
          "bindingKey": "name"
        }
      },
      {
        "title": "Location",
        "fraction": 1,
        "bindingConfiguration": {
          "bindingType": "text",
          "bindingKey": "location"
        }
      }
    ],
    "items": [
      {
        "name": "Copenhagen Office",
        "location": "Wilders Plads 15A 1403 Copenhagen K Denmark"
      },
      {
        "name": "New York Office",
        "location": "World Trade Center"
      }
    ]
  }
}
💡

Use the array format when the table structure is already configured in the template. Use the object format when the API request should also define the table columns.

Complete payload example

{
  "title": "Office overview",
  "createdDate": "2025-10-10T00:00:00",
  "company": {
    "name": "Omnidocs",
    "address": "Wilders Plads 15A 1403 Copenhagen K Denmark",
    "cvr": 35679529
  },
  "selectedOffice": {
    "option": "Copenhagen Office",
    "data": {
      "name": "Copenhagen Office",
      "location": "Wilders Plads 15A 1403 Copenhagen K Denmark",
      "agent": "John"
    }
  },
  "locations": [
    {
      "name": "Copenhagen Office",
      "location": "Wilders Plads 15A 1403 Copenhagen K Denmark",
      "cost": "$$$",
      "agent": "John"
    },
    {
      "name": "New York Office",
      "location": "World Trade Center",
      "cost": "$$$",
      "agent": "John"
    }
  ]
}

Common validation issues

Common reasons a request may fail include:

  • A required node is missing from the payload
  • A value uses the wrong JSON type
  • A date value does not match the expected format
  • A select node references an option that does not exist
  • A repeat or table node receives an object where an array is expected
  • A referenced template ID is invalid or unavailable

Summary

Dynamic templates let you generate documents from structured JSON payloads.
To generate a document successfully, make sure each property in your request matches the expected node type and binding key in the template.

Use:

  • Strings for text and dates
  • Numbers for numeric values
  • Objects for groups and elements
  • Arrays for repeats, multi-selects, and simple tables
  • Explicit column definitions when the API should control table structure