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

# Submissions

> Create and manage document submissions, pre-fill fields, track signing status, and download completed documents.

A submission is a single instance of a template sent out for signing. When you create a submission, you assign real people (with names and emails) to each submitter role defined in the template. DocuTrust handles sending invitation emails, tracking progress, and assembling the final signed document.

## Submission object

The standard submission object returned by list and create endpoints:

```json theme={null}
{
  "id": 187,
  "slug": "n3k8p1w5",
  "source": "api",
  "status": "pending",
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "submitter_count": 2,
  "created_at": "2026-04-08T10:31:00.000Z",
  "updated_at": "2026-04-08T10:31:00.000Z",
  "completed_at": null,
  "expire_at": "2026-05-08T10:31:00.000Z",
  "archived_at": null
}
```

| Field             | Type           | Description                                                                            |
| ----------------- | -------------- | -------------------------------------------------------------------------------------- |
| `id`              | integer        | Unique submission identifier.                                                          |
| `slug`            | string         | URL-safe unique identifier.                                                            |
| `source`          | string         | How the submission was created: `api`, `web`, `embed`, `bulk`, or `draft`.             |
| `status`          | string         | Current status: `draft`, `pending`, `completed`, `declined`, `expired`, or `archived`. |
| `template_id`     | string         | ID of the template this submission was created from.                                   |
| `submitter_count` | integer        | Number of submitter roles in this submission.                                          |
| `created_at`      | string         | ISO 8601 creation timestamp.                                                           |
| `updated_at`      | string         | ISO 8601 last-modified timestamp.                                                      |
| `completed_at`    | string or null | ISO 8601 timestamp when all submitters completed, or null.                             |
| `expire_at`       | string or null | ISO 8601 expiration timestamp, or null if no expiration set.                           |
| `archived_at`     | string or null | ISO 8601 timestamp when the submission was archived, or null.                          |

## Full submission object

When retrieving a single submission by ID, the response includes additional nested data:

```json theme={null}
{
  "id": 187,
  "slug": "n3k8p1w5",
  "source": "api",
  "status": "completed",
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "submitter_count": 2,
  "created_at": "2026-04-08T10:31:00.000Z",
  "updated_at": "2026-04-08T11:20:00.000Z",
  "completed_at": "2026-04-08T11:20:00.000Z",
  "expire_at": "2026-05-08T10:31:00.000Z",
  "archived_at": null,
  "metadata": {
    "deal_id": "DEAL-2026-0042",
    "department": "Sales"
  },
  "audit_log": [
    {
      "event": "submission.created",
      "timestamp": "2026-04-08T10:31:00.000Z",
      "actor": "admin@docutrust-test.com",
      "ip_address": "203.0.113.10"
    },
    {
      "event": "form.sent",
      "timestamp": "2026-04-08T10:31:01.000Z",
      "actor": "system",
      "ip_address": null
    },
    {
      "event": "form.viewed",
      "timestamp": "2026-04-08T11:10:00.000Z",
      "actor": "jane@example.com",
      "ip_address": "198.51.100.22"
    },
    {
      "event": "form.completed",
      "timestamp": "2026-04-08T11:15:00.000Z",
      "actor": "jane@example.com",
      "ip_address": "198.51.100.22"
    },
    {
      "event": "form.completed",
      "timestamp": "2026-04-08T11:20:00.000Z",
      "actor": "bob@acmecorp.com",
      "ip_address": "203.0.113.50"
    },
    {
      "event": "submission.completed",
      "timestamp": "2026-04-08T11:20:00.000Z",
      "actor": "system",
      "ip_address": null
    }
  ],
  "submitters": [
    {
      "id": 301,
      "uuid": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
      "slug": "r7t2q9v4",
      "email": "jane@example.com",
      "name": "Jane Smith",
      "role": "Client",
      "status": "completed",
      "phone": "+15551234567",
      "external_id": "cust-001",
      "metadata": {},
      "values": {
        "full_name": "Jane Smith",
        "agreement_date": "2026-04-08",
        "payment_method": "Credit Card"
      },
      "preferences": {
        "send_email": true
      },
      "opened_at": "2026-04-08T11:10:00.000Z",
      "sent_at": "2026-04-08T10:31:01.000Z",
      "completed_at": "2026-04-08T11:15:00.000Z",
      "declined_at": null
    },
    {
      "id": 302,
      "uuid": "a8b7c6d5-e4f3-2109-abcd-987654321098",
      "slug": "k5m9n3p7",
      "email": "bob@acmecorp.com",
      "name": "Bob Johnson",
      "role": "Company Representative",
      "status": "completed",
      "phone": null,
      "external_id": "emp-042",
      "metadata": {},
      "values": {
        "company_name": "Acme Corp",
        "rep_signature": "data:image/png;base64,..."
      },
      "preferences": {
        "send_email": true
      },
      "opened_at": "2026-04-08T11:17:00.000Z",
      "sent_at": "2026-04-08T10:31:01.000Z",
      "completed_at": "2026-04-08T11:20:00.000Z",
      "declined_at": null
    }
  ],
  "template": {
    "id": 42,
    "name": "Service Agreement",
    "slug": "qk7x9m2p",
    "external_id": "contract-sa-2026",
    "folder_name": "Legal Contracts"
  },
  "documents": [
    {
      "id": 95,
      "name": "Service Agreement - Signed.pdf",
      "url": "/api/submissions/187/documents/95",
      "content_type": "application/pdf",
      "size": 284672
    }
  ]
}
```

## Status lifecycle

Submissions move through these statuses:

```
draft → pending (via send_draft)
pending → completed
pending → declined
pending → expired
pending → archived
```

| Status      | Enum | Description                                                                                          |
| ----------- | ---- | ---------------------------------------------------------------------------------------------------- |
| `draft`     | `0`  | The submission has been created but not yet sent to submitters. No invitation emails are dispatched. |
| `pending`   | `1`  | At least one submitter has not yet completed their form. This is the status after sending.           |
| `completed` | `2`  | All submitters have completed their forms. The signed document is ready for download.                |
| `declined`  | `3`  | A submitter declined to sign the document, causing the submission to terminate.                      |
| `expired`   | `4`  | The submission passed its `expire_at` timestamp without all parties completing.                      |
| `archived`  | --   | The submission was manually archived via the API or dashboard.                                       |

<Note>
  A submission moves to `completed` only when every submitter's status is `completed`. If even one submitter is still `waiting` or `sent`, the submission remains `pending`. A submission moves to `declined` when any submitter declines.
</Note>

## Creating submissions

### Basic creation

Send a template for signing by creating a submission with submitter details mapped to the template's roles.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "$DOCUTRUST_URL/api/submissions" \
    -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "send_email": true,
      "submitters_order": "sequential",
      "expire_at": "2026-05-08T00:00:00.000Z",
      "metadata": {
        "deal_id": "DEAL-2026-0042",
        "department": "Sales"
      },
      "quick_sign_mode": "review_and_sign",
      "prefill_behavior": {
        "skip_if_prefilled": true,
        "editable_if_prefilled": false
      },
      "submitters": [
        {
          "role": "Client",
          "email": "jane@example.com",
          "name": "Jane Smith",
          "phone": "+15551234567",
          "external_id": "cust-001",
          "metadata": {},
          "values": {
            "full_name": "Jane Smith",
            "agreement_date": "2026-04-08"
          }
        },
        {
          "role": "Company Representative",
          "email": "bob@acmecorp.com",
          "name": "Bob Johnson",
          "phone": null,
          "external_id": "emp-042",
          "metadata": {},
          "values": {
            "company_name": "Acme Corp"
          }
        }
      ]
    }'
  ```

  ## Binary field-value limits

  Base64 data-URI values for `signature`, `initials`, `stamp`, `image`, and `file` fields are limited
  to 10 MB each by default. This boundary is shared by signing, API, MCP, and bulk/service writers,
  so changing the write path does not bypass it. Invalid Base64 or oversized values return a
  structured field validation error; API writers surface it as `422`.

  Self-hosted operators may adjust `MAX_FIELD_UPLOAD_SIZE_MB`. Invalid or non-positive settings
  fall back to 10 MB.

  ```javascript Node.js theme={null}
  const response = await fetch(`${process.env.DOCUTRUST_URL}/api/submissions`, {
    method: "POST",
    headers: {
      "X-Auth-Token": process.env.DOCUTRUST_TOKEN,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      template_id: "tpl_7VQhP2tM9xA1kR8bN",
      send_email: true,
      submitters_order: "sequential",
      expire_at: "2026-05-08T00:00:00.000Z",
      metadata: {
        deal_id: "DEAL-2026-0042",
        department: "Sales",
      },
      quick_sign_mode: "review_and_sign",
      prefill_behavior: {
        skip_if_prefilled: true,
        editable_if_prefilled: false,
      },
      submitters: [
        {
          role: "Client",
          email: "jane@example.com",
          name: "Jane Smith",
          phone: "+15551234567",
          external_id: "cust-001",
          metadata: {},
          values: { full_name: "Jane Smith", agreement_date: "2026-04-08" },
        },
        {
          role: "Company Representative",
          email: "bob@acmecorp.com",
          name: "Bob Johnson",
          phone: null,
          external_id: "emp-042",
          metadata: {},
          values: { company_name: "Acme Corp" },
        },
      ],
    }),
  });

  const submission = await response.json();
  ```

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

  url = f"{os.environ['DOCUTRUST_URL']}/api/submissions"
  headers = {
      "X-Auth-Token": os.environ["DOCUTRUST_TOKEN"],
      "Content-Type": "application/json",
  }
  payload = {
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "send_email": True,
      "submitters_order": "sequential",
      "expire_at": "2026-05-08T00:00:00.000Z",
      "metadata": {
          "deal_id": "DEAL-2026-0042",
          "department": "Sales",
      },
      "quick_sign_mode": "review_and_sign",
      "prefill_behavior": {
          "skip_if_prefilled": True,
          "editable_if_prefilled": False,
      },
      "submitters": [
          {
              "role": "Client",
              "email": "jane@example.com",
              "name": "Jane Smith",
              "phone": "+15551234567",
              "external_id": "cust-001",
              "metadata": {},
              "values": {"full_name": "Jane Smith", "agreement_date": "2026-04-08"},
          },
          {
              "role": "Company Representative",
              "email": "bob@acmecorp.com",
              "name": "Bob Johnson",
              "phone": None,
              "external_id": "emp-042",
              "metadata": {},
              "values": {"company_name": "Acme Corp"},
          },
      ],
  }

  response = requests.post(url, headers=headers, json=payload)
  submission = response.json()
  ```
</CodeGroup>

### Request parameters

| Parameter          | Type    | Required | Description                                                                                                                                |
| ------------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `template_id`      | string  | Yes      | The template to create a submission from.                                                                                                  |
| `send_email`       | boolean | No       | Whether to send invitation emails to submitters. Defaults to `true`.                                                                       |
| `submitters_order` | string  | No       | `"sequential"` (submitters sign in order) or `"parallel"` (all sign simultaneously). Defaults to `"sequential"`.                           |
| `quick_sign_mode`  | string  | No       | Controls quick-sign behavior for the submission. Defaults to `"confirmation_modal"` when omitted. Set `"normal"` to force legacy behavior. |
| `prefill_behavior` | object  | No       | Submission-level prefill behavior. Defaults to `{ "skip_if_prefilled": true, "editable_if_prefilled": false }` when omitted.               |
| `expire_at`        | string  | No       | ISO 8601 timestamp when the submission should expire.                                                                                      |
| `metadata`         | object  | No       | Custom key-value pairs attached to the submission for your application's use.                                                              |
| `preferences`      | object  | No       | Submission-level preferences (for example message overrides, redirect URLs, reminder templates).                                           |
| `submitters`       | array   | Yes      | Array of submitter objects (see below).                                                                                                    |

### Submitter parameters

| Parameter     | Type    | Required | Description                                                                                                                                                           |
| ------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `role`        | string  | Yes      | Must match a submitter role name from the template.                                                                                                                   |
| `email`       | string  | Yes      | Submitter's email address.                                                                                                                                            |
| `name`        | string  | No       | Submitter's full name.                                                                                                                                                |
| `phone`       | string  | No       | Phone number in E.164 format (e.g., `+15551234567`). Required if the template has `phone_verification` fields.                                                        |
| `external_id` | string  | No       | Your custom identifier for mapping to external systems.                                                                                                               |
| `metadata`    | object  | No       | Custom key-value pairs attached to this specific submitter.                                                                                                           |
| `values`      | object  | No       | Pre-filled field values keyed by field `key`. See [Pre-filling field values](#pre-filling-field-values).                                                              |
| `preferences` | object  | No       | Submitter-level preferences. See below.                                                                                                                               |
| `completed`   | boolean | No       | When `true`, the submitter is immediately marked as completed without going through the signing flow. See [Auto-sign](#auto-sign).                                    |
| `send_sms`    | boolean | No       | When `true`, sends an SMS notification to the submitter's `phone` number instead of an email. Requires `phone` to be set in E.164 format.                             |
| `fields`      | array   | No       | Per-submitter field overrides. Each entry sets a `default_value` for a specific field by `name`. See [Per-submitter field overrides](#per-submitter-field-overrides). |

### Submitter preferences

| Preference   | Type    | Default | Description                                                     |
| ------------ | ------- | ------- | --------------------------------------------------------------- |
| `send_email` | boolean | `true`  | Whether to send an invitation email to this specific submitter. |

## Auto-sign

When a submitter's role is pre-approved (e.g., the sender or an internal representative), you can skip their signing flow entirely by setting `completed: true`. The submitter is immediately recorded as completed, and the submission moves forward to the next party (or finishes if this was the last submitter).

```json theme={null}
{
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "send_email": false,
  "submitters_order": "sequential",
  "quick_sign_mode": "normal",
  "expire_at": "2026-06-01T00:00:00.000Z",
  "metadata": {
    "deal_id": "DEAL-2026-0099",
    "auto_approved_by": "ops-team"
  },
  "submitters": [
    {
      "email": "sender@company.com",
      "name": "Company Representative",
      "role": "First Party",
      "completed": true,
      "phone": "+15559876543",
      "external_id": "emp-100",
      "metadata": {
        "department": "Operations"
      },
      "values": {
        "company_name": "Acme Corp",
        "rep_title": "Director of Operations"
      },
      "preferences": {
        "send_email": false
      }
    },
    {
      "email": "recipient@client.com",
      "name": "Client",
      "role": "Second Party",
      "phone": "+15551234567",
      "external_id": "cust-200",
      "metadata": {},
      "values": {
        "full_name": "Client"
      },
      "preferences": {
        "send_email": true
      }
    }
  ]
}
```

<Tip>
  This is useful for workflows where the sender pre-approves their portion of the document before the recipient signs. The first party's fields are locked with their pre-filled values, and only the second party needs to complete the signing flow.
</Tip>

## Pre-filling field values

Pre-fill fields by passing a `values` object keyed by field `key`/`name` or field UUID. This is useful for populating known information like names, addresses, or dates so signers do not have to type them manually.

```json theme={null}
{
  "submitters": [
    {
      "role": "Client",
      "email": "jane@example.com",
      "values": {
        "full_name": "Jane Smith",
        "email_address": "jane@example.com",
        "agreement_date": "2026-04-08",
        "company_name": "Smith Consulting LLC",
        "address_line_1": "123 Main St",
        "city": "Portland",
        "state": "OR",
        "zip_code": "97201",
        "payment_method": "Credit Card"
      }
    }
  ]
}
```

### Repeated key behavior (fan-out)

If a single key/name matches multiple fields in the template schema:

* Scalar value: value is applied to all matching field UUIDs.
* Array value with exact length: values are distributed positionally in document order.
* Array length mismatch: request fails with `422 invalid_field_values`.
* Mixed UUID + key payloads: UUID-keyed values win for explicitly targeted fields; key-based values fill remaining matches.

When key-based mapping matches multiple fields, the API returns a warning header:

* `X-Submission-Warning: name_key_ambiguous:<key>`

<Tip>
  Combine pre-filling with `readonly: true` on the field in the template schema to lock certain values. The signer will see the value but cannot change it.
</Tip>

### Per-submitter field overrides

Use the `fields` array on a submitter to set default values for specific fields by name. This is different from the `values` object (which uses field keys): `fields` targets fields by their human-readable `name` and lets you set a `default_value` that the signer sees when they open the form.

```json theme={null}
{
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "send_email": true,
  "submitters_order": "sequential",
  "expire_at": "2026-06-15T00:00:00.000Z",
  "metadata": {
    "onboarding_batch": "Q2-2026"
  },
  "submitters": [
    {
      "email": "signer@example.com",
      "name": "Jane Smith",
      "role": "First Party",
      "phone": "+15551234567",
      "external_id": "cust-301",
      "metadata": {
        "source": "onboarding-portal"
      },
      "fields": [
        {
          "name": "Company Name",
          "default_value": "Acme Corp"
        },
        {
          "name": "Start Date",
          "default_value": "2026-05-01"
        },
        {
          "name": "Department",
          "default_value": "Engineering"
        },
        {
          "name": "Employee ID",
          "default_value": "EMP-2026-0042"
        }
      ],
      "values": {
        "full_name": "Jane Smith",
        "email_address": "signer@example.com"
      },
      "preferences": {
        "send_email": true
      }
    }
  ]
}
```

<Note>
  `fields` sets the default value shown in the form (the signer can change it unless the field is `readonly` in the template schema). `values` pre-fills the field and records it as the submitted value. You can use both together -- `values` takes precedence for any overlapping fields.
</Note>

### Value types by field

| Field type  | Value format                                                   | Example                                    |
| ----------- | -------------------------------------------------------------- | ------------------------------------------ |
| `text`      | Any scalar, coerced to string (`null`/`undefined` -> `""`)     | `"Jane Smith"` or `150`                    |
| `number`    | Number, or numeric string (non-numeric strings rejected)       | `"42500"` or `42500`                       |
| `date`      | ISO date (`YYYY-MM-DD`) or ISO timestamp (coerced to date)     | `"2026-04-08"` or `"2026-04-08T17:26:13Z"` |
| `checkbox`  | Boolean, or boolean-like strings (`true/false/1/0/y/n/yes/no`) | `true` or `"yes"`                          |
| `select`    | String (must match an option)                                  | `"Credit Card"`                            |
| `radio`     | String (must match an option)                                  | `"Option A"`                               |
| `cells`     | String                                                         | `"123456789"`                              |
| `signature` | String data URL, or `{ "image": "data:image/png;base64,..." }` | `"data:image/png;base64,..."`              |
| `initials`  | String data URL, or `{ "image": "data:image/png;base64,..." }` | `"data:image/png;base64,..."`              |
| `file`      | Not pre-fillable                                               | Files must be uploaded by the signer.      |

## Quick sign modes

Control the signing experience for the submission using top-level `quick_sign_mode`.

When omitted, the API defaults to:

* `quick_sign_mode: "confirmation_modal"`
* `prefill_behavior: { "skip_if_prefilled": true, "editable_if_prefilled": false }`

| Mode                    | Description                                                                                                                                                                                                                                                                                                                                                                                                 |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `normal`                | Standard signing flow. The signer scrolls through the document and fills each field individually.                                                                                                                                                                                                                                                                                                           |
| `review_and_sign`       | The signer reviews the entire document first, then completes all fields in a guided step-by-step flow at the end.                                                                                                                                                                                                                                                                                           |
| `confirmation_modal`    | A bottom-sheet carousel walks the signer through signature and initials fields only. Text fields are pre-filled and shown as read-only overlays on the document. Signatures are grouped by type — the signer signs **once** and it applies to all signature fields, same for initials. Typically a 2-step flow. The start screen is auto-skipped. Falls back to `normal` if required text fields are empty. |
| `auto_scroll_signature` | The document auto-scrolls to each signature field in sequence. Optimized for documents with many signature lines.                                                                                                                                                                                                                                                                                           |

```json theme={null}
{
  "quick_sign_mode": "confirmation_modal",
  "submitters": [
    {
      "role": "Client",
      "email": "jane@example.com"
    }
  ]
}
```

To force legacy behavior:

```json theme={null}
{
  "quick_sign_mode": "normal",
  "prefill_behavior": {
    "skip_if_prefilled": false,
    "editable_if_prefilled": true
  }
}
```

## Draft submissions

Create a draft submission that is not sent to submitters until you explicitly send it. This is useful for building submissions incrementally or requiring approval before sending.

### Create a draft

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "send_email": false,
    "status": "draft",
    "submitters": [
      {
        "role": "Client",
        "email": "jane@example.com",
        "name": "Jane Smith"
      }
    ]
  }'
```

### Update a draft

Modify the draft before sending:

```bash theme={null}
curl -X PUT "$DOCUTRUST_URL/api/submissions/187" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "submitters": [
      {
        "role": "Client",
        "email": "jane@example.com",
        "name": "Jane M. Smith",
        "values": {
          "full_name": "Jane M. Smith"
        }
      }
    ]
  }'
```

### Send a draft

When the draft is ready, send it to all submitters:

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/187/send_draft" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

## Bulk creation

Send the same template to many recipients at once. Each entry in the array creates an independent submission.

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/bulk_create" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "send_email": true,
    "submissions": [
      {
        "submitters": [
          {
            "role": "Client",
            "email": "jane@example.com",
            "name": "Jane Smith",
            "values": { "full_name": "Jane Smith" }
          }
        ]
      },
      {
        "submitters": [
          {
            "role": "Client",
            "email": "bob@example.com",
            "name": "Bob Johnson",
            "values": { "full_name": "Bob Johnson" }
          }
        ]
      },
      {
        "submitters": [
          {
            "role": "Client",
            "email": "carol@example.com",
            "name": "Carol Williams",
            "values": { "full_name": "Carol Williams" }
          }
        ]
      }
    ]
  }'
```

**Response:**

```json theme={null}
[
  {
    "id": 200,
    "slug": "a1b2c3d4",
    "source": "bulk",
    "status": "pending",
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "submitter_count": 1,
    "created_at": "2026-04-08T12:00:00.000Z",
    "updated_at": "2026-04-08T12:00:00.000Z",
    "completed_at": null,
    "expire_at": null,
    "archived_at": null
  },
  {
    "id": 201,
    "slug": "e5f6g7h8",
    "source": "bulk",
    "status": "pending",
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "submitter_count": 1,
    "created_at": "2026-04-08T12:00:00.000Z",
    "updated_at": "2026-04-08T12:00:00.000Z",
    "completed_at": null,
    "expire_at": null,
    "archived_at": null
  },
  {
    "id": 202,
    "slug": "i9j0k1l2",
    "source": "bulk",
    "status": "pending",
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "submitter_count": 1,
    "created_at": "2026-04-08T12:00:00.000Z",
    "updated_at": "2026-04-08T12:00:00.000Z",
    "completed_at": null,
    "expire_at": null,
    "archived_at": null
  }
]
```

### Preview before sending

Use the bulk preview endpoint to validate your data without actually creating submissions:

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/bulk_preview" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "submissions": [
      {
        "submitters": [
          {
            "role": "Client",
            "email": "jane@example.com",
            "name": "Jane Smith"
          }
        ]
      }
    ]
  }'
```

## Email-based bulk creation

Create one submission per email address from a comma-separated string. This is a convenience endpoint that avoids the overhead of building the full `submissions` array when you only need simple single-role submissions.

`POST /api/submissions/emails`

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "$DOCUTRUST_URL/api/submissions/emails" \
    -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "emails": "alice@example.com, bob@example.com, carol@example.com",
      "send_email": true,
      "send_sms": false,
      "name": "Default Name",
      "role": "First Party",
      "message": {
        "subject": "Please sign this document",
        "body": "Hi {{submitter.name}}, please review and sign {{template.name}}."
      },
      "expire_at": "2026-05-01T00:00:00Z",
      "metadata": {
        "campaign": "onboarding-q2-2026",
        "source": "hr-portal"
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch(`${process.env.DOCUTRUST_URL}/api/submissions/emails`, {
    method: "POST",
    headers: {
      "X-Auth-Token": process.env.DOCUTRUST_TOKEN,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      template_id: "tpl_7VQhP2tM9xA1kR8bN",
      emails: "alice@example.com, bob@example.com, carol@example.com",
      send_email: true,
      send_sms: false,
      name: "Default Name",
      role: "First Party",
      message: {
        subject: "Please sign this document",
        body: "Hi {{submitter.name}}, please review and sign {{template.name}}.",
      },
      expire_at: "2026-05-01T00:00:00Z",
      metadata: {
        campaign: "onboarding-q2-2026",
        source: "hr-portal",
      },
    }),
  });

  const submitters = await response.json();
  ```

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

  url = f"{os.environ['DOCUTRUST_URL']}/api/submissions/emails"
  headers = {
      "X-Auth-Token": os.environ["DOCUTRUST_TOKEN"],
      "Content-Type": "application/json",
  }
  payload = {
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "emails": "alice@example.com, bob@example.com, carol@example.com",
      "send_email": True,
      "send_sms": False,
      "name": "Default Name",
      "role": "First Party",
      "message": {
          "subject": "Please sign this document",
          "body": "Hi {{submitter.name}}, please review and sign {{template.name}}.",
      },
      "quick_sign_mode": "confirmation_modal",
      "expire_at": "2026-05-01T00:00:00Z",
      "metadata": {
          "campaign": "onboarding-q2-2026",
          "source": "hr-portal",
      },
  }

  response = requests.post(url, headers=headers, json=payload)
  submitters = response.json()
  ```
</CodeGroup>

### Request parameters

| Parameter          | Type    | Required | Description                                                                                                                                            |
| ------------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `template_id`      | string  | Yes      | The template to create submissions from.                                                                                                               |
| `emails`           | string  | Yes      | Comma-separated list of email addresses. One submission is created per email.                                                                          |
| `send_email`       | boolean | No       | Whether to send invitation emails. Defaults to `true`.                                                                                                 |
| `send_sms`         | boolean | No       | Whether to send SMS notifications instead of email. Requires phone-capable template. Defaults to `false`.                                              |
| `quick_sign_mode`  | string  | No       | Quick-sign mode for each created submission. Defaults to `"confirmation_modal"` when omitted.                                                          |
| `prefill_behavior` | object  | No       | Prefill behavior for each created submission. Defaults to `{ "skip_if_prefilled": true, "editable_if_prefilled": false }` when omitted.                |
| `name`             | string  | No       | Default display name assigned to each submitter.                                                                                                       |
| `role`             | string  | No       | The submitter role to assign. Must match a role in the template. Defaults to the first role.                                                           |
| `message`          | object  | No       | Custom email message with `subject` and `body`. Supports tokens: `{{submitter.name}}`, `{{submitter.email}}`, `{{template.name}}`, `{{account.name}}`. |
| `expire_at`        | string  | No       | ISO 8601 expiration timestamp applied to all created submissions.                                                                                      |
| `metadata`         | object  | No       | Custom key-value pairs attached to each created submission.                                                                                            |

**Response:**

Returns an array of submitter objects, each with an `embed_src` URL for embedding the signing form:

```json theme={null}
[
  {
    "id": 401,
    "uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "slug": "p3q7r2s8",
    "email": "alice@example.com",
    "name": "Default Name",
    "role": "First Party",
    "status": "sent",
    "phone": null,
    "external_id": null,
    "metadata": {},
    "values": {},
    "preferences": {
      "send_email": true
    },
    "embed_src": "https://your-app.com/s/p3q7r2s8",
    "opened_at": null,
    "sent_at": "2026-04-09T10:00:00.000Z",
    "completed_at": null,
    "declined_at": null,
    "submission_id": 210,
    "template_id": "tpl_7VQhP2tM9xA1kR8bN"
  },
  {
    "id": 402,
    "uuid": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
    "slug": "t4u8v3w9",
    "email": "bob@example.com",
    "name": "Default Name",
    "role": "First Party",
    "status": "sent",
    "phone": null,
    "external_id": null,
    "metadata": {},
    "values": {},
    "preferences": {
      "send_email": true
    },
    "embed_src": "https://your-app.com/s/t4u8v3w9",
    "opened_at": null,
    "sent_at": "2026-04-09T10:00:00.000Z",
    "completed_at": null,
    "declined_at": null,
    "submission_id": 211,
    "template_id": "tpl_7VQhP2tM9xA1kR8bN"
  },
  {
    "id": 403,
    "uuid": "c3d4e5f6-a7b8-9012-cdef-123456789012",
    "slug": "x5y9z4a1",
    "email": "carol@example.com",
    "name": "Default Name",
    "role": "First Party",
    "status": "sent",
    "phone": null,
    "external_id": null,
    "metadata": {},
    "values": {},
    "preferences": {
      "send_email": true
    },
    "embed_src": "https://your-app.com/s/x5y9z4a1",
    "opened_at": null,
    "sent_at": "2026-04-09T10:00:00.000Z",
    "completed_at": null,
    "declined_at": null,
    "submission_id": 212,
    "template_id": "tpl_7VQhP2tM9xA1kR8bN"
  }
]
```

<Tip>
  Use the `embed_src` URL from each submitter object to embed the signing form directly in your application via an iframe, without the signer needing to check their email.
</Tip>

## Listing submissions

```bash theme={null}
curl "$DOCUTRUST_URL/api/submissions?limit=25&status=pending" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

### Filter parameters

| Parameter     | Type    | Description                                                                           |
| ------------- | ------- | ------------------------------------------------------------------------------------- |
| `status`      | string  | Filter by status: `draft`, `pending`, `completed`, `declined`, `expired`, `archived`. |
| `template_id` | string  | Filter by template.                                                                   |
| `after`       | integer | Cursor for pagination (return items after this ID).                                   |
| `before`      | integer | Cursor for pagination (return items before this ID).                                  |
| `limit`       | integer | Items per page (1-100, default 10).                                                   |

**Response:**

```json theme={null}
{
  "data": [
    {
      "id": 187,
      "slug": "n3k8p1w5",
      "source": "api",
      "status": "pending",
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "submitter_count": 2,
      "created_at": "2026-04-08T10:31:00.000Z",
      "updated_at": "2026-04-08T10:31:00.000Z",
      "completed_at": null,
      "expire_at": "2026-05-08T10:31:00.000Z",
      "archived_at": null
    },
    {
      "id": 185,
      "slug": "m2n9p4q7",
      "source": "web",
      "status": "completed",
      "template_id": "tpl_7VQhP2tM9xA1kR8bN",
      "submitter_count": 1,
      "created_at": "2026-04-07T14:00:00.000Z",
      "updated_at": "2026-04-07T15:30:00.000Z",
      "completed_at": "2026-04-07T15:30:00.000Z",
      "expire_at": null,
      "archived_at": null
    }
  ],
  "pagination": {
    "count": 2,
    "next": 185,
    "prev": null
  }
}
```

## Retrieving a submission

```bash theme={null}
curl "$DOCUTRUST_URL/api/submissions/187" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

This returns the [full submission object](#full-submission-object) with nested submitters, audit log, template, and documents.

## Sending reminders

Send reminder emails (or SMS) to all submitters who have not yet completed a pending submission.

`POST /api/submissions/:id/send_reminder`

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/187/send_reminder" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

**Response:**

```json theme={null}
{
  "success": true,
  "reminded": 2,
  "submitters": [
    {
      "id": 301,
      "uuid": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
      "slug": "r7t2q9v4",
      "email": "jane@example.com",
      "name": "Jane Smith",
      "role": "Client",
      "status": "sent",
      "phone": "+15551234567",
      "external_id": "cust-001",
      "metadata": {},
      "values": {},
      "preferences": {
        "send_email": true
      },
      "opened_at": null,
      "sent_at": "2026-04-08T10:31:01.000Z",
      "completed_at": null,
      "declined_at": null
    },
    {
      "id": 302,
      "uuid": "a8b7c6d5-e4f3-2109-abcd-987654321098",
      "slug": "k5m9n3p7",
      "email": "bob@acmecorp.com",
      "name": "Bob Johnson",
      "role": "Company Representative",
      "status": "sent",
      "phone": null,
      "external_id": "emp-042",
      "metadata": {},
      "values": {},
      "preferences": {
        "send_email": true
      },
      "opened_at": "2026-04-08T11:17:00.000Z",
      "sent_at": "2026-04-08T10:31:01.000Z",
      "completed_at": null,
      "declined_at": null
    }
  ]
}
```

<Note>
  Reminders are only sent to submitters whose status is `waiting`, `sent`, or `opened`. Submitters who have already completed, declined, or expired are skipped. The `reminded` count reflects how many submitters actually received a reminder. If the submission is already completed, expired, or archived, the endpoint returns a `422` error.
</Note>

### Customizable reminder emails

Customize the subject and body of reminder emails by including `reminder_subject` and `reminder_body` in the submission `preferences` when creating or updating a submission.

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_7VQhP2tM9xA1kR8bN",
    "send_email": true,
    "submitters_order": "sequential",
    "expire_at": "2026-05-08T00:00:00.000Z",
    "preferences": {
      "reminder_subject": "Action required: Please sign {{template.name}}",
      "reminder_body": "Hi {{submitter.name}},\n\nThis is a friendly reminder that your signature is still needed on {{template.name}}.\n\nPlease click the link below to review and sign:\n{{submitter.link}}\n\nThis document expires on {{submission.expire_at}}.\n\nThank you,\n{{account.name}}"
    },
    "metadata": {
      "deal_id": "DEAL-2026-0042",
      "department": "Sales"
    },
    "submitters": [
      {
        "role": "Client",
        "email": "jane@example.com",
        "name": "Jane Smith",
        "phone": "+15551234567",
        "external_id": "cust-001",
        "metadata": {},
        "values": {
          "full_name": "Jane Smith",
          "agreement_date": "2026-04-08"
        }
      }
    ]
  }'
```

**Supported tokens in reminder templates:**

| Token                      | Description                                 |
| -------------------------- | ------------------------------------------- |
| `{{submitter.name}}`       | The submitter's display name.               |
| `{{submitter.email}}`      | The submitter's email address.              |
| `{{submitter.link}}`       | The unique signing URL for this submitter.  |
| `{{template.name}}`        | The template name.                          |
| `{{submission.expire_at}}` | The submission expiration date (formatted). |
| `{{account.name}}`         | Your account/company name.                  |

<Tip>
  If `reminder_subject` or `reminder_body` are not set, DocuTrust uses the default reminder email template configured in your account settings.
</Tip>

## Subscription payments

Collect subscription payments from signers as part of the signing workflow. Use `POST /api/payments/subscribe` to create a subscription payment linked to a submission.

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/payments/subscribe" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "submission_id": 187,
    "submitter_id": 301,
    "plan_id": "plan_premium_monthly",
    "price_cents": 4999,
    "currency": "usd",
    "interval": "month",
    "interval_count": 1,
    "trial_days": 14,
    "metadata": {
      "customer_id": "cust-001",
      "deal_id": "DEAL-2026-0042",
      "plan_name": "Premium Monthly"
    }
  }'
```

**Request parameters:**

| Parameter        | Type    | Required | Description                                                         |
| ---------------- | ------- | -------- | ------------------------------------------------------------------- |
| `submission_id`  | integer | Yes      | The submission this payment is linked to.                           |
| `submitter_id`   | integer | Yes      | The submitter making the payment.                                   |
| `plan_id`        | string  | Yes      | Your internal plan identifier.                                      |
| `price_cents`    | integer | Yes      | Price in cents (e.g., `4999` for \$49.99).                          |
| `currency`       | string  | Yes      | ISO 4217 currency code (e.g., `"usd"`, `"eur"`, `"gbp"`).           |
| `interval`       | string  | Yes      | Billing interval: `"day"`, `"week"`, `"month"`, or `"year"`.        |
| `interval_count` | integer | No       | Number of intervals between billings. Defaults to `1`.              |
| `trial_days`     | integer | No       | Number of free trial days before the first charge. Defaults to `0`. |
| `metadata`       | object  | No       | Custom key-value pairs attached to the subscription.                |

**Response:**

```json theme={null}
{
  "id": 56,
  "submission_id": 187,
  "submitter_id": 301,
  "plan_id": "plan_premium_monthly",
  "status": "active",
  "price_cents": 4999,
  "currency": "usd",
  "interval": "month",
  "interval_count": 1,
  "trial_days": 14,
  "trial_ends_at": "2026-04-22T10:31:00.000Z",
  "current_period_start": "2026-04-08T10:31:00.000Z",
  "current_period_end": "2026-05-08T10:31:00.000Z",
  "metadata": {
    "customer_id": "cust-001",
    "deal_id": "DEAL-2026-0042",
    "plan_name": "Premium Monthly"
  },
  "created_at": "2026-04-08T10:31:00.000Z",
  "updated_at": "2026-04-08T10:31:00.000Z"
}
```

<Note>
  Subscription payments require payment configuration to be set up in your account settings. See the [Payments feature guide](/features/payments) for initial setup.
</Note>

## Downloading completed documents

### Download all documents as a ZIP

```bash theme={null}
curl -O -J "$DOCUTRUST_URL/api/submissions/187/documents/download" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

### Download as a merged PDF

Merge all documents in the submission into a single PDF file. This is useful when a submission contains multiple documents (e.g., agreement + addendum + audit trail) and you want a single combined file.

```bash theme={null}
curl -O -J "$DOCUTRUST_URL/api/submissions/187/documents/download?merge=true" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

The `merge=true` query parameter instructs the server to concatenate all submission documents in order and return a single PDF. Without this parameter, the endpoint returns a ZIP archive containing each document as a separate file.

### Download by document type

Request a specific document type instead of the full package:

```bash theme={null}
# Signed PDF only (no audit trail)
curl -O -J "$DOCUTRUST_URL/api/submissions/187/documents/download?type=signed_pdf" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"

# Audit trail only
curl -O -J "$DOCUTRUST_URL/api/submissions/187/documents/download?type=audit_trail" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"

# Combined (default) — signed PDF + audit trail in one file
curl -O -J "$DOCUTRUST_URL/api/submissions/187/documents/download?type=combined" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

Add `?inline=true` to return with `Content-Disposition: inline` for in-browser preview instead of download.

<Note>
  Documents are generated asynchronously after all submitters complete. If `GET /api/submissions/:id/documents` returns an empty array for a completed submission, the document generation job hasn't finished yet. Wait a few seconds and retry.
</Note>

### List available documents

```bash theme={null}
curl "$DOCUTRUST_URL/api/submissions/187/documents" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

**Response:**

```json theme={null}
[
  {
    "id": 95,
    "name": "Service Agreement - Signed.pdf",
    "url": "/api/submissions/187/documents/95",
    "content_type": "application/pdf",
    "size": 284672
  },
  {
    "id": 96,
    "name": "Service Agreement - Audit Trail.pdf",
    "url": "/api/submissions/187/documents/96",
    "content_type": "application/pdf",
    "size": 45312
  }
]
```

## Archiving submissions

Archive a submission to remove it from active views. The submission data is preserved and can still be retrieved via the API.

```bash theme={null}
curl -X DELETE "$DOCUTRUST_URL/api/submissions/187" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN"
```

<Note>
  Archiving is a soft delete. The submission and all its documents remain accessible. The `archived_at` timestamp is set and the `status` changes to `archived`.
</Note>

## Creating from document files

You can skip the template creation step entirely and create a submission directly from a document file. DocuTrust creates a one-time template behind the scenes.

### From PDF

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/pdf" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -F "files[]=@/path/to/contract.pdf" \
  -F "submitters[][role]=First Party" \
  -F "submitters[][email]=jane@example.com" \
  -F "submitters[][name]=Jane Smith"
```

### From DOCX

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/docx" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -F "file=@/path/to/contract.docx" \
  -F "submitters[][role]=First Party" \
  -F "submitters[][email]=jane@example.com"
```

### From HTML

```bash theme={null}
curl -X POST "$DOCUTRUST_URL/api/submissions/html" \
  -H "X-Auth-Token: $DOCUTRUST_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<html><body><h1>Quick Agreement</h1><p>I agree to the terms.</p></body></html>",
    "submitters": [
      {
        "role": "First Party",
        "email": "jane@example.com",
        "name": "Jane Smith"
      }
    ]
  }'
```
