Documenso

Templates API

Create documents from reusable templates via API.

This guide may not reflect the latest endpoints or parameters. For an always up-to-date reference, see the OpenAPI Reference.

Template Object

A template object contains the following properties:

PropertyTypeDescription
idnumberUnique template identifier
envelopeIdstringAssociated envelope ID
typestringTemplate type: PRIVATE or PUBLIC
visibilitystringWho can view: EVERYONE, ADMIN, MANAGER_AND_ABOVE
titlestringTemplate title
externalIdstring | nullYour custom identifier
publicTitlestring | nullPublic-facing title (for public templates)
publicDescriptionstring | nullPublic-facing description (for public templates)
userIdnumberOwner's user ID
teamIdnumber | nullTeam ID if team-owned
folderIdstring | nullFolder containing the template
createdAtstringISO 8601 timestamp
updatedAtstringISO 8601 timestamp
recipientsarrayPredefined recipients with roles and fields
fieldsarraySignature and form fields on the template
templateMetaobjectEmail settings, signing options, redirect URL
directLinkobject | nullDirect link configuration if enabled

Example Template Object

{
  "id": 123,
  "envelopeId": "envelope_abc123xyz",
  "type": "PRIVATE",
  "visibility": "EVERYONE",
  "title": "Employment Contract",
  "externalId": "template-emp-001",
  "publicTitle": null,
  "publicDescription": null,
  "userId": 1,
  "teamId": 5,
  "folderId": null,
  "createdAt": "2025-01-10T08:00:00.000Z",
  "updatedAt": "2025-01-10T08:30:00.000Z",
  "recipients": [
    {
      "id": 1,
      "email": "employee@example.com",
      "name": "Employee",
      "role": "SIGNER",
      "signingOrder": 1
    },
    {
      "id": 2,
      "email": "hr@company.com",
      "name": "HR Manager",
      "role": "SIGNER",
      "signingOrder": 2
    }
  ],
  "fields": [
    {
      "id": 101,
      "type": "SIGNATURE",
      "page": 1,
      "positionX": 10,
      "positionY": 80,
      "width": 30,
      "height": 5,
      "recipientId": 1
    }
  ],
  "templateMeta": {
    "subject": "Your Employment Contract",
    "message": "Please review and sign your employment contract.",
    "redirectUrl": "https://example.com/welcome"
  },
  "directLink": null
}

List Templates

Retrieve a paginated list of templates.

GET /template

Query Parameters

ParameterTypeDescription
pageintegerPage number (default: 1)
perPageintegerResults per page (default: 10, max: 100)
typestringFilter by type: PRIVATE or PUBLIC
folderIdstringFilter by folder ID
orderByColumnstringSort field (only createdAt supported)
orderByDirectionstringSort direction: asc or desc (default: desc)

Code Examples

# List all templates
curl -X GET "https://app.documenso.com/api/v2/template" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx"

# Filter by type and paginate

curl -X GET "https://app.documenso.com/api/v2/template?type=PRIVATE&page=1&perPage=20" \
 -H "Authorization: api_xxxxxxxxxxxxxxxx"
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
const BASE_URL = 'https://app.documenso.com/api/v2';

// List all templates
const response = await fetch(`${BASE_URL}/template`, {
  method: 'GET',
  headers: {
    Authorization: API_TOKEN,
  },
});

const { data, pagination } = await response.json();
console.log(`Found ${pagination.totalItems} templates`);

// Filter by type
const privateResponse = await fetch(
  `${BASE_URL}/template?type=PRIVATE&page=1&perPage=20`,
  {
    method: 'GET',
    headers: {
      Authorization: API_TOKEN,
    },
  }
);

const privateTemplates = await privateResponse.json();

Response

{
  "data": [
    {
      "id": 123,
      "envelopeId": "envelope_abc123",
      "type": "PRIVATE",
      "title": "Employment Contract",
      "createdAt": "2025-01-10T08:00:00.000Z",
      "updatedAt": "2025-01-10T08:30:00.000Z",
      "recipients": [
        {
          "id": 1,
          "email": "employee@example.com",
          "name": "Employee",
          "role": "SIGNER"
        }
      ]
    }
  ],
  "pagination": {
    "page": 1,
    "perPage": 10,
    "totalPages": 3,
    "totalItems": 25
  }
}

Get Template

Retrieve a single template by ID.

GET /template/{templateId}

Path Parameters

ParameterTypeDescription
templateIdnumberThe template ID

Code Examples

curl -X GET "https://app.documenso.com/api/v2/template/123" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx"
const templateId = 123;

const response = await fetch(`https://app.documenso.com/api/v2/template/${templateId}`, {
  method: 'GET',
  headers: {
    Authorization: 'api_xxxxxxxxxxxxxxxx',
  },
});

const template = await response.json();
console.log(template.title, template.recipients.length);

Response

Returns the full template object including recipients, fields, and metadata.


Create Document from Template

Create a new document using a template. This is the primary way to use templates programmatically.


POST /template/use

Request Body

FieldTypeRequiredDescription
templateIdnumberYesThe template ID to use
recipientsarrayYesRecipient details (maps to template recipients)
distributeDocumentbooleanNoIf true, immediately send the document to recipients
externalIdstringNoYour custom identifier for the created document
folderIdstringNoFolder ID to create the document in
prefillFieldsarrayNoPre-fill field values before sending
overrideobjectNoOverride template settings for this document
formValuesobjectNoPDF form values to insert

Recipients Array

Each recipient object must include:

FieldTypeRequiredDescription
idnumberYesThe recipient ID from the template
emailstringYesRecipient's email address
namestringNoRecipient's display name

Code Examples

# Create document from template
curl -X POST "https://app.documenso.com/api/v2/template/use" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "recipients": [
      {
        "id": 1,
        "email": "john.doe@example.com",
        "name": "John Doe"
      },
      {
        "id": 2,
        "email": "jane.smith@company.com",
        "name": "Jane Smith"
      }
    ],
    "distributeDocument": true,
    "externalId": "contract-2025-001"
  }'

# Create document with field prefilling
curl -X POST "https://app.documenso.com/api/v2/template/use" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "recipients": [
      {
        "id": 1,
        "email": "john.doe@example.com",
        "name": "John Doe"
      }
    ],
    "prefillFields": [
      {
        "id": 101,
        "type": "text",
        "value": "Senior Software Engineer"
      },
      {
        "id": 102,
        "type": "number",
        "value": "85000"
      },
      {
        "id": 103,
        "type": "date",
        "value": "2025-02-01"
      }
    ],
    "distributeDocument": true
  }'
const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
const BASE_URL = 'https://app.documenso.com/api/v2';

// Create document from template
const response = await fetch(`${BASE_URL}/template/use`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    recipients: [
      {
        id: 1,
        email: 'john.doe@example.com',
        name: 'John Doe',
      },
      {
        id: 2,
        email: 'jane.smith@company.com',
        name: 'Jane Smith',
      },
    ],
    distributeDocument: true,
    externalId: 'contract-2025-001',
  }),
});

const document = await response.json();
console.log('Created document:', document.id);

// Create document with prefilled fields
const prefillResponse = await fetch(`${BASE_URL}/template/use`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    recipients: [
      {
        id: 1,
        email: 'john.doe@example.com',
        name: 'John Doe',
      },
    ],
    prefillFields: [
      {
        id: 101,
        type: 'text',
        value: 'Senior Software Engineer',
      },
      {
        id: 102,
        type: 'number',
        value: '85000',
      },
      {
        id: 103,
        type: 'date',
        value: '2025-02-01',
      },
    ],
    distributeDocument: true,
  }),
});

const prefilledDocument = await prefillResponse.json();

Response

Returns the created document object with recipients and signing URLs.

{
  "id": "envelope_xyz789",
  "type": "DOCUMENT",
  "status": "PENDING",
  "title": "Employment Contract",
  "source": "TEMPLATE",
  "externalId": "contract-2025-001",
  "recipients": [
    {
      "id": 1,
      "email": "john.doe@example.com",
      "name": "John Doe",
      "role": "SIGNER",
      "signingStatus": "NOT_SIGNED",
      "signingUrl": "https://app.documenso.com/sign/abc123"
    }
  ]
}

Override Template Settings

When creating a document from a template, you can override various settings:

const response = await fetch(`${BASE_URL}/template/use`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    recipients: [{ id: 1, email: 'signer@example.com', name: 'Signer' }],
    override: {
      title: 'Custom Document Title',
      subject: 'Custom email subject',
      message: 'Custom email message body',
      timezone: 'America/New_York',
      dateFormat: 'MM/dd/yyyy',
      redirectUrl: 'https://example.com/custom-redirect',
      language: 'de',
      typedSignatureEnabled: true,
      uploadSignatureEnabled: false,
      drawSignatureEnabled: true,
    },
    distributeDocument: true,
  }),
});

Override Options

FieldTypeDescription
titlestringDocument title
subjectstringEmail subject line
messagestringEmail body message
timezonestringTimezone for date fields
dateFormatstringDate format string
redirectUrlstringURL to redirect after signing
languagestringDocument language code
typedSignatureEnabledbooleanAllow typed signatures
uploadSignatureEnabledbooleanAllow uploaded signature images
drawSignatureEnabledbooleanAllow drawn signatures

Prefill Fields

Prefill field values when creating a document from a template. This is useful for populating known data before sending.

Supported Field Types

TypeValue FormatDescription
textstringText field value
numberstringNumeric value as string
datestring (ISO 8601)Date in YYYY-MM-DD format
radiostringSelected option value
checkboxarray of stringsArray of checked option values
dropdownstringSelected dropdown value

Prefill Field Schema

type PrefillField = {
  id: number; // Field ID from template
  type: string; // Field type (must match template field)
  label?: string; // Optional label override
  placeholder?: string; // Optional placeholder (text/number only)
  value: string | string[]; // Value to prefill
};

Example: Prefill Multiple Field Types

const response = await fetch(`${BASE_URL}/template/use`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    recipients: [{ id: 1, email: 'signer@example.com', name: 'Signer' }],
    prefillFields: [
      // Text field
      {
        id: 101,
        type: 'text',
        value: 'John Doe',
      },
      // Number field
      {
        id: 102,
        type: 'number',
        value: '50000',
      },
      // Date field
      {
        id: 103,
        type: 'date',
        value: '2025-03-15',
      },
      // Radio field (select one option)
      {
        id: 104,
        type: 'radio',
        value: 'full-time',
      },
      // Checkbox field (select multiple options)
      {
        id: 105,
        type: 'checkbox',
        value: ['health', 'dental', '401k'],
      },
      // Dropdown field
      {
        id: 106,
        type: 'dropdown',
        value: 'engineering',
      },
    ],
    distributeDocument: true,
  }),
});

The field type in prefillFields must match the actual field type in the template. A mismatch will result in an error.


Update Template

Update a template's properties.

POST /template/update

Request Body

FieldTypeRequiredDescription
templateIdnumberYesTemplate ID
dataobjectNoTemplate properties to update
metaobjectNoEmail and signing settings to update

Code Examples

curl -X POST "https://app.documenso.com/api/v2/template/update" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "data": {
      "title": "Updated Employment Contract",
      "visibility": "ADMIN"
    },
    "meta": {
      "subject": "Updated: Your Employment Contract",
      "redirectUrl": "https://example.com/updated-redirect"
    }
  }'
const response = await fetch(`${BASE_URL}/template/update`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    data: {
      title: 'Updated Employment Contract',
      visibility: 'ADMIN',
    },
    meta: {
      subject: 'Updated: Your Employment Contract',
      redirectUrl: 'https://example.com/updated-redirect',
    },
  }),
});

const template = await response.json();

Duplicate Template

Create a copy of an existing template.


POST /template/duplicate

Request Body

FieldTypeRequiredDescription
templateIdnumberYesTemplate ID

Code Examples

curl -X POST "https://app.documenso.com/api/v2/template/duplicate" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123
  }'
const response = await fetch(`${BASE_URL}/template/duplicate`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
  }),
});

const duplicatedTemplate = await response.json();
console.log('New template ID:', duplicatedTemplate.id);

Delete Template

Delete a template.


POST /template/delete

Request Body

FieldTypeRequiredDescription
templateIdnumberYesTemplate ID

Code Examples

curl -X POST "https://app.documenso.com/api/v2/template/delete" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123
  }'
const response = await fetch(`${BASE_URL}/template/delete`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
  }),
});

const { success } = await response.json();

Response

{
  "success": true
}

Direct link templates allow recipients to create and sign documents without requiring you to explicitly create each document. When a recipient visits the direct link, a new document is automatically created from the template.

POST /template/direct/create
FieldTypeRequiredDescription
templateIdnumberYesTemplate ID
directRecipientIdnumberNoRecipient ID to use as the direct link signer
curl -X POST "https://app.documenso.com/api/v2/template/direct/create" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "directRecipientId": 1
  }'
const response = await fetch(`${BASE_URL}/template/direct/create`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    directRecipientId: 1,
  }),
});

const directLink = await response.json();
console.log('Direct link token:', directLink.token);
// Share: https://app.documenso.com/d/{token}

Response

{
  "id": 456,
  "token": "abc123xyz",
  "templateId": 123,
  "directTemplateRecipientId": 1,
  "enabled": true,
  "createdAt": "2025-01-15T10:00:00.000Z"
}

Enable or disable an existing direct link.

POST /template/direct/toggle
curl -X POST "https://app.documenso.com/api/v2/template/direct/toggle" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123,
    "enabled": false
  }'
const response = await fetch(`${BASE_URL}/template/direct/toggle`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
    enabled: false,
  }),
});

const directLink = await response.json();
console.log('Direct link enabled:', directLink.enabled);

POST /template/direct/delete
curl -X POST "https://app.documenso.com/api/v2/template/direct/delete" \
  -H "Authorization: api_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "templateId": 123
  }'
const response = await fetch(`${BASE_URL}/template/direct/delete`, {
  method: 'POST',
  headers: {
    Authorization: API_TOKEN,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    templateId: 123,
  }),
});

const { success } = await response.json();

Custom Document Data

When creating a document from a template, you can replace the template's PDF with a custom PDF by using the customDocumentData parameter. This is useful when you need to generate the PDF dynamically while reusing the template's recipient and field configuration.

To use custom document data:

  1. Retrieve the template to get the envelopeItemId of the PDF you want to replace
  2. Include customDocumentData in your template/use request, mapping each envelopeItemId to a new file

The field positions from the template are preserved on the new PDF. Ensure the replacement PDF has the same page layout to maintain accurate field placement.

See the OpenAPI Reference for the full request schema.


Template Types

TypeDescription
PRIVATEOnly accessible by owner and team members
PUBLICCan be shared publicly with a direct link

Complete Example: Contract Workflow

This example demonstrates a complete workflow for using templates to send contracts.

const API_TOKEN = process.env.DOCUMENSO_API_TOKEN;
const BASE_URL = 'https://app.documenso.com/api/v2';

async function sendEmploymentContract(employeeData: {
  email: string;
  name: string;
  position: string;
  salary: number;
  startDate: string;
}) {
  // 1. Get the template to find recipient and field IDs
  const templateResponse = await fetch(`${BASE_URL}/template/456`, {
    headers: { Authorization: API_TOKEN },
  });
  const template = await templateResponse.json();

  // 2. Find the employee recipient slot
  const employeeRecipient = template.recipients.find(
    (r) => r.role === 'SIGNER' && r.signingOrder === 1
  );

  // 3. Find fields to prefill
  const positionField = template.fields.find(
    (f) => f.fieldMeta?.label === 'Position'
  );
  const salaryField = template.fields.find(
    (f) => f.fieldMeta?.label === 'Salary'
  );
  const startDateField = template.fields.find(
    (f) => f.type === 'DATE'
  );

  // 4. Create document from template with prefilled data
  const documentResponse = await fetch(`${BASE_URL}/template/use`, {
    method: 'POST',
    headers: {
      Authorization: API_TOKEN,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      templateId: 456,
      recipients: [
        {
          id: employeeRecipient.id,
          email: employeeData.email,
          name: employeeData.name,
        },
      ],
      prefillFields: [
        {
          id: positionField.id,
          type: 'text',
          value: employeeData.position,
        },
        {
          id: salaryField.id,
          type: 'number',
          value: employeeData.salary.toString(),
        },
        {
          id: startDateField.id,
          type: 'date',
          value: employeeData.startDate,
        },
      ],
      override: {
        subject: `Employment Contract for ${employeeData.name}`,
        message: `Hi ${employeeData.name},\n\nPlease review and sign your employment contract.`,
      },
      distributeDocument: true,
      externalId: `emp-contract-${Date.now()}`,
    }),
  });

  const document = await documentResponse.json();

  return {
    documentId: document.id,
    signingUrl: document.recipients[0].signingUrl,
  };
}

// Usage
const result = await sendEmploymentContract({
  email: 'john.doe@example.com',
  name: 'John Doe',
  position: 'Senior Engineer',
  salary: 120000,
  startDate: '2025-03-01',
});

console.log('Document created:', result.documentId);
console.log('Signing URL:', result.signingUrl);

See Also

On this page