Create a Document from Template

Automate repeated document creation from a template.

Template

A PandaDoc template is a document template created and edited in the PandaDoc web application. Our help center has further information on PandaDoc templates.

We have prepared a sample PandaDoc template that you can use to test the request. You can find it in the Templates section of your account or download it here:

After downloading, the system will create a document from this template. The browser will redirect you to this document. Return to the templates page to find the template_id that you can use in Postman. Look for it in your browser's address bar: https://app.pandadoc.com/a/#/templates/{ID}/content.

Asynchronous document creation

❗️

Document creation is a non-blocking (asynchronous) operation

The document creation process may take some time.

With a successful request, you receive a response with the created document's ID and status document.uploaded. After processing completes on our servers, usually a few seconds, the document moves to the document.draft status. Please wait for the webhook call or check this document's status before proceeding.

The change of status from document.uploaded to another status signifies the document is ready for further processing. Attempting to use a newly created document before PandaDoc servers process it will result in a ​"404 document not found" response.

Date fields

Specify date formatting in the PandaDoc template date field settings. Pass the date field value in the following way: "fields": {"Date": {"value": "2019-02-21T00:00:00.000Z"}}

Signing order

Set a signing order of recipients for documents created from templates via API.
In addition, we allow overriding a signing order in the document creation request.

"recipients": [  
  {  
    "email": "[email protected]",
    "first_name": "Josh",
    "last_name": "Ron",
    "role": "user",
    "signing_order": 1
  }
]

Create on member's behalf

Create documents on your colleagues' behalf when it's needed. Simply add an additional owner section in the document creation request.
You can set an owner of a document as an email or membership_id. Unique member's identifier you may find in the List Members.

"owner":{
	"email":"[email protected]"
}
"owner":{
	"membership_id":"radQBiBkU7MBk59NSgaGfd"
}

Prefilled fields

🚧

You can't prefill a Signature field.

If you want to prefill a particular field, you need to map a template field to the API field:

  1. Open your template on the web view
  2. Open field properties
Field properties

Field properties

  1. Scroll down to Merge Field and give your field a meaningful name:
  1. Use this name in your request body, like in the example on the right panel:
     "fields": {
        "Favorite.Color": {
          "value": "PandaDoc green"
        },
        "Delivery": {
          "value": "Same Day Delivery"
        },
        "Like": {
          "value": true
        },
        "Date": {
          "value": "2019-12-31T00:00:00.000Z"
        }
      },
    

Images

Upload images to Image blocks when creating a new document from a template. Please note the image blocks in the template should be pre-set before creating a document.

Link an image to a particular image block in your template by its name. For example, if there is an image block named "Image 1" in your template, uploading an image with the name "Image 1" via API places this image in this block.

Upload an image as a URL parameter inside a JSON request body in the following format:

"images": [
        {
            "name": "Image 1",
            "urls": [
                "https://s3.amazonaws.com/pd-static-content/public-docs/pandadoc-panda-bear.png"
            ]
        }
    ]

Image formats supported: GIF, JPG, PNG. Editor 2.0 allows only one image per block and doesn't allow images in text blocks.

Content Placeholder

With API, you can replace the Content Placeholder with content library items. In addition, it's possible to prefill fields/variables values, add items to the pricing table, and assign recipients to roles from the content library item.
See a detailed guide on how to use a content placeholder.

Content Placeholder can be accessed via Block ID which automatically generates upon placeholder creation in the template. You can easily change it in the template.

"content_placeholders": [
        {
            "uuid": "305eca46-f5be-435b-bbb4-f4dacf3896f5",
            "block_id": "Content Placeholder 1",
            "description": "Click here to add content library items"
        }
    ]

As mentioned above, you can replace a placeholder with a few content library items each and you can be pass them as an array of content library items in the API document creation request.

"content_placeholders": [
        {
            "block_id": "{{block_id}}",
            "content_library_items": [
                {
                    "id": "{{cli_id}}",
                    "pricing_tables": [
                        {
                            "name": "Pricing Table 1",
                            "sections": [
                                {
                                    "title": "Sample Section",
                                    "default": true,
                                    "rows": [
                                        {
                                            "options": {
                                                "optional": true,
                                                "optional_selected": true,
                                                "qty_editable": true
                                            },
                                            "data": {
                                                "name": "Placeholder Panda",
                                                "price": 10,
                                                "qty": 3
                                            }
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    "id": "{{cli_id_2}}",
                    "recipients": [
                        {
                            "email": "[email protected]",
                            "first_name": "John",
                            "last_name": "Roe",
                            "role": "Signer"  
                        }
                    ],
                    "fields": {
                        "Date": {
        	                "value": "2019-12-31T00:00:00.000Z"
                        }
                    }
                }
            ]
        }

Content placeholders restrictions:

  • Content placeholder must be replaced with at least 1 content library item.
  • You can add up to 10 content library items in one content placeholder.
  • Content library item must be unique in the content placeholder. You can use the same one for different placeholders.

Pricing table

Section types

There are two types of sections in the pricing table (PT):

  1. Default sections won't have a section Header in the resulting document. Set the "default" parameter as "true" to mark a section as default.
  2. Non-default sections will have a Header and should be added with "default": false option.
2862

Pricing Table

You can set a multiple-choice section in the "sections" description inside a JSON request body in the format: "multichoice_enabled": true. Use the parameter "multichoice_selected" set as true to select the row, while other rows should be deselected in the row description.

Here is a code example of a "Multiple choice section" where the second item in the section is selected below:

"sections": [  
    {  
        "title": "First Section",
        "default": false,
        "multichoice_enabled": true,
        "rows": [  
            {  
                "options": {
                    "multichoice_selected": false
                },
                "data":{  
                    "name": "Toy Panda",
                    "price": 20,
                    "qty": 2
                }
            },
            {  
                "options": {
                    "multichoice_selected": true
                },
                "data":{  
                    "name": "Toy Panda",
                    "price": 10,
                    "qty": 3
                }
            }
        ]

🚧

Multiple-choice section restrictions

If you don't mark any row as selected in the "Multiple choice section,” the first row in the section will be selected. If you mark several rows, only the first one will be selected.

It is not possible to set rows as optional in the "Multiple choice section.”

Column types

Column typeJSON example
Text"Name": "Toy Panda",
"Description": "Fluffy!"
Tax"Tax": {
"value": 7.5,
"type": "percent"
}
Discount"Discount": {
"value": 7.5,
"type": "percent"
}
Fee"Fee": {
"value": 7.5,
"type": "percent"
}
Additional multiplayer"Multiplayer": 1.5
Price"Price": 15.0
Quantity"QTY": 15

Taxes

Your document can have several taxes. To apply several taxes successfully, you must use these names: tax_first, tax_second.

For a global tax in your pricing table (PT), follow these steps:

  1. Add a Tax column to the PT in your template. You can hide it if you don't really need it there.
  2. Edit the PT section in your payload to match the following example:
    "pricing_tables":
    [
        {
            "name": "Pricing Table 1",
            "data_merge": true,
            "options":
            {
                "currency": "EUR",
                "Tax":
                {
                    "name": "Tax",
                    "type": "percent",
                    "value": 19
                }
            },
            "sections":
            [
                {
                    "title": "Pricing Section",
                    "default": true,
                    "rows":
                    [
                        {
                            "options":
                            {
                                "optional": false,
                                "optional_selected": false,
                                "qty_editable": false
                            },
                            "data":
                            {
                                "Name": "Meta Conversion Advertising",
                                "Price": 6000,
                                "QTY": 6,
                                "Description": "Conversion Kampagnen Management \n+ Performance Design",
                                "Unit": "Monatlich",
                                "Tax":
                                {
                                    "type": "percent",
                                    "value": 0
                                }
                            }
                        }
                    ]
                }
            ]
        }
    ]

Data merge

Frequently, our customers need to name columns in the pricing table according to names in their system and that's where data merge may help. The data merge feature is available by default and the only thing you need to do is enable it in API as well.

Here is how you can check what names your columns have with the data merge feature by default and change them.

2868

Template -> Pricing Table Settings -> Set up data merge

1900

Column names for API are presented on the left

To use these column names instead of default ones you need to add the data_merge boolean parameter as true (false by default) into the pricing table object of the document creation request body and use them in the data section.

"pricing_tables": [
        {
            "name": "Pricing Table 1",
            "data_merge":true,
            "options": {
                "discount": {
                    "type": "absolute",
                    "name": "Discount",
                    "value": 2.26
                }
            },
            "sections": [
                {
                    "title": "Sample Section",
                    "default": true,
                    "rows": [
                        {
                            "options": {
                                "optional": true,
                                "optional_selected": true,
                                "qty_editable": true
                            },
                            "data": {
                                "Name": "Toy Panda",
                                "Description": "Fluffy!",
                                "Price": 10,
                                "QTY": 3,
                                "SKU":"TEST1",
                                "Tax": {
                                    "value": 7.5,
                                    "type": "percent"
                                },
                                "CustomText":"testcolumn"
                            },
                            "custom_fields": {
                                "Fluffiness": "5 / 5"
                            }
                        }
                    ]
                }
            ]
        }
    ]

As a result, all values from the document creation request will be properly matched with columns in the pricing table of the newly created document.

2854

Document -> Pricing Table

For more information on how to add and set your pricing table, visit our help center. You will also discover ways your recipients can interact with the pricing table. This is a fun feature you’ll want to explore more!

Variables in titles

The name parameter is optional for the documents created from a template. Here's how you dynamically populate the document name:

Set document name to include a variable

  1. Set the template name to include a variable on the UI and pass only the template_uuid in the payload:
{  
  "template_uuid": "RWVafhmMWniwA5FWnEQVvg",
}
  1. For name, pass a variable enclosed in square brackets, like this: Proposal for [Company.Name], and a new parameter detect_title_variables:
{  
  "name": "Proposal for [Company.Name]",
  "detect_title_variables": true,
  "template_uuid": "RWVafhmMWniwA5FWnEQVvg",
  ...
}

🚧

Variable is created if it already exists in the template or you have passed it in the payload. Otherwise, it will be presented as plain text in square brackets.

Pass variable value

Then pass the variable in the tokens section of the Create Document payload:

  "tokens": [
    {
      "name": "Company.Name",
      "value": "Panda"
    }