# How the Docuseal Multi-Submitter Workflow Handles Document Submissions

> Discover how the Docuseal multi-submitter workflow handles document submissions. Learn about unambiguous submission creation and support for complex agreements, even with undefined submitters.

- Repository: [DocuSeal/docuseal](https://github.com/docusealco/docuseal)
- Tags: how-to-guide
- Published: 2026-05-05

---

**The Docuseal multi-submitter workflow identifies "undefined" submitters—those lacking email, invitation metadata, or role assignments—and restricts public shared links to templates containing exactly one such undefined submitter, ensuring unambiguous submission creation while supporting complex multi-party agreements through deterministic UUID assignment.**

The multi-submitter workflow in Docuseal enables templates to support unlimited signers while maintaining deterministic behavior for public submissions. When sharing templates via public links, the platform must resolve which party the link represents without requiring prior email configuration. This workflow is implemented in the `docusealco/docuseal` repository through a validation system that filters undefined submitters and enforces single-owner semantics for shared access.

## Identifying Undefined Submitters

The workflow hinges on distinguishing between defined and **undefined submitters**. A submitter is considered undefined when it lacks all of the following attributes: `invite_by_uuid`, `optional_invite_by_uuid`, `invite_via_field_uuid`, `linked_to_uuid`, `is_requester`, or `email`.

The `Templates.filter_undefined_submitters` method in [`lib/templates.rb`](https://github.com/docusealco/docuseal/blob/main/lib/templates.rb) (lines 74‑80) scans the template’s submitter list and returns only entries that meet this "blank" criteria. This helper is called early in the submission creation process to determine if a public link can safely generate a submission.

## Validating Shared Link Requests

When a user submits via a public link, `StartFormController#update` orchestrates the validation. The controller first calls `filter_undefined_submitters` to count how many undefined submitters remain in the template.

**If the count exceeds one**, the request is rejected with **422 Unprocessable Content**. The response includes a specific error message generated by `multiple_submitters_error_message` (lines 204‑210 in [`app/controllers/start_form_controller.rb`](https://github.com/docusealco/docuseal/blob/main/app/controllers/start_form_controller.rb)), preventing ambiguous links that could accidentally assign the submission to the wrong party. This guard (lines 44‑48) ensures that public links only work when the submission owner is unambiguous.

## Constructing the Submission

Once the guard passes—meaning exactly one undefined submitter exists—the controller proceeds to `assign_submission_attributes` (lines 152‑174). This method performs three critical operations:

1. **Selects the submitter UUID**: It picks the UUID of the first undefined submitter (or the first submitter if none are undefined) to serve as the submission owner (`@submitter.uuid`).
2. **Creates the submission object**: It instantiates a new `Submission` record containing the complete roster of template submitters (`template_submitters: template.submitters`).
3. **Copies defined submitters**: It delegates to `Submissions::AssignDefinedSubmitters` (located in [`lib/submissions/assign_defined_submitters.rb`](https://github.com/docusealco/docuseal/blob/main/lib/submissions/assign_defined_submitters.rb)) to copy any pre-filled submitters—those already possessing emails, roles, or other metadata—into the newly created submission.

This process ensures that while the shared link creates only one submitter record (the one filling out the form), the resulting `Submission` object maintains the complete multi-party chain for subsequent routing and signing.

## UI Safeguards and Optional 2FA

The platform prevents users from creating invalid configurations through the **Share Link settings page**. In `app/views/templates_share_link/show.html.erb` (lines 39‑44), a conditional warning block checks if multiple undefined submitters exist; if so, it disables the shared link checkbox and displays an explanatory message.

For templates with `shared_link_2fa` enabled, the workflow includes an additional verification step. After the submitter record is created but before redirecting to the fill-in form, `handle_require_2fa` (lines 12‑28 in `StartFormController`) validates an OTP code. If the template preferences require 2FA and the submitted `one_time_code` is invalid or missing, the user is prompted for verification before proceeding.

## Practical Implementation Examples

### Creating a Multi-Submitter Template

```ruby

# Rails console: Create a template for three parties

template = Template.create!(
  account: current_account,
  name: "Tripartite Agreement",
  submitter_count: 3,
  only_field_types: %w[text signature]
)

```

Behind the scenes, `submitter_count` generates three empty submitter hashes. When retrieved later, `filter_undefined_submitters` will recognize all three as undefined until emails or roles are assigned.

### Submitting via Public Link

```json
POST /api/v1/submissions
{
  "template_id": "c0a1e2f3-4b5c-6d7e-8f9a-bcdef0123456",
  "submitters": [
    { "email": "alice@example.com", "name": "Alice" }
  ]
}

```

**Server processing:**
- `StartFormController#update` receives the payload
- `filter_undefined_submitters` finds exactly one undefined submitter → passes guard
- `assign_submission_attributes` assigns Alice to that UUID and builds the submission
- `Submissions::AssignDefinedSubmitters` processes any additional pre-filled submitters

If the template had two undefined submitters remaining, the controller would return **422** with the message from `multiple_submitters_error_message` instead of creating the submission.

### Enforcing Two-Factor Authentication

```json
POST /api/v1/submissions
{
  "template_id": "c0a1e2f3-4b5c-6d7e-8f9a-bcdef0123456",
  "submitters": [{ "email": "bob@example.com" }],
  "one_time_code": "123456"
}

```

When `template.preferences['shared_link_2fa']` is true, the controller executes `handle_require_2fa`. The submission proceeds only if the OTP matches the code sent to the submitter's email; otherwise, the response renders the OTP entry view.

## Summary

- **Undefined submitters** lack email, invite metadata, or role links, and are identified by `Templates.filter_undefined_submitters` in [`lib/templates.rb`](https://github.com/docusealco/docuseal/blob/main/lib/templates.rb).
- **Shared link validation** rejects requests when multiple undefined submitters exist to prevent ambiguous assignments, implemented in `StartFormController#update`.
- **Submission construction** uses `assign_submission_attributes` to select a single UUID owner while preserving the full submitter roster in the `Submission` object.
- **Defined submitter propagation** is handled by `Submissions::AssignDefinedSubmitters` to ensure pre-configured parties are included in the workflow.
- **UI safeguards** in `templates_share_link/show.html.erb` prevent enabling public links for invalid template states.
- **Optional 2FA** adds an OTP verification layer via `handle_require_2fa` before finalizing the submission.

## Frequently Asked Questions

### What qualifies as an undefined submitter in Docuseal?

An undefined submitter is any submitter hash that lacks `invite_by_uuid`, `optional_invite_by_uuid`, `invite_via_field_uuid`, `linked_to_uuid`, `is_requester`, and `email` attributes. The `filter_undefined_submitters` method in [`lib/templates.rb`](https://github.com/docusealco/docuseal/blob/main/lib/templates.rb) returns only submitters meeting this criteria, which the platform treats as "empty slots" available for public link assignment.

### Why can't I enable a shared link for my multi-signer template?

The shared link feature requires exactly **one** undefined submitter to ensure unambiguous ownership. If `filter_undefined_submitters` returns more than one entry, `StartFormController#update` would reject submission attempts with a 422 error. The UI reflects this constraint by disabling the shared link checkbox and displaying a warning in `app/views/templates_share_link/show.html.erb` when multiple undefined submitters are detected.

### How does Docuseal handle pre-defined submitters when creating a submission?

When `assign_submission_attributes` creates the submission, it includes all template submitters in the `template_submitters` JSON field. Immediately after, `Submissions::AssignDefinedSubmitters` processes this list and copies any submitters that already contain emails or roles into separate submitter records associated with the new submission, ensuring that pre-configured parties are preserved while the public link user fills the remaining undefined slot.

### What happens if two-factor authentication is enabled on a shared link?

When `template.preferences['shared_link_2fa']` is true, the `handle_require_2fa` method in `StartFormController` intercepts the flow after submitter creation but before form access. The controller verifies the submitted `one_time_code` against the generated OTP; valid codes allow the redirect to the fill-in form, while missing or invalid codes render the OTP entry view, preventing unauthorized document access even with the public URL.