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 endpoint will be used.

Prerequisites

  1. API Token: Learn more about generating your API token and expected headers in the Authentication 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 and Ironclad's Help Center.

👍

Tip: End-to-End Testing

Test your API requests in 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).

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.

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.

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.

{
  "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 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 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. 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 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 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 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 in order for API requests on their behalf to succeed.

Creator Example (Email)

{
  "template": "[WORKFLOW_TEMPLATE_ID]",
  "creator": {
    "type": "email",
    "email": "[email protected]"
  },
  "attributes": {
    "[FIELD_ID_1]": "[FIELD_VALUE_1]",
    "[FIELD_ID_2]": "[FIELD_VALUE_2]",
    "[FIELD_ID_3]": "[FIELD_VALUE_3]",
  }
}

Creator Example (User ID)

{
  "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 endpoint using (1) the workflow design's template ID from Section 1 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:

{
  "id": "[TEMPLATE_ID]",
  "name": "[NAME_OF_WORKFLOW_DESIGN]",
  "schema": {
    "[FIELD_ID_1]": {
      "type": "[FIELD_TYPE]", // string, number, boolean, date, duration, monetaryAmount, email, address, or array
      "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 or open your design in Workflow Designer.

Schema Object Model (Example)

{
  "id": "60f83d3ecdd9d05a78472166",
  "name": "My Workflow Design Name",
  "schema": {
    "counterpartyName": {
      "type": "string",
      "displayName": "Counterparty Name"
    },
    "role4e49a9bbd20c4101b1e475294e534076": {
      "type": "email",
      "displayName": "Counterparty Signer Email"
    },
    "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 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 endpoint to get the field IDs and properly formatted values under the attributes property.

📘

Supported Field Types

User dropdown fields, formula fields, and related records fields are currently not supported via API. Consider passing data into string fields or moving fields to an Internal Form for users to fill in after a workflow is launched.

Field TypeSample Value
String

Note: Strings have a 32,000 character limit. Workflows will error at the archive step if it is exceeded.
"counterpartyName": "Acme LLC"
Address

Note: Addresses are validated.
  • Non-US addresses require (1) street (lines), (2) locality, and (3) country.
  • 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.
  • The lines array is limited to four street lines.
"custom03314b365999474aae2fd6fe41fd643e": {
    "lines": [
        "325 5th Street",
        "Suite 200"
    ],
    "locality": "San Francisco", 
    "region": "California",
    "postcode": "94107",
    "country": "USA"
}
Number"customd40a3b08606d43eca25a45a5fa32fcc9": 35
Monetary Value"customd35f2489f20b46aa89b981e0f0d99cc7": {
    "currency": "USD",
    "amount": 25.37
}
Date"custome793ed5d6e1046989da91894f1da6019": "2021-05-11T17:16:53-07:00"
Duration
The duration value must include one or more units of time (years, months, weeks, or days).
"someDurationField": {
    "years": 1,
    "months": 2,
    "weeks": 3,
    "days": 4
}
Email"someEmailField": "[email protected]"
Boolean

Note: The Yes/No field field in Workflow Designer is a boolean.

"someYesNoField": true
Single-Select (Same as String)"someSingleSelectField": "Option A"
Multi-Select"someMultiSelectField": [
    "Option A",
    "Option B"
]
Table"someTable": [
    {
        "someTextFieldInTable": "Some Row 1 Text",
        "someNumberFieldInTable": 25,
        "someMultiSelectFieldInTable": ["Option A", "Option B"],
    },
    {
        "someTextFieldInTable": "Some Row 2 Text",
        "someNumberFieldInTable": 27,
        "someMultiSelectFieldInTable": ["Option B", "Option C"]
    }
]
File

Note: See Section 3.5 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.
Option 1: Multipart/Form-Data Request
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 for more details.
"draft": [
    { "file": "someFirstFile" },
    { "file": "someSecondFile" }
]

Option 2: Publicly Accessible URLs
// The urls below are stubs. Please replace them with urls that point to your own files.

"draft": [
    {"url": "https://your.file.server.test/test-doc-1.docx"},
    {"url": "https://your.file.server.test/test-doc-2.docx"}
]

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 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 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).

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.

{
  "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.

Multipart/Form-Data HTTP Request Example

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


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]

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 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 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.

Usage Supported File Types
Included in signature packet:
- Counterparty paper workflow file upload field (draft attribute)
- Custom file upload fields configured for inclusion in signature packets
.doc, .docx, .pdf
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.
.doc, .docx, .pdf, .jpeg, .jpg, .png, .gif, .xls, .xlsx, .csv, .ppt, .pptx

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 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 to pass in binary files.

5. Launch the Workflow

You are now ready to launch the workflow. The Create a Workflow Synchronously endpoint will be used to launch the workflow.

Prepare a request with the following information:

  1. URL: https://[YOUR_IRONCLAD_DOMAIN]/public/api/v1/workflows. Replace [YOUR_IRONCLAD_DOMAIN] with the Ironclad domain 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 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 endpoint (used above) that launches the workflow and waits to respond with whether the workflow has successfully launched or encountered errors.
  2. An asynchronous launch endpoint which has an accompanying asynchronous job 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 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

{

  "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.

  1. 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.

  2. 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.

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 : '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: '[email protected]',
    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.

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 : '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: '[email protected]',
    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.


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 : '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));


What’s Next

Learn more about the different properties used to launch a workflow or how to launch a workflow with external files.