---
updatedAt: 2026-08-04T19:19:00.000Z
---

Fetch the complete documentation index at: https://developer.ironcladapp.com/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Launch a Workflow

This is a simple example outlining how to launch a workflow using our REST API.

# Goal

Technical audiences will learn how to use Ironclad's API to launch workflows. Ironclad administrators and business counterparts can also benefit from this guide by learning how workflow design decisions impact API design and complexity.

## Overview

This guide will cover the steps for constructing a valid request for launching workflows along with tips and limitations to be aware of. The [Create a Workflow Synchronously](https://developer.ironcladapp.com/reference/launch-a-new-workflow) endpoint will be used.

## Prerequisites

1. **OAuth Client App:** An OAuth client app that has been granted the appropriate scopes. Learn more about creating an OAuth 2.0 client application, generating a token, and expected request structure in the [Authentication](https://developer.ironcladapp.com/reference/authentication-api) article.
2. **Published workflow design and Workflow Designer access:** See your internal company admin for access to Workflow Designer.
3. **Beginner understanding of Workflow Designer:** For a refresher, please see [Ironclad Academy](https://academy.ironcladapp.com/learn/scorm-view/582dd51c-3a5b-4a20-aa66-ee020b0a362e?isPreview=false\&learningPathSlug=) and Ironclad's [Help Center](https://support.ironcladapp.com/hc/en-us/articles/12271117797527-How-to-Build-a-Workflow-Using-Workflow-Designer).

> 👍 Tip: End-to-End Testing
>
> Test your API requests in [sandbox mode](https://support.ironcladapp.com/hc/en-us/articles/12269963678487-Use-Sandbox-Mode) or in your separate sandbox instance (if you have purchased one) before running them in a live production environment. Testing should include launching the workflow *and* running them end-to-end to completion (e.g., dispatching signature requests and archiving).

<b>Note: This guide and any software contained in it should be used at your own risk by individuals qualified to evaluate its effectiveness. IT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL IRONCLAD BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH YOUR USE OF THIS GUIDE OR ANY SOFTWARE IT CONTAINS.</b>

<b>Your use of the Ironclad API must comply with Ironclad’s API Terms of Use (available at <https://legal.ironcladapp.com/api-terms-of-use>     ) and the terms of the Enterprise Services Agreement (or equivalent) entered into between you and Ironclad.</b>

# Details

Each workflow launch request has 2 required parameters in the request body: (1) template ID and (2) attributes. The remainder of this guide will cover how to discover and construct these parameters.

Copy the template below into your preferred editor and populate it as you walk through the steps in this guide.

```json
{
  "template": "[WORKFLOW_TEMPLATE_ID]",
  "attributes": {
    "[FIELD_ID_1]": "[FIELD_VALUE_1]",
    "[FIELD_ID_2]": "[FIELD_VALUE_2]",
    "[FIELD_ID_3]": "[FIELD_VALUE_3]",
  }
}
```

**Note:** Your data will be transmitted to Ironclad in the request body. The request body will be either (1) a raw JSON with the format above or (2) a [multipart/form-data](https://developer.mozilla.org/en-US/docs/Web/API/FormData) request if you plan to include binary files directly in the body. The JSON payload (`template` and `attributes`) will be substantially the same in both scenarios, but it will be included as one request body part in the `multipart/form-data` scenario.

## 1. Request Body - Template ID

The `template` parameter identifies which workflow design to launch. Workflow designs receive a template ID when they are published.

1. In Workflow Designer, publish the workflow you wish to launch if it has not been published already.
2. See [Getting Started](https://developer.ironcladapp.com/reference/getting-started-api) for an overview of retrieving template IDs in Ironclad. Copy it into your request body as the value for the `template` parameter.

**Note:** If you are testing in a production Ironclad environment instead of a development environment, we recommend using [sandbox mode](https://support.ironcladapp.com/hc/en-us/articles/12269963678487-Use-Sandbox-Mode#publishaworkflowinsandboxmode). Sandbox mode isolates your tests to that environment and avoids creating properties in your full production environment until you are ready to publish your final workflow design.

## 2. Request Body - Creator (Legacy)

The `creator` parameter identifies which Ironclad user account is treated as the user that started the workflow. The `creator` takes on the Workflow Owner role in Ironclad.

**Note:** The `creator` parameter has been superseded by the `x-as-user-email` and `x-as-user-id` request *headers*; it is no longer required if `x-as-user-email` or `x-as-user-id` is sent (see [Section 4](#4-request-headers) for full details).

There are two options for specifying a creator: email or user ID. User email is recommended for simplicity. User ID, a unique ID generated by Ironclad for each user, may be used if you have retrieved it using the [List all Users](https://developer.ironcladapp.com/reference/retrieve-all-users) endpoint. This approach is beyond the scope of this article.

1. In Ironclad, identify a user you wish to launch the workflow on behalf of.
2. In Ironclad, verify that the user is in a group with permission to start the workflow. If they are not, [add them to a group](https://support.ironcladapp.com/hc/en-us/articles/12286570480791-Manage-Groups) and ensure the group includes the Start Workflow permission for the workflow you are trying to launch.
3. In your request body, update the email attribute in the creator object with the user's email address.

> 📘 Permissions
>
> The creator must have the [Start Workflow permission](https://support.ironcladapp.com/hc/en-us/articles/12286499429527-Group-Permissions-Overview) in order for API requests on their behalf to succeed.

**Creator Example (Email)**

```json
{
  "template": "[WORKFLOW_TEMPLATE_ID]",
  "creator": {
    "type": "email",
    "email": "example@example.com"
  },
  "attributes": {
    "[FIELD_ID_1]": "[FIELD_VALUE_1]",
    "[FIELD_ID_2]": "[FIELD_VALUE_2]",
    "[FIELD_ID_3]": "[FIELD_VALUE_3]",
  }
}
```

**Creator Example (User ID)**

```json
{
  "template": "[WORKFLOW_TEMPLATE_ID]",
  "creator": {
      "type": "id",
      "id": "abcdef12345678910"
  },
  "attributes": {
    "[FIELD_ID_1]": "[FIELD_VALUE_1]",
    "[FIELD_ID_2]": "[FIELD_VALUE_2]",
    "[FIELD_ID_3]": "[FIELD_VALUE_3]",
  }
}
```

## 3. Request Body - Attributes

The `attributes` parameter specifies the values you want to pass into your workflow's fields. Constructing the `attributes` parameter involves two steps: (1) inventorying the fields that can/must be populated and (2) creating the request body.

### 3.1. Retrieve the Workflow's Launch Form Schema

Each workflow design has a "launch form" schema that describes the field ID, type, and display name of fields you can pass data into.

Retrieve this schema by sending a GET request to the [Retrieve a Workflow Schema](https://developer.ironcladapp.com/reference/retrieve-a-workflow-schema) endpoint using (1) the workflow design's template ID from [Section 1](#1-request-body---template-id) and (2) the `?form=launch` URL query parameter.

If the API request is successful, you should receive a response body that conforms to the following format:

```json
{
  "id": "[TEMPLATE_ID]",
  "name": "[NAME_OF_WORKFLOW_DESIGN]",
  "schema": {
    "[FIELD_ID_1]": {
      "type": "[FIELD_TYPE]", // string, number, boolean, date, duration, monetaryAmount, email, address, array, or referenceType
      "displayName": "[FIELD_DISPLAY_NAME]"
    },
    "[FIELD_ID_2]": {
      "type": "[FIELD_TYPE]",
      "displayName": "[FIELD_DISPLAY_NAME]"
    },
    "[FIELD_ID_3]": {
      "type": "[FIELD_TYPE]",
      "displayName": "[FIELD_DISPLAY_NAME]"
    }
  }
}
```

The `schema` property holds objects that describe each field. The objects describing each field will have the following properties:

* **Field API Name**: The unique ID automatically generated by Ironclad to identify each field. You will use this property when creating the payload to specify which field you are passing data into. An object is nested within this property and contains the following properties:
  * **Field Type**: The type of data the field can be populated with. Field types can be changed in Workflow Designer.
  * **Field Display Name**: The question customized by workflow designers when building workflows and seen by end users when submitting the Launch Form. Field display names can be changed in Workflow Designer.

The following example illustrates data types corresponding to different fields created in an Ironclad launch form. For an overview of fields that can be used in Workflow Designer, please see the [following article](https://support.ironcladapp.com/hc/en-us/articles/12250969976599-Types-of-Form-Fields-in-Workflow-Designer) or open your design in Workflow Designer.

**Schema Object Model (Example)**

```json
{
  "id": "60f83d3ecdd9d05a78472166",
  "name": "My Workflow Design Name",
  "schema": {
    "counterpartyName": {
      "type": "string",
      "displayName": "Counterparty Name"
    },
    "role4e49a9bbd20c4101b1e475294e534076": {
      "type": "email",
      "displayName": "Counterparty Signer Email"
    },
    "entity_reference": {
      "type": "referenceType",
      "displayName": "Entity"
    },
    "localAnotherEntity": {
      "type": "referenceType",
      "displayName": "Vendor Entity"
    },
    "rolec326ea18494d41b9af47303412e30c0b": {
      "type": "string",
      "displayName": "Counterparty Signer Name"
    },
    "someTextField": {
      "type": "string",
      "displayName": "Some Text Field"
    },
    "someDropdownField": {
      "type": "string",
      "displayName": "Some Dropdown Field"
    },
    "someSingleSelectMultipleChoiceField": {
      "type": "string",
      "displayName": "Some Single-Select Multiple Choice Field"
    },
    "someMultiSelectMultipleChoiceField": {
      "type": "array",
      "displayName": "Some Multi-Select Multiple Choice Field",
      "elementType": {
        "type": "string"
      }
    },
    "someNumberField": {
      "type": "number",
      "displayName": "Some Number Field"
    },
    "someBooleanField": {
      "type": "boolean",
      "displayName": "Some Boolean Field (Yes/No)"
    },
    "someDateField": {
      "type": "date",
      "displayName": "Some Date Field"
    },
    "someMonetaryField": {
      "type": "monetaryAmount",
      "displayName": "Some Monetary Field"
    },
    "someAddressField": {
      "type": "address",
      "displayName": "Some Address Field"
    },
    "someDurationField": {
      "type": "duration",
      "displayName": "Some Duration Field"
    },
    "someTable": {
      "type": "array",
      "displayName": "Some Table",
      "elementType": {
        "type": "object",
        "schema": {
          "someTextFieldInTable": {
            "type": "string",
            "displayName": "Some Text Field In Table"
          },
          "someNumberFieldInTable": {
            "type": "number",
            "displayName": "Some Number Field In Table"
          },
          "someMultiSelectFieldInTable": {
            "type": "array",
            "displayName": "Some Multi-Select Field In Table",
            "elementType": {
              "type": "string"
            }
          }
        }
      }
    },
    "someAdditionalFileUploadField": {
      "type": "array",
      "displayName": "Some Additional File Upload Field",
      "elementType": {
        "type": "document"
      }
    }
  }
}
```

### 3.2. Create Request Body (Attributes)

Construct your `attributes` parameter using the field IDs from [Section 3.1](#31-retrieve-the-workflows-launch-form-schema) above. Each field has a data type that dictates how values must be formatted. See the following table to learn how to format values for different types.

> 👍 Tip: Constructing Request Bodies
>
> A shortcut for creating a sample request body is to manually launch a workflow with test values in Ironclad. After the workflow launches, send a request to the [Retrieve a Workflow](https://developer.ironcladapp.com/reference/retrieve-a-workflow) endpoint to get the field IDs and properly formatted values under the `attributes` property.

> 📘 Supported Field Types
>
> Population of formula fields is not currently supported via API. Consider passing data into string fields or moving fields to an [Internal Form](https://support.ironcladapp.com/hc/en-us/articles/12250887031191-Form-Types-in-Workflow-Designer) for users to fill in after a workflow is launched.

<Table align={["left","left"]}>
  <thead>
    <tr>
      <th>
        Field Type
      </th>

      <th>
        Sample Value
      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        String <br /><br /> **Note:** Strings have a **32,000 character limit**. Workflows will error at the archive step if it is exceeded.
      </td>

      <td>
        "counterpartyName": "Acme LLC"
      </td>
    </tr>

    <tr>
      <td>
        Address <br /><br /> **Note:** Addresses are validated. <ul><li>Non-US addresses require (1) street (`lines`), (2) locality, and (3) country.</li><li>US addresses require (1) street (`lines`), (2) locality, (3) region, (4) postcode, and (5) country. US address validation is enforced if `U.S.A.`, `USA`, `United States`, or `United States of America` are used as the country.</li><li>The `lines` array is limited to four street lines.</li></ul>
      </td>

      <td>
        "counterpartyAddress": \{<br />    "lines": [ <br />      "325 5th Street",<br />        "Suite 200"<br />    ],<br />    "locality": "San Francisco", <br />    "region": "California",<br />    "postcode": "94107",<br />    "country": "USA"<br /> }
      </td>
    </tr>

    <tr>
      <td>
        Number
      </td>

      <td>
        "standard_timesRenewed": 12
      </td>
    </tr>

    <tr>
      <td>
        Monetary Value
      </td>

      <td>
        "totalContractValue": \{<br />    "currency": "USD",<br />    "amount": 25.37<br />}
      </td>
    </tr>

    <tr>
      <td>
        Date
      </td>

      <td>
        Date fields accept multiple formats: <br /> "agreementDate": "2021-05-11T17:16:53-07:00"  
            **OR** <br /> "agreementDate": "2021-05-11"  
            **OR** <br /> "agreementDate": "2021-05-11T17:16:53Z"
      </td>
    </tr>

    <tr>
      <td>
        Duration <br />The duration value must include _one or more_ units of time (`years`, `months`, `weeks`, or `days`).
      </td>

      <td>
        "initialTermLength": \{<br />    "years": 1,<br />    "months": 2,<br />    "weeks": 3,<br />    "days": 4<br />}
      </td>
    </tr>

    <tr>
      <td>
        Email
      </td>

      <td>
        "counterpartySignerEmail": "`test@gmail.com`"
      </td>
    </tr>

    <tr>
      <td>
        Boolean <br /><br /> **Note:** The [Yes/No field](https://support.ironcladapp.com/hc/en-us/articles/12250969976599-Types-of-Form-Fields-in-Workflow-Designer) field in Workflow Designer is a boolean.
      </td>

      <td>
        "contractExtending": true
      </td>
    </tr>

    <tr>
      <td>
        Single-Select (Same as String)
      </td>

      <td>
        "protectionPeriod": "Option A"
      </td>
    </tr>

    <tr>
      <td>
        Multi-Select
      </td>

      <td>
        "someMultiSelectField": [

          "Option A",<br />   "Option B"<br />]
      </td>
    </tr>

    <tr>
      <td>
        Table
      </td>

      <td>
        "someTable": [<br />    \{ <br />        "someTextFieldInTable": "Some Row 1 Text",<br />        "someNumberFieldInTable": 25, <br />        "someMultiSelectFieldInTable":  ["Option A", "Option B"] <br />     }, <br />    \{<br />        "someTextFieldInTable": "Some Row 2 Text",<br />        "someNumberFieldInTable": 27,<br />        "someMultiSelectFieldInTable":  ["Option B", "Option C"]<br />     }<br />] <br />
      </td>
    </tr>

    <tr>
      <td>
        File<br /><br /> **Note:** See [Section 3.5](#35-files-overview) for full details on usage and requirements. Files can either be sent as (1) binaries directly in a `multipart/form-data` request or (2) publicly accessible URLs in a regular raw JSON request body. The two methods cannot be combined.
      </td>

      <td>
        **Option 1: Multipart/Form-Data Request**<br />The value of the `file` property below is the request _body part_ name that you plan to include the file's binary under. See [Section 3.5.1](#351-multipartform-data-requests-binaries)  for more details.<br />`"draft": [ { "file": "someFirstFile" },`<br />      `{ "file": "someSecondFile" } ]`<br /> <br /> <br />**Option 2: Publicly Accessible URLs**<br />// The urls below are stubs. Please replace them with urls that point to your own files.<br /><br /> `"draft": [`<br />  `  {"url": "https://your.file.server/testdoc-1.docx"},` <br /> `  {"url": "https://your.file.server/testdoc-2.docx" }`<br />`]`
      </td>
    </tr>

    <tr>
      <td>
        User Role
      </td>

      <td>
        "approver3be1d629ad524bb2aade2078cd06e94": "682b83ea0303cccab88b4ce"

        **OR**

        "approver3be1d629ad524bb2aade2078cd06e94": "`user@example.com`"
      </td>
    </tr>

    <tr>
      <td>
        Related Record
      </td>

      <td>
        The value of a Related Record field should be either the readable ID (e.g. "IC-456") or the UUID of the record to set:

        "customRelatedRecordKey": "67818c492207a528ce9665ad"

        **OR**

        "customRelatedRecordKey": "IC-68"
      </td>
    </tr>

    <tr>
      <td>
        Entity <br /><br /> **Note:** A workflow can have multiple entity fields. Set each one by its real attribute ID from the launch form schema — see [Entity References in Workflows and Records](https://developer.ironcladapp.com/reference/entity-references-in-workflows-records) for details, including the `entity_reference` alias behavior for the first entity slot. The value must be a **string** — the entity's readable ID (e.g., `"ENTITY-1"`) or its record UUID. Passing a non-string value returns a 400 BadRequest with error code `INVALID_PARAM`.
      </td>

      <td>
        "entity_reference": "ENTITY-1"

        **OR**

        "entity_reference": "0f1a6991-5e34-4945-89aa-eadc54eed62c"
      </td>
    </tr>
  </tbody>
</Table>

### 3.3 Required Fields

The attributes parameter must include values for all required launch form fields and conditionally required fields. These settings can be checked in Workflow Designer.

* In Ironclad, open the workflow's design in Workflow Designer.
* Navigate to the launch form under the Create tab to identify required and conditionally required fields.

**Note:** Launch form fields with [default values](https://support.ironcladapp.com/hc/en-us/articles/12403007165847-Customize-Form-Fields-in-Workflow-Designer#setadefaultvalueforaformfieldtype) can be omitted from `attributes` if you wish to use the default value.

> 🚧 Required Fields
>
> Requests will fail if the attributes object has missing or incorrectly formatted data for required fields.
>
> * Workflows launched via API have their launch forms automatically "submitted" so users are not prompted to fill it out.
> * If your process includes data that can only be filled in by the business user, consider (1) using [Internal Forms](https://support.ironcladapp.com/hc/en-us/articles/12250887031191-Form-Types-in-Workflow-Designer) which are sent after the workflow is launched to collect information or (2) making the launch form fields optional if they do not need to be filled in.

### 3.4 Optional Fields (Blank Values)

Launch form fields that are optional and non-triggered conditional fields can be left blank. **Exclude** the field from your attributes object if you do not wish to provide a value.

> 🚧 Blank Values
>
> Do **not** send blank strings, null, or other representations of blank values as it may trigger form validation (e.g., sending a blank value to an address field which enforces address formatting).

### 3.5 Files (Overview)

Files can be included when launching workflows by (1) including them as binaries in a `multipart/form-data` request or (2) specifying a publicly accessible URL where they are hosted. The two methods cannot be combined.

Workflow designs can have (1) one or more file upload fields and (2) one or more files can be sent to each file upload field. File extension support depends on whether the field is used in the signature packet (see [Section 3.5.3](#353-supported-file-extensions)).

#### 3.5.1 Multipart/Form-Data Requests (Binaries)

A `multipart/form-data` request body must be used instead of a JSON request body if you intend to send binary files directly within the request.

**Request Header:** Ensure your request uses a `Content-Type` header with `multipart/form-data` as its value.

**Request Body:** Two key request body parts will be included. You may have additional parts if you are sending multiple binary files.

1. A part named `data` will hold the JSON request body payload you assembled in the previous steps (`template` and `attributes`) as plain text.
2. Separate part(s) for each binary file will be added. Each binary will be included under a part with its own unique part **name**. Each part name will be identified in the previous `data` JSON payload when specifying which files to attach to which file upload field.

For step 1, take the JSON you have assembled from the previous steps. Modify `attributes` to identify the files that will be attached to each file upload field.

* For the attribute key, use your file upload field's attribute name.
* For the attribute value, add an array and include as many `{"file": "[YOUR_UNIQUE_FILE_PART_NAME]"}` elements as needed to identify each file.

For example, if you have three files and want to upload two of them to the `draft` property as contracts for review and upload one of them to a custom file upload field as supporting documentation, you can create a JSON like the below.

Once you have assembled the JSON, append it as the value of the `data` part.

```json
{
  "template": "[WORKFLOW_TEMPLATE_ID]",
  "attributes": {
    "[FIELD_ID_1]": "[FIELD_VALUE_1]",
    "[FIELD_ID_2]": "[FIELD_VALUE_2]",
    "draft": [
      {"file": "someFirstFile"},
      {"file": "someSecondFile"}
    ],
    "someAdditionalFileUploadField": [
      {"file": "someThirdFile"}
    ]
  }
}
```

For step 2, append each binary file using `[YOUR_UNIQUE_FILE_PART_NAME]` as the part name. The value of `[YOUR_UNIQUE_FILE_PART_NAME]` should be different for each part (e.g., `someFirstFile`, `someSecondFile`, `someThirdFile`).

The request you construct from the above will result in a raw HTTP representation similar to the example below.

<details>
  <summary>Multipart/Form-Data HTTP Request Example</summary>

This example request includes two files under the `draft` file upload field.

```http

POST /public/api/v1/workflows HTTP/1.1
Host: demo.ironcladapp.com
x-as-user-email: [SOME_AUTHORIZED_USER@YOUR_COMPANY.COM]
Authorization: Bearer [API_TOKEN]
Content-Length: 740
Content-Type: multipart/form-data; boundary=----[BOUNDARY_VALUE]

------[BOUNDARY_VALUE]
Content-Disposition: form-data; name="data"

{
    "template": "623ccb751d749b1eef29a4c0",
    "attributes": {
        "counterpartyName": "Test",
        "draft": [
          {"file": "someFirstFile"}, {"file": "someSecondFile"}
        ],
        "someAdditionalFileUploadField": [
          {"file": "someThirdFile"}
        ]
    }
}
------[BOUNDARY_VALUE]
Content-Disposition: form-data; name="someFirstFile"; filename="MSA - Counterparty LLC.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document

(binary data)
------[BOUNDARY_VALUE]
Content-Disposition: form-data; name="someSecondFile"; filename="Order Form - Counterparty LLC.docx"
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document

(binary data)
------[BOUNDARY_VALUE]
Content-Disposition: form-data; name="someThirdFile"; filename="Certification.png"
Content-Type: image/png

(binary data)
------[BOUNDARY_VALUE]

```

</details>

Different applications and languages have their own methods for assembling multipart/form-data requests. Please reference your system's documentation for those details.

#### 3.5.2 Files from Public URLs

Ironclad can add files to a workflow by *pulling* files directly from a public URL that links directly to the file. See [Section 3.2](#32-create-request-body-attributes) for an example of the JSON.

**Note**

1. URLs must be publicly accessible online. You may choose to host your files with a [signed URL](https://cloud.google.com/storage/docs/access-control/signed-urls) for obfuscation.
2. URLs must end with the file extension (e.g., `.docx`). File providers such as Google Drive may generate a link that does not link to the file itself but rather a page with the file embedded, which will not work.
3. Ironclad only accepts urls that use the HTTP protocol. Every file url must start with http\:// or https\://.

#### 3.5.3 Supported File Extensions

The supported file extensions depend on how the file upload field is used. For example, the out-of-the-box file upload field for counterparty paper workflows expects a Word/PDF document because negotiating a contract as an image is not supported.

> 🚧 Counterparty paper workflows
>
> Workflows ingesting counterparty paper **must** use `.doc`, `.docx`, and `.pdf` for the system-default file upload field that intakes counterparty paper (`draft` attribute). **Workflows will fail** at the Sign step if other file formats are submitted for the draft attribute.

<Table align={["left","left"]}>
  <thead>
    <tr>
      <th>

      </th>

      <th>

      </th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <td>
        Usage
      </td>

      <td>
        Supported File Types
      </td>
    </tr>

    <tr>
      <td>
        Included in signature packet:

        * [Counterparty paper workflow](https://support.ironcladapp.com/hc/en-us/articles/12270323088791-Paper-Source-Overview) file upload field (`draft` attribute)
        * Custom file upload fields configured for [inclusion in signature packets](https://support.ironcladapp.com/hc/en-us/articles/12250969976599-Types-of-Form-Fields-in-Workflow-Designer)
      </td>

      <td>
        `.doc`, `.docx`, `.pdf`
      </td>
    </tr>

    <tr>
      <td>
        Not included in signature packet.

        * Launch forms can be customized to include file upload fields where the uploaded documents are not included in the signature packet.
      </td>

      <td>
        `.doc`, `.docx`, `.pdf`, `.jpeg`, `.jpg`, `.png`, `.gif`, `.xls`, `.xlsx`, `.csv`, `.ppt`, `.pptx`
      </td>
    </tr>
  </tbody>
</Table>

## 4. Request Headers

Add the following headers to your request:

1. An `Authorization` header: `Authorization: Bearer [YOUR_API_TOKEN]`
2. A `x-as-user-email` header: Add an `x-as-user-email` header. For its value, use the email address of the user you wish to designate as the workflow creator. The `x-as-user-id` header is available if you prefer to identify the user by their Ironclad user ID, but email address tends to be simpler (see [SCIM endpoints](https://developer.ironcladapp.com/reference/retrieve-all-users) for retrieving user IDs). If you have included the legacy `creator` parameter in your request body, this header value will take precedence.
3. A `Content-Type` header: Use `Content-Type: application/json` if you are not passing in binary files. Use `Content-Type: multipart/form-data` if you are following the instructions in [Section 3.5.1](#351-multipartform-data-requests-binaries) to pass in binary files.

## 5. Launch the Workflow

You are now ready to launch the workflow. The [Create a Workflow Synchronously](https://developer.ironcladapp.com/reference/launch-a-new-workflow) endpoint will be used to launch the workflow.

Prepare a request with the following information:

1. **URL:** `https://{{baseUrl}}/public/api/v1/w/public/api/v1/workflows`. Replace ***baseUrl*** with the Ironclad subdomain where you are launching the workflow (e.g., `preview.ironcladapp.com`, `demo.ironcladapp.com`, `ironcladapp.com`, etc.).
2. **Method:** POST
3. **Headers:** Compile the headers discussed in [Section 4](#4-request-headers).
4. **Request Body:** Compile the properties from Sections 1-3 into a single JSON object; include it as the request body.
5. Send the request.

If the request is successful, you will receive a response with the launched workflow's information and workflow ID.

### Launch Workflow Endpoint Variations

Ironclad has two variations of the launch endpoint that you may choose from depending on your use case:

1. A [synchronous](https://developer.ironcladapp.com/reference/launch-a-new-workflow) endpoint (used above) that launches the workflow and waits to respond with whether the workflow has successfully launched or encountered errors.
2. An [asynchronous](https://developer.ironcladapp.com/reference/create-a-new-workflow-async) launch endpoint which has an accompanying [asynchronous job status](https://developer.ironcladapp.com/reference/retrieve-asynchronous-workflow-status) endpoint for checking on the status of the workflow launch job.
   1. The asynchronous variation creates a job to launch the workflow and responds with the job ID.
   2. The job ID is used to query the [asynchronous job status](https://developer.ironcladapp.com/reference/retrieve-asynchronous-workflow-status) endpoint for whether the workflow has successfully launched or encountered errors.

**Considerations**: Ironclad's server has an approximately 60 second timeout on requests. The synchronous endpoint may time out if the workflow takes a significant amount of time to launch. Timeout errors do not reflect whether the workflow has successfully launched; the workflow may have still successfully launched after the timeout.

* Consider using the synchronous version for quick testing and normal workflows.
* Consider using the asynchronous version if you encounter timeouts from complex workflows. A rule of thumb for complex workflows are workflows that (1) involve passing in files from public URLs or (2) workflows that involve a long launch time when manually submitted in Ironclad due to the number of fields, templates, or conditions built into it.

## 6. Troubleshooting

1. **Invalid attributes:** Requests with invalid attributes will receive a 400 error response with a `redirectUrl`. You can open the `redirectUrl` in your browser to populate a launch form; this approach allows you to visually identify fields that were not successfully transferred and validation errors.

**Example Error Response**

```json
{

  "code": "INVALID_PARAM",
  "message": "invalid attributes",
  "param": "attributes.{customec9e0dd8bd0f464bb30912e868b88653}",
  "redirectUrl": "[REDIRECT_URL]",
  "metadata": {
    "invalidAttributes": {
      "customec9e0dd8bd0f464bb30912e868b88653": {
        "invalidValue": [
          {"url": "https://example.com/my_file_with_the_same_name.pdf"},
          {"url": "https://example.com/my_file_with_the_same_name.pdf"}
        ],
        "reasons": ["Cannot upload multiple files with the same name (\"my_file_with_the_same_name.pdf\")."
        ]
      }
    }
  }
}
```

> 👍 Tip: Simplify Launch Forms and Test
>
> Start by launching workflows with simple launch forms. Increase the number and complexity of fields and data types on it after you've successfully tested simple requests.

2. **Permissions (Creator):** Under Company Settings, the Ironclad user that is used as the `creator` in the request payload and `x-as-user-email` request header must be in a group with the Start Workflow permission for the workflow design that is launched on their behalf.

3. **Request Header (User):** If you are using a `multipart/form-data` request in order to include binary files, you must use the `x-as-user-email` or `x-as-user-id` request header to identify the workflow creator. This request header has superseded the `creator` parameter. A 400 error response will be returned if a user request header is required and not included.

> Legacy Token is not supported without either the x-as-user-id or x-as-user-email request header

If you are not using a `multipart/form-data` request (i.e., not including binary files directly in the request body), you may continue to use the legacy `creator` parameter.

# Example Code

The following example code uses Node.js along with the `dotenv` and `axios` packages. They are for demonstration purposes only as to how your code may look at the start.

The `form-data` package is used for the example that describes how to launch workflows with attachments in a multipart/form-data request.

## Asynchronous Route

The following example outlines how to launch a workflow asynchronously and then poll for changes to the status.

Some general recommendations around polling:

* Please try to handle polling so that the API is not being queried for longer than what would be naturally expected (i.e. it should not take more than a few minutes to be completed, so cancel polling if it does).
* While we have aimed to make checking the workflow job status responsive and a lightweight process on our end, we recommend ensuring there’s a time gap when you are checking the status of the workflow launch. Please do not poll any quicker than 2 seconds between requests.

```javascript

require('dotenv').config();
const axios = require('axios').default;

// Be sure to store your API securely!
const apiToken = process.env.API_TOKEN;

// Your host URL may vary based on the implementation.
const hostUrl = (process.env.HOST_URL ? process.env.HOST_URL : 'na1.ironcladapp');
const apiUrl = `https://${hostUrl}.com/public/api/v1`;

// The ID of the workflow template to be launched.
const workflowTemplateId = '60f83d3ecdd9d05a78472166';
// The Ironclad Request body needed to launch the workflow.
const ironcladRequestBody = {
  template: workflowTemplateId,
  attributes: {
    counterpartyName: 'Example Company',
    role4e49a9bbd20c4101b1e475294e534076: 'jane.doe@example.com',
    rolec326ea18494d41b9af47303412e30c0b: 'Jane Doe',
    someTextField: 'A random text value.',
    someDateField: '2021-05-11T17:16:53Z',
    someNumberField: 12345,
    someBooleanField: true,
    someMultiSelectField: ['Option A', 'Option C'],
    someMonetaryField: {
      currency: 'USD',
      amount: 15.75,
    },
    someTable: [
      {
        someTextFieldInTable: 'A random text value for first table row.',
        someNumberFieldInTable: 234,
        someMultiSelectFieldInTable: ['Option D'],
      },
      {
        someTextFieldInTable: 'A random text value for second table row.',
        someNumberFieldInTable: 456,
        someMultiSelectFieldInTable: ['Option E'],
      },
    ],
    someAddressField: {
      lines: ['325 5th Street', 'Suite 200'],
      locality: 'San Francisco',
      region: 'CA',
      postcode: '94107',
      country: 'USA',
    },
  },
};

const checkWorkflowProgress = async (workflowId) => {
  const asyncStatusUrl = `${apiUrl}/workflows/async/${workflowId}`;
  return await axios.get(asyncStatusUrl, {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiToken}`,
      },
  });
};

const pollForWorkflowStatusChanges = async (workflowId) => {
  let pollingCount = 0;
  const pollingLimit = 10;
  return new Promise((resolve, reject) => {
    const interval = setInterval(async () => {
      pollingCount += 1;
      console.log(`Polling count: ${pollingCount}.`);
      const response = await checkWorkflowProgress(workflowId);

      if (response.data.status === 'success') {
        console.log('Successfully launched the workflow!');
        resolve(response.data);
        clearInterval(interval);
      } else if (response.data.status === 'in_progress') {
          console.log('Workflow launch still in progress.');
      } else if (response.data.status === 'failed') {
        console.log('Workflow launch failed');
        reject(new Error(
          `Workflow launch failed with error: ${JSON.stringify(response.data.error,)}`),
          );
          clearInterval(interval);
      } else {
        console.log('Unknown job status. This should not happen!');
      }

      if (pollingCount >= pollingLimit) {
        clearInterval(interval);
        reject(new Error('Did not retrieve a success status after 10 tries.'));
      }
    }, 5000);
  });
};
  
const launchWorkflowAsynchronously = async () => {
  const asyncUrl = `${apiUrl}/workflows/async`;
  console.log(`Starting launch of workflow with template ${workflowTemplateId}.`,);
  const launchResponse = await axios.post(asyncUrl, ironcladRequestBody, {
    headers: {
      'Content-Type': 'application/json',
      'x-as-user-email': '[SOME_AUTHORIZED_USER@YOUR_COMPANY.COM]',
      'Authorization': `Bearer ${apiToken}`,
    },
  });
  console.log(`Now polling for changes to the async status.`);
  return await pollForWorkflowStatusChanges(launchResponse.data.asyncJobId);
};
  
launchWorkflowAsynchronously()
.then((response) => console.log(response))
.catch((err) => console.log(err));

```

## Synchronous Route

This example uses the synchronous route for launching workflows. The request body is a simple raw JSON to show how to launch workflows when only metadata, without in-line file attachments, needs to be sent to Ironclad.

```javascript
require('dotenv').config();
const axios = require('axios').default;

// Be sure to store your API securely!
const apiToken = process.env.API_TOKEN;

// Your host URL may vary based on the implementation.
const hostUrl = process.env.HOST_URL ? process.env.HOST_URL : 'na1.ironcladapp';
const apiUrl = `https://${hostUrl}.com/public/api/v1`;

// The ID of the workflow template to be launched.
const workflowTemplateId = '65adf6f38d0ed50bd8c80008';

// The Ironclad Request body needed to launch the workflow.
const ironcladRequestBody = {
  template: workflowTemplateId,
  attributes: {
    counterpartyName: 'Example Company',
    role58a2edbad73947018a482e26cc6cadc3: 'Chris Counterparty',
    rolea30976486d214f2a9b9942c17e20c0f7: 'chris.counterparty@example.com',
    someTextField: 'A random text value.',
    someDateField: '2021-05-11T17:16:53Z',
    someNumberField: 12345,
    someBooleanField: true,
    someMultiSelectField: ['Option A', 'Option C'],
    someMonetaryField: {
      currency: 'USD',
      amount: 15.75,
    },
    someTable: [
      {
        someTextFieldInTable: 'A random text value for first table row.',
        someNumberFieldInTable: 234,
        someMultiSelectFieldInTable: ['Option D'],
      },
      {
        someTextFieldInTable: 'A random text value for second table row.',
        someNumberFieldInTable: 456,
        someMultiSelectFieldInTable: ['Option E'],
      },
    ],
    someAddressField: {
      lines: ['325 5th Street', 'Suite 200'],
      locality: 'San Francisco',
      region: 'CA',
      postcode: '94107',
      country: 'USA',
    },
  },
};

const launchWorkflowSynchronously = async () => {
  const syncUrl = `${apiUrl}/workflows`;
  return await axios.post(syncUrl, ironcladRequestBody, {
    headers: {
      'Content-Type': 'application/json',
      'x-as-user-email': '[SOME_AUTHORIZED_USER@YOUR_COMPANY.COM]',
      Authorization: `Bearer ${apiToken}`,
    },
  });
};

launchWorkflowSynchronously()
  .then((response) => console.log(response))
  .catch((err) => console.log(err));

```

## Synchronous Route (File Attachments in Body)

This example shows how to launch a workflow with attachments included directly in the request body. The synchronous route with a `multipart/form-data` request body must be used in this method. This example uses a counterparty paper workflow design.

```javascript

require('dotenv').config();
const axios = require('axios').default;
const fs = require('fs');
const FormData = require('form-data');

const apiToken = process.env.API_TOKEN;
// Your host URL may vary based on the implementation.
const hostUrl = process.env.HOST_URL ? process.env.HOST_URL : 'na1.ironcladapp';
const apiUrl = `https://${hostUrl}.com/public/api/v1`;

// The ID of the workflow template to be launched.
const workflowTemplateId = '60f83d3ecdd9d05a78472166';

/* The Ironclad request body needed to launch the workflow.

For regular workflow fields, such as strings, numbers, etc. your JSON will specify (1) the field name as the key and (2) a value to pass into the field.

For file attachment fields, your JSON will specify (1) the field name as the key and (2) the request body part name you wish to use to send the binary file under. Each body part name is a unique name of your choice, not the actual file name.
*/
const ironcladRequestBodyMetadata = {
  template: workflowTemplateId,
  attributes: {
    draft: [{ file: 'someFirstFile' }, { file: 'someSecondFile' }],
    counterpartyName: 'Example Company',
  },
};

const someFirstFile = fs.createReadStream('./MSA - Counterparty LLC.docx');
const someSecondFile = fs.createReadStream('./Order Form - Counterparty LLC.docx');

const form = new FormData();
// Assemble the multipart request by appending the workflow attributes and binary files. The name of the request body part before each file must match the name you specified in your workflow attributes.
form.append('data', JSON.stringify(ironcladRequestBodyMetadata), {
  contentType: 'application/json',
});
form.append('someFirstFile', someFirstFile, {
  contentType: 'application/octet-stream',
});
form.append('someSecondFile', someSecondFile, {
  contentType: 'application/octet-stream',
});

const launchWorkflowSynchronously = async () => {
  const syncUrl = `${apiUrl}/workflows`;
  return await axios.post(syncUrl, form, {
    headers: {
      'Content-Type': 'multipart/form-data',
      'x-as-user-email': '[SOME_AUTHORIZED_USER@YOUR_COMPANY.COM]',
      Authorization: `Bearer ${apiToken}`,
    },
  });
};

launchWorkflowSynchronously()
  .then((response) => console.log(response))
  .catch((err) => console.log(err));

```