Docuseal API Structure for Creating and Managing Templates and Submissions: Complete REST Reference

Docuseal exposes a JSON-only REST API under the /api namespace that supports full CRUD operations for templates and submissions, secured via Bearer tokens or session cookies with CanCanCan authorization.

Docuseal is an open-source document signing platform hosted at docusealco/docuseal. The API structure for creating and managing templates and submissions follows RESTful conventions, exposing two primary resources—/api/templates and /api/submissions—that accept JSON payloads and return serialized responses via dedicated service objects.

Templates API Endpoints

The templates resource supports document template management, including schema definition, field configuration, and lifecycle operations.

List and Retrieve Operations

  • List templates: GET /api/templates supports pagination, search via the q parameter, and filtering by archived, folder, slug, and external_id. Implementation located at TemplatesController#index.
  • Retrieve single template: GET /api/templates/:id returns the template serialized by Templates::SerializeForApi.call. See TemplatesController#show.

Update and Delete Operations

  • Update template: PATCH /api/templates/:id accepts name, fields, submitters, folder assignment, and archived status. Strong parameters are defined in TemplatesController#update.
  • Delete template: DELETE /api/templates/:id performs a soft-delete (archive) by default. Append ?permanently=true to purge the record completely. See TemplatesController#destroy.

Clone and Nested Submissions

  • Clone template: POST /api/templates/:id/clone creates a duplicate schema via TemplatesCloneController#create.
  • Template submissions: GET /api/templates/:id/submissions lists all submissions for a specific template, while POST /api/templates/:id/submissions creates a new submission scoped to that template. These routes delegate to SubmissionsController.

Template Request Payload

Templates are accepted as a strong-parameter hash defined in template_params:


# app/controllers/api/templates_controller.rb (excerpt)

permitted_params = [
  :name,
  :external_id,
  :shared_link,
  {
    submitters: [%i[
      name uuid is_requester invite_by_uuid invite_via_field_uuid
      optional_invite_by_uuid linked_to_uuid email order
    ]],
    fields: [[:uuid, :submitter_uuid, :name, :type,
              :required, :readonly, :default_value,
              :title, :description, :prefillable,
              { preferences: {}, default_value: [], conditions: [%i[field_uuid value action operation]],
                options: [%i[value uuid]],
                validation: %i[message pattern min max step],
                areas: [%i[uuid x y w h cell_w attachment_uuid option_uuid page]] }]]
  }
]

Typical JSON body for template creation:

{
  "template": {
    "name": "Employment Contract",
    "external_id": "emp-contract-v1",
    "fields": [
      {
        "uuid": "f1",
        "name": "Employee Name",
        "type": "text",
        "required": true
      },
      {
        "uuid": "f2",
        "name": "Start Date",
        "type": "date",
        "required": true
      }
    ],
    "submitters": [
      { "name": "Employee", "uuid": "s1", "email": "employee@example.com" },
      { "name": "HR Manager", "uuid": "s2", "email": "hr@example.com" }
    ]
  }
}

Template Response Structure

Templates::SerializeForApi.call (located in [lib/templates/serialize_for_api.rb](https://github.com/docusealco/docuseal/blob/master/lib/templates/serialize_for_api.rb)) returns:

  • id, name, slug, fields, submitters, schema, author
  • documents array containing id, uuid, url, preview_image_url, filename
  • folder_name, application_key, expires_at

Submissions API Endpoints

The submissions resource handles document signing workflows, submitter invitations, and completion tracking.

List and Retrieve Operations

  • List submissions: GET /api/submissions supports filtering by template_id, slug, archived, and template_folder. Implementation at SubmissionsController#index.
  • Retrieve submission: GET /api/submissions/:id returns submitters, documents, audit trail, and status via SubmissionsController#show.

Create and Destroy Operations

  • Create submission: POST /api/submissions is the primary endpoint for initiating signing workflows. Parameters are validated by Params::SubmissionCreateValidator and normalized via Submissions::NormalizeParamUtils. See SubmissionsController#create.
  • Delete submission: DELETE /api/submissions/:id archives the record; use ?permanently=true for hard deletion. See SubmissionsController#destroy.

Collection Routes for Bulk Operations

The API provides specialized collection endpoints defined in [config/routes.rb](https://github.com/docusealco/docuseal/blob/master/config/routes.rb):

  • POST /api/submissions/init: Creates a submission without initial file uploads, useful for headless integrations.
  • POST /api/submissions/emails: Bulk creates submissions from a list of email addresses.

Both routes utilize the same create action logic but handle different payload structures.

Submission Request Payload

The controller permits the following nested attributes via submissions_params:


# app/controllers/api/submissions_controller.rb (excerpt)

permitted_attrs = [
  :send_email, :send_sms, :bcc_completed, :completed_redirect_url, :reply_to, :go_to_last,
  :require_phone_2fa, :require_email_2fa, :expire_at, :name,
  {
    variables: {},
    message: %i[subject body],
    submitters: [[:send_email, :send_sms, :completed_redirect_url, :uuid, :name, :email,
                  :role, :completed, :phone, :application_key, :external_id,
                  :reply_to, :go_to_last, :require_phone_2fa, :require_email_2fa,
                  :order, :index, :invite_by,
                  { metadata: {}, values: {}, roles: [], readonly_fields: [], message: %i[subject body],
                    fields: [:name, :uuid, :default_value, :value, :title, :description,
                             :readonly, :required, :validation_pattern, :invalid_message,
                             { default_value: [], value: [], preferences: {}, validation: {} }] }]]
  }
]

Example payload creating a submission from template ID 42:

{
  "template_id": 42,
  "send_email": true,
  "expire_at": "2026-06-01T00:00:00Z",
  "submitters": [
    {
      "email": "employee@example.com",
      "name": "John Doe",
      "role": "Employee",
      "fields": [
        { "uuid": "f1", "value": "John Doe" },
        { "uuid": "f2", "value": "2023-05-01" }
      ]
    },
    {
      "email": "hr@example.com",
      "name": "HR Manager",
      "role": "Manager"
    }
  ],
  "variables": { "company": "Acme Corp" },
  "message": {
    "subject": "Please sign the employment contract",
    "body": "Hello, please review and sign the attached document."
  }
}

Submission Response Structure

Submissions::SerializeForApi.call (located in [lib/submissions/serialize_for_api.rb](https://github.com/docusealco/docuseal/blob/master/lib/submissions/serialize_for_api.rb)) returns:

  • id, name, slug, expire_at, created_at, updated_at, archived_at
  • template (including id, name, external_id, folder_name)
  • submitters array with id, email, documents, and status
  • variables, documents (populated after completion), audit_log_url, combined_document_url
  • status enum: pending, completed, declined, or expired

Authentication and Security

Both API resources are protected by CanCanCan authorization via load_and_authorize_resource. Requests require either:

  • A valid Bearer token in the Authorization header
  • An authenticated session cookie from a Docuseal user

Unauthorized requests return standard HTTP 401/403 responses.

Practical Code Examples

Create a Template

curl -X POST "https://your-docuseal-instance.com/api/templates" \
     -H "Authorization: Bearer <ACCESS_TOKEN>" \
     -H "Content-Type: application/json" \
     -d '{
        "template": {
          "name": "NDA",
          "external_id": "nda-2024",
          "fields": [
            {"uuid":"f1","name":"Company Name","type":"text","required":true},
            {"uuid":"f2","name":"Effective Date","type":"date","required":true}
          ],
          "submitters": [
            {"name":"Counterparty","uuid":"s1","email":"partner@example.com"},
            {"name":"Signer","uuid":"s2","email":"signer@example.com"}
          ]
        }
      }'

Response includes the template id, slug, and empty documents array (populated after PDF upload).

Create a Submission

curl -X POST "https://your-docuseal-instance.com/api/submissions" \
     -H "Authorization: Bearer <TOKEN>" \
     -H "Content-Type: application/json" \
     -d '{
        "template_id": 123,
        "expire_at": "2026-06-30T00:00:00Z",
        "submitters": [
          {
            "email":"john.doe@example.com",
            "name":"John Doe",
            "role":"Employee",
            "fields":[
              {"uuid":"f1","value":"Acme Corp"},
              {"uuid":"f2","value":"2023-05-01"}
            ]
          },
          {
            "email":"hr@example.com",
            "name":"HR Manager",
            "role":"Manager"
          }
        ],
        "message": {"subject":"Please sign", "body":"Kindly sign the attached NDA."}
      }'

Success returns submitter signing URLs:

{
  "submitters": [
    {
      "id": 321,
      "url": "https://your-docuseal-instance.com/s/321?token=abc123"
    },
    {
      "id": 322,
      "url": "https://your-docuseal-instance.com/s/322?token=def456"
    }
  ],
  "expire_at": "2026-06-30T00:00:00Z",
  "created_at": "2026-05-05T12:34:56Z"
}

Retrieve Completed Submission

curl -X GET "https://your-docuseal-instance.com/api/submissions/789" \
     -H "Authorization: Bearer <TOKEN>"

Returns status: "completed", documents array with download URLs, audit_log_url, and combined_document_url.

Summary

  • The Docuseal API structure consists of two primary REST resources: /api/templates and /api/submissions, both requiring Bearer token or session authentication.
  • Templates support CRUD operations plus cloning (POST /api/templates/:id/clone) and nested submission listing, with payloads validated via template_params and serialized via Templates::CreateOrUpdate and SerializeForApi.
  • Submissions support creation with complex submitter configurations, bulk email endpoints (/api/submissions/emails), and headless initialization (/api/submissions/init), using Submissions::NormalizeParamUtils for payload processing.
  • Both resources implement soft-delete by default (use ?permanently=true for hard deletion) and return JSON structured by dedicated serialization classes in lib/templates/serialize_for_api.rb and lib/submissions/serialize_for_api.rb.

Frequently Asked Questions

What authentication method does the Docuseal API use?

The API uses Bearer token authentication via the Authorization header or session cookies from authenticated Docuseal users. All endpoints invoke load_and_authorize_resource from CanCanCan to enforce resource-level permissions.

How do I permanently delete a template or submission via the API?

By default, DELETE /api/templates/:id and DELETE /api/submissions/:id perform soft-deletion (archiving). Append ?permanently=true to the query string to trigger hard deletion, which removes the record from the database entirely.

What is the difference between POST /api/submissions and POST /api/submissions/init?

POST /api/submissions accepts full template and submitter data including initial file uploads. POST /api/submissions/init is a collection route shortcut that creates a submission without requiring file attachments, designed for headless integrations where documents are uploaded later.

How are webhook events triggered in the Docuseal API?

Webhook events (such as template.created, template.updated, submission.created) are enqueued via WebhookUrls.enqueue_events calls within the controller actions. These background jobs dispatch payloads to configured webhook URLs asynchronously after database transactions commit.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →