> ## Documentation Index
> Fetch the complete documentation index at: https://docsautomator.co/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Create Document via API

> Pass data directly via the API to generate documents

When your automation's data source is set to **API**, you pass all field data directly in the request body. This is the most flexible option, as you control exactly what data goes into the document.

## Endpoint

```
POST https://api.docsautomator.co/createDocument
```

## Request Body

<ParamField body="docId" type="string" required>
  The automation ID. Find it on the automation's settings page or via `GET /automations`.
</ParamField>

<ParamField body="data" type="object" required>
  Key-value pairs for template placeholders. Keys must match the placeholder names in your template (e.g., `{{customer_name}}` in your template → `"customer_name"` in the data object). Line items are also included inside this object as `line_items_1`, `line_items_2`, etc. — see [Example with Line Items](#example-with-line-items) below.
</ParamField>

<ParamField body="documentName" type="string">
  Custom name for the generated document. Overrides the automation's document name setting.
</ParamField>

<ParamField body="async" type="boolean" default="false">
  When `true`, returns immediately with a `jobId` (HTTP 202). Poll [`GET /job/{jobId}`](/api-reference/documents/get-job-status) for the result.
</ParamField>

<ParamField body="webhookParams" type="object">
  Custom parameters passed through to webhook notifications under both `webhookParams` and `additionalParams` (identical content; the latter is kept for backward compatibility).
</ParamField>

<ParamField body="skipEsign" type="boolean" default="false">
  When `true`, skips e-signing for this request even if the automation has e-signing enabled. The document is generated and delivered normally (Drive save, email, webhook), but no signing session is started and no signing invitations are sent. Useful for two-step approval flows: generate a draft for review first, then re-run without `skipEsign` to send the document for signing. Also accepted as a query parameter (`?skipEsign=true`) on GET requests.
</ParamField>

<ParamField body="actingUserEmail" type="string">
  Email address of the team member generating this document. When the automation's email delivery (or e-signature email settings) has **Send from the team member who generates the document** enabled, the email is sent from this member's own connected Gmail or Outlook account instead of the configured sender. The address must match a mailbox connected to the workspace; otherwise DocsAutomator falls back to the automation's configured sender. Also accepted as a query parameter (`?actingUserEmail=...`) on GET requests or as an `X-Acting-User-Email` request header (the header takes precedence). The in-app Generate button passes this automatically.
</ParamField>

<ParamField body="existingPdfs" type="string[]">
  Array of publicly accessible PDF URLs to merge or prepend to the generated document.
</ParamField>

<ParamField body="docTemplateLink" type="string">
  Override the automation's Google Doc template URL for this request only. Pass a full Google Docs URL or just the document ID.
</ParamField>

## Basic Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.docsautomator.co/createDocument \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "docId": "YOUR_AUTOMATION_ID",
      "data": {
        "customer_name": "Acme Corp",
        "invoice_number": "INV-2025-001",
        "invoice_date": "2025-01-15",
        "due_date": "2025-02-15",
        "total": "$5,500.00"
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.docsautomator.co/createDocument", {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      docId: "YOUR_AUTOMATION_ID",
      data: {
        customer_name: "Acme Corp",
        invoice_number: "INV-2025-001",
        invoice_date: "2025-01-15",
        due_date: "2025-02-15",
        total: "$5,500.00",
      },
    }),
  });

  const result = await response.json();
  console.log(result.pdfUrl);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.docsautomator.co/createDocument",
      headers={
          "Authorization": "Bearer YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={
          "docId": "YOUR_AUTOMATION_ID",
          "data": {
              "customer_name": "Acme Corp",
              "invoice_number": "INV-2025-001",
              "invoice_date": "2025-01-15",
              "due_date": "2025-02-15",
              "total": "$5,500.00",
          },
      },
  )

  result = response.json()
  print(result["pdfUrl"])
  ```
</CodeGroup>

## Example with Line Items

Pass line items as arrays inside the `data` object. Use `line_items_1` for the first group, `line_items_2` for a second group, and so on — there is no limit on the number of line item groups. Each object's keys must match the line item placeholder names in your template.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.docsautomator.co/createDocument \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "docId": "YOUR_AUTOMATION_ID",
      "data": {
        "customer_name": "Acme Corp",
        "invoice_date": "2025-01-15",
        "subtotal": "$5,500.00",
        "tax": "$495.00",
        "total": "$5,995.00",
        "line_items_1": [
          { "description": "Consulting", "quantity": 10, "rate": "$150", "amount": "$1,500" },
          { "description": "Development", "quantity": 20, "rate": "$200", "amount": "$4,000" }
        ]
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.docsautomator.co/createDocument", {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      docId: "YOUR_AUTOMATION_ID",
      data: {
        customer_name: "Acme Corp",
        invoice_date: "2025-01-15",
        subtotal: "$5,500.00",
        tax: "$495.00",
        total: "$5,995.00",
        line_items_1: [
          { description: "Consulting", quantity: 10, rate: "$150", amount: "$1,500" },
          { description: "Development", quantity: 20, rate: "$200", amount: "$4,000" },
        ],
      },
    }),
  });

  const result = await response.json();
  console.log(result.pdfUrl);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.docsautomator.co/createDocument",
      headers={
          "Authorization": "Bearer YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={
          "docId": "YOUR_AUTOMATION_ID",
          "data": {
              "customer_name": "Acme Corp",
              "invoice_date": "2025-01-15",
              "subtotal": "$5,500.00",
              "tax": "$495.00",
              "total": "$5,995.00",
              "line_items_1": [
                  {"description": "Consulting", "quantity": 10, "rate": "$150", "amount": "$1,500"},
                  {"description": "Development", "quantity": 20, "rate": "$200", "amount": "$4,000"},
              ],
          },
      },
  )

  result = response.json()
  print(result["pdfUrl"])
  ```
</CodeGroup>

### Nested Line Items

Use the `children` key for nesting (up to 2 levels):

```json theme={null}
{
  "docId": "YOUR_AUTOMATION_ID",
  "data": {
    "project_name": "Website Redesign",
    "line_items_1": [
      {
        "phase": "Design",
        "children": [
          {
            "task": "Wireframes",
            "hours": 8,
            "children": [
              { "detail": "Homepage wireframe", "status": "Complete" }
            ]
          }
        ]
      }
    ]
  }
}
```

<Info>
  Learn more about setting up line items in your template in the [Line Items guide](/features/line-items).
</Info>

## Images

Any placeholder whose name contains `image` is filled with a picture. Pass a publicly accessible URL as the value (a single URL, or an array for a multi-image placeholder):

```json theme={null}
{
  "docId": "YOUR_AUTOMATION_ID",
  "data": {
    "image_logo": "https://example.com/logo.png",
    "image_gallery": [
      "https://example.com/a.jpg",
      "https://example.com/b.jpg"
    ]
  }
}
```

To make an image a clickable link, pass it as a `{ "url", "link" }` object instead of a plain URL string. No automation setup is required, and the link survives PDF export (Google Doc and Word templates). Arrays work too, with a `link` per image:

```json theme={null}
{
  "docId": "YOUR_AUTOMATION_ID",
  "data": {
    "image_product": {
      "url": "https://example.com/product.jpg",
      "link": "https://shop.example.com/products/123"
    }
  }
}
```

<Info>
  See [Dynamic Images](/features/dynamic-images) for supported formats, resizing, choosing which image to insert, and clickable links.
</Info>

## Async Mode

For high-volume or latency-sensitive workflows, use async mode. The API returns a `jobId` immediately, and you poll for the result.

<CodeGroup>
  ```bash cURL theme={null}
  # 1. Start async document creation
  curl -X POST https://api.docsautomator.co/createDocument \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "docId": "YOUR_AUTOMATION_ID",
      "async": true,
      "data": {
        "customer_name": "Acme Corp",
        "total": "$5,500.00"
      }
    }'
  # Returns: { "message": "Document creation request queued.", "jobId": "job_abc123", "logId": "..." }

  # 2. Poll for the result
  curl https://api.docsautomator.co/job/job_abc123 \
    -H "Authorization: Bearer YOUR_API_KEY"
  # Returns: { "status": "completed", "result": { "pdfUrl": "https://...", ... } }
  ```

  ```javascript Node.js theme={null}
  // 1. Start async document creation
  const createResponse = await fetch("https://api.docsautomator.co/createDocument", {
    method: "POST",
    headers: {
      "Authorization": "Bearer YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      docId: "YOUR_AUTOMATION_ID",
      async: true,
      data: {
        customer_name: "Acme Corp",
        total: "$5,500.00",
      },
    }),
  });

  const { jobId } = await createResponse.json();

  // 2. Poll for the result with exponential backoff
  let delay = 2000;
  while (true) {
    await new Promise((resolve) => setTimeout(resolve, delay));

    const jobResponse = await fetch(
      `https://api.docsautomator.co/job/${jobId}`,
      { headers: { "Authorization": "Bearer YOUR_API_KEY" } }
    );
    const job = await jobResponse.json();

    if (job.status === "completed") {
      console.log("PDF URL:", job.result.pdfUrl);
      break;
    }
    if (job.status === "failed") {
      throw new Error(`Job failed: ${job.error}`);
    }

    delay = Math.min(delay * 2, 30000); // Max 30s between polls
  }
  ```

  ```python Python theme={null}
  import requests
  import time

  # 1. Start async document creation
  create_response = requests.post(
      "https://api.docsautomator.co/createDocument",
      headers={
          "Authorization": "Bearer YOUR_API_KEY",
          "Content-Type": "application/json",
      },
      json={
          "docId": "YOUR_AUTOMATION_ID",
          "async": True,
          "data": {
              "customer_name": "Acme Corp",
              "total": "$5,500.00",
          },
      },
  )

  job_id = create_response.json()["jobId"]

  # 2. Poll for the result with exponential backoff
  delay = 2
  while True:
      time.sleep(delay)

      job_response = requests.get(
          f"https://api.docsautomator.co/job/{job_id}",
          headers={"Authorization": "Bearer YOUR_API_KEY"},
      )
      job = job_response.json()

      if job["status"] == "completed":
          print("PDF URL:", job["result"]["pdfUrl"])
          break
      if job["status"] == "failed":
          raise Exception(f"Job failed: {job.get('error')}")

      delay = min(delay * 2, 30)  # Max 30s between polls
  ```
</CodeGroup>

## Response

### Sync mode (200)

```json theme={null}
{
  "message": "success",
  "pdfUrl": "https://files.docsautomator.co/..."
}
```

Additional fields are included depending on your automation's configuration:

| Field                         | Included when                                                                                                |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `googleDocUrl`                | Save Google Doc is enabled                                                                                   |
| `savePdfGoogleDriveFolderId`  | Save PDF to Google Drive is enabled                                                                          |
| `savePdfGoogleDriveFileId`    | Save PDF to Google Drive is enabled                                                                          |
| `savePdfGoogleDriveUrl`       | Save PDF to Google Drive is enabled                                                                          |
| `wordFileUrl`                 | Save Word document is enabled (Word templates; download URL for the generated .docx)                         |
| `saveWordGoogleDriveFolderId` | Save Word document to Google Drive is enabled                                                                |
| `saveWordGoogleDriveFileId`   | Save Word document to Google Drive is enabled                                                                |
| `signingSessionId`            | E-signature is enabled                                                                                       |
| `signingStatus`               | E-signature is enabled (`"created"` or `"queued"`)                                                           |
| `signingLinks`                | E-signature is enabled (array of signer objects with `signerIndex`, `email`, `name`, `signingUrl`, `status`) |
| `signingDeliveryMethod`       | E-signature is enabled                                                                                       |
| `esignSkipped`                | E-signature is enabled but skipped for this request via `skipEsign: true`                                    |

### Async mode (202)

```json theme={null}
{
  "message": "Document creation request queued.",
  "jobId": "job_abc123",
  "logId": "log_xyz789"
}
```
