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

Details

Each workflow launch request has 3 required parameters in the request body: (1) template ID, (2) creator, and (3) 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]",
  "creator": {
    "type": "email",
    "email": "[USER_EMAIL]"
  },
  "attributes": {
    "[FIELD_ID_1]": "[FIELD_VALUE_1]",
    "[FIELD_ID_2]": "[FIELD_VALUE_2]",
    "[FIELD_ID_3]": "[FIELD_VALUE_3]",
  }

1. Template ID (Request Body)

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.

2. Creator (Request Body)

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

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

Creator Example (Email)

"creator": {
  "type": "email",
  "email": "[email protected]"
}

Creator Example (User ID)

"creator": {
  "type": "id",
  "id": "abcdef12345678910"
}

📘

Permissions

The creator must have the Start Workflow permission in order for API requests on their behalf to succeed.

3. Attributes (Request Body)

The attributes parameter specifies the values to pass into workflow 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 format that follows:

{
  "id": "[TEMPLATE_ID]",
  "name": "[NAME_OF_WORKFLOW_DESIGN]",
  "schema": {
    "[FIELD_ID_1]": {
      "type": "[FIELD_TYPE]", // string, number, boolean, date, 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 in the response body provides an object with nested field-related objects. The field-related objects will have the following:

  • 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:
    • 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 filled in 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"
    },
    "custom03314b365999474aae2fd6fe41fd643e": {
      "type": "string",
      "displayName": "My Custom Text Field"
    },
    "customde7960b7350442da8233d4c9e13d1bfd": {
      "type": "string",
      "displayName": "My Dropdown Field"
    },
    "customeafe5a3666d440e19630a49087b91c4e": {
      "type": "string",
      "displayName": "My Single-Select Multiple Choice Field"
    },
    "customff89815d10804c12a392e3a1f19e15a2": {
      "type": "array",
      "displayName": "My Multi-Select Multiple Choice Field",
      "elementType": {
        "type": "string"
      }
    },
    "customd40a3b08606d43eca25a45a5fa32fcc9": {
      "type": "number",
      "displayName": "My Custom Number Field"
    },
    "custome68d1ab63a9846ccbcb4c65dfde2215d": {
      "type": "boolean",
      "displayName": "My Custom Boolean Field (Yes/No)"
    },
    "custome793ed5d6e1046989da91894f1da6019": {
      "type": "date",
      "displayName": "My Custom Date Field"
    },
    "customd35f2489f20b46aa89b981e0f0d99cc7": {
      "type": "monetaryAmount",
      "displayName": "My Custom Monetary Amount Field"
    },
    "custom0b4e1a4fd0f84431a93db17b65a041b0": {
      "type": "address",
      "displayName": "My Custom Address Field"
    },
    "list7c0aaf5a248047b99f3bb9c86388a34c": {
      "type": "array",
      "displayName": "Some Dynamic Table",
      "elementType": {
        "type": "object",
        "schema": {
          "dynamicProperty2a36a8386b31402b9b45ba7efce12d25": {
            "type": "string",
            "displayName": "Some Dynamic Table String"
          },
          "dynamicPropertyee7af7cb2305418997fed0348412838b": {
            "type": "number",
            "displayName": "Some Dynamic Table Number"
          },
          "dynamicPropertye8fa405980d6487b9f17cbe048057232": {
            "type": "array",
            "displayName": "Some Dynamic Table Multiple Select",
            "elementType": {
              "type": "string"
            }
          }
        }
      }
    },
    "custom3f04dd95e1694c83a6da2af87908a869": {
      "type": "array",
      "displayName": "My Custom File Upload Field",
      "elementType": {
        "type": "document"
      }
    }
  }
}

3.2. Create Request Body (Attributes)

Construct your attributes pararmeter 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"
Email"customecda3d929f044e788082a00ce3c515e5": "[email protected]"
Boolean

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

"custome68d1ab63a9846ccbcb4c65dfde2215d": true
Single-Select (Same as String)"customeafe5a3666d440e19630a49087b91c4e": "Option A"
Multi-Select"customff89815d10804c12a392e3a1f19e15a2": [
    "Option A",
    "Option B"
]
Dynamic Table"list7c0aaf5a248047b99f3bb9c86388a34c": [
    {
        "dynamicProperty2a36a8386b31402b9b45ba7efce12d25": "Some Row 1 Text",
        "dynamicPropertyee7af7cb2305418997fed0348412838b": 25,
        "dynamicPropertye8fa405980d6487b9f17cbe048057232": ["Option A", "Option B"],
    },
    {
        "dynamicProperty2a36a8386b31402b9b45ba7efce12d25": "Some Row 2 Text",
        "dynamicPropertyee7af7cb2305418997fed0348412838b": 27,
        "dynamicPropertye8fa405980d6487b9f17cbe048057232": ["Option B", "Option C"]
    }
]
File

Note: See Section 3.5 for full details on usage and requirements. Ironclad adopts a file “pulling” model for attaching files to workflows. During workflow launch, Ironclad's server fetches the files; the files must be hosted online at publicly accessible urls.
// The urls below are stubs. Please replace them with urls that point to your own files.

"custom3f04dd95e1694c83a6da2af87908a869": [
    { "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.

🚧

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

Ironclad adds files to a workflow by pulling files directly from a public URL that links directly to the file.

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

File upload fields support have file type restrictions that depend on whether the field is used in the signature packet.

🚧

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:

.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. 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: Add authorization headers: Authorization: Bearer [YOUR_API_TOKEN]
  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 varations 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 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.

5. 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\")."
        ]
      }
    }
  }
}
  1. Permissions (Creator): Under Company Settings, the Ironclad user that is used as the creator must be in a group with the Start Workflow permission for the workflow design that is launched on their behalf.

👍

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.

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.

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,
  creator: {
    email: '[email protected]',
    type: 'email',
  },
  attributes: {
    counterpartyName: 'Example Company',
    role4e49a9bbd20c4101b1e475294e534076: '[email protected]',
    rolec326ea18494d41b9af47303412e30c0b: 'Jane Doe',
    custom03314b365999474aae2fd6fe41fd643e: 'A random text value.',
    custom6e7cf34c788842a98a916729d775131c: '2021-05-11T17:16:53-07:00',
  },
};

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, JSON.stringify(ironcladRequestBody), {
      headers: {
        'Content-Type': 'application/json',
        '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

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,
  creator: {
    email: '[email protected]',
    type: 'email',
  },
  attributes: {
    counterpartyName: 'Example Company',
    role4e49a9bbd20c4101b1e475294e534076: '[email protected]',
    rolec326ea18494d41b9af47303412e30c0b: 'Jane Doe',
    custom03314b365999474aae2fd6fe41fd643e: 'A random text value.',
    custom6e7cf34c788842a98a916729d775131c: '2021-05-11T17:16:53-07:00',
  },
};

const launchWorkflowSynchronously = async () => {
  const syncUrl = `${apiUrl}/workflows`;
  return await axios.post(syncUrl, JSON.stringify(ironcladRequestBody), {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiToken}`,
    },
  });
};

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

Did this page help you?