Create a Record

Learn about creating an Ironclad Record via the API.

Goal

Technical audiences will learn how to use Ironclad's API to create records in Ironclad's repository. 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 creating records along with tips and limitations to be aware of. The Create a Record 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.

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.

Steps to Creating a Record

1. Create the Payload

In order to create an Ironclad Record via the API, you will need to include 3 required parameters in your request body: (1) record type, (2) name, and (3) properties. The properties parameter can be an empty object if you do not wish to provide any values, but it must still be included (i.e. "properties": {}). The links parameter is optional and can be omitted if you do not wish to link the record to any existing records.

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

{
  "type": "[VALID_RECORD_TYPE]",
  "name": "[NAME_OF_RECORD]",
  "properties": {
    "[PROPERTY_ID_1]": {
      "type": "[PROPERTY_ID_1_TYPE]", // string, number, email, date, monetary_amount
      "value": "[PROPERTY_ID_1_VALUE]" 
    },  
    "[PROPERTY_ID_2]": {
      "type": "[PROPERTY_ID_2_TYPE]",
      "value": "[PROPERTY_ID_2_VALUE]" 
    },  
    "[PROPERTY_ID_3]": {
      "type": "[PROPERTY_ID_3_TYPE]",
      "value": "[PROPERTY_ID_3_VALUE]" 
    }
  },
  "links": [
    {
      "recordId": "[RELATED_RECORD_ID]"
    }
  ]
}

1.1. Record Type

Every record in Ironclad has a type property that is used to identify the contract type or category of information in the record (e.g., "Statement of Work", "Non-Disclosure Agreement", "Vendor Agreement", etc.). The record types that are available in your environment are determined by the workflows that have been deployed.

Use the retrieve records schema endpoint to get a list of all record types. The response includes a recordTypes property which holds the keys for each record type.

📘

Permissions

Your company may be using record types to control view/edit permissions to the record. Check with your company's admin or workflow designer if you would like to determine whether any permissions are involved.

1.2. Name

The name of the record is a human-readable string that helps users understand the contents of your record when looking at it in the repository. Many companies follow a convention along the lines of "[CONTRACT_TYPE] - [COUNTERPARTY_NAME]" (e.g., "SOW with Acme LLC"), but you are free to create your own convention.

1.3. Properties

You can add metadata, record properties, to each record. The list of record properties that you can add can be found by calling the retrieve records schema endpoint. The response includes a properties attribute which describes the (1) keys for each record property and (2) their type (string, date, number, email, monetary_amount). The type determines what format is required for the value.

The record properties available in your environment are determined by the properties built into each workflow. If you need to create additional record properties, work with your Ironclad admin to add them to the relevant workflows.

👍

Records Schema

Your records schema may include record properties with "visible": false and "resolvesTo": "[RECORD_PROPERTY_ID]" values. Use only the "visible": true properties in the schema for simplicity.

Context: Ironclad creates record properties whenever a new field is added to a workflow and published. If the field's name and type matches those of a field in a different workflow, Ironclad automatically resolves those record properties to each other instead of creating duplicate columns.

As a reminder, each property in the payload must be specified as an object with type and value properties. The table below provides the supported types and required format.

"properties": {
  "[PROPERTY_ID_1]": {
    "type": "[PROPERTY_ID_1_TYPE]",
    "value": "[PROPERTY_ID_1_VALUE]" 
  }
}
Property Type Sample Value
string "counterpartyName": {
  "type": "string",
  "value": "Acme LLC"
}
number "quantity_10209d7a-8f3f-4721-a0eb-f1594f4c1e41_number": {
  "type": "number",
  "value": 100.3
}
monetary_amount

Note: The currency property must be ISO-4217.
"totalContractValue_10209d7a-8f3f-4721-a0eb-f1594f4c1e41_monetaryAmount": {
  "type": "monetary_amount",
  "value": {
    "currency": "USD"
    "amount": 10.70
  }
}
duration

Note: The duration property must be ISO 8601 duration format.
"standard_renewalTermLength": {
  "type": "duration",
  "value": "P3Y3M7W8D"
}
date

Note: Value must be ISO8601 formatted with date and time "YYYY-MM-DDTHH:mmZ", "YYYY-MM-DDTHH:mm:ssZ", or "YYYY-MM-DDTHH:mm:ss.SSSZ"

"expirationDate_10209d7a-8f3f-4721-a0eb-f1594f4c1e41_date": {
  "type": "date",
  "value": "2022-10-31:08:30:38Z"
}
email "someEmailField_38bc2557-b075-4ff4-89fe-83fac941d438_email": {
  "type": "email",
  "value": "[email protected]"
}
single-select dropdown (string)

Note: Dropdowns technically are not a separate type in the records API; they are stored as type "string" in records. This row is included for completeness because the workflows API has a structured object for tables. When a workflow stores a table as a record, each key:value in a row is comma (,) separated and each row is semi-colon (;) separated.
"someSingleDropdownField_38bc2557-b075-4ff4-89fe-83fac941d438_string": {
  "type": "string",
  "value": "Option A"
}
multi-select dropdown (string)

Note: Dropdowns technically are not a separate type in the records API; they are stored as type "string" in records. This row is included for completeness because the workflows API has a structured object for tables. When a workflow stores a multi-select dropdown as a record, each selected value is "english list" separated if multiple values have been selected.
"someMultiselectField_38bc2557-b075-4ff4-89fe-83fac941d438_string": {
  "type": "string",
  "value": "Option A , Option B , and Option C"
}
table (string)

Note: Tables technically are not a separate type in the records API; they are stored as type "string" in records. This row is included for completeness because the workflows API has a structured object for tables. When a workflow stores a table as a record, each key:value in a row is comma (,) separated and each row is semi-colon (;) separated.
"someDynamicTable_38bc2557-b075-4ff4-89fe-83fac941d438_list": {
  "type": "string",
  "value": "Some Dynamic Text Field: Acme LLC , Some Dynamic Number Field: 43 , Some Dynamic Date Field: September 17, 2022 ; Some Dynamic Text Field: Example, Inc. , Some Dynamic Number Field: 87 , Some Dynamic Date Field: September 20, 2022;"
}
address (string)

Note: Addresses technically are not a separate type in the records API; they are stored as type "string" in records. Any valid string is accepted, but \n characters will be used to render line breaks on the record UI. This row is included for completeness because the workflows API has a structured object for addresses.
"counterpartyBillingAddress": {
  "type": "string",
  "value": "1233 Howard Street\nSan Francisco, California 94103\nUnited States"
}

📘

Attachments and Related Records

Attachments and related records are not considered properties. You can add or remove attachments via the create an attachment endpoint and related records in the next section.

1.4. Related Record Links

Related record links create bi-directional links between two records; conceptually it is similar to placing hyperlinks that point to each other on each record. The links parameter is optional and can be omitted if you do not wish to link the record to any existing records.

Links can be added as an array of recordId key:values. See the Getting Started - Records guide to understand more about record IDs in Ironclad.

"links": [
  {"recordId": "ffa94b27-6074-41a6-9af0-828d6114cb96"},
  {"recordId": "workflow:632cab598a95cb469deccd8b"},
]

1.5 Example Payload

The snippet below provides an illustrative example of what the above steps may look like. The type, name, and properties parameters can be filled in with the snippets you have constructed through the previous steps.

const recordPayload = () => {
  // Using the current date for example purposes.
  const now = Date();

  // The date needs to be formatted for the API.
  const formattedDate = dateFormat(now, `yyyy-mm-dd'T'HH:mm:ssp`);

  return {
    type: 'contract',
    name: 'My API Generated Record',
    properties: {
      agreementDate: {
        type: 'date',
        value: formattedDate,
      },
      counterpartyName: {
        type: 'string',
        value: 'Example Company',
      },
    },
  };
};

2. Create the Record

You are now ready to create the record. The Create a Record endpoint will be used to create the record. Prepare a request with the following information:

Prepare a request with the following information:

  1. URL: https://[YOUR_IRONCLAD_DOMAIN]/public/api/v1/records. Replace [YOUR_IRONCLAD_DOMAIN] with the Ironclad domain where you are creating the record (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 the Steps 1.1 - 1.4 into a single JSON object; include it as the request body.
  5. Send the request.

Reminder: This request does not include an attachment of the accepted record, which is covered on the Add Attachment to a Record page.

The following code snippet contains an example of what this may look like.

// Create the record.
const createRecord = async () => {
  const createRecordUrl = `${apiUrl}/records`;
  const record = recordPayload();
  const response = await axios.post(
    createRecordUrl,
    JSON.stringify(record),
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiToken}`,
      },
    },
  );
  return response;
};

createRecord()
  .then((response) => console.log(
    `Created record with ID: ${response.data.id}`,
  ))
  .catch((err) => console.log(err));

Example Code (Full)

The following example code combines the snippets above; it 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.

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

// 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`;

/*
 * Create payload based on example available records schema.
 * See retrieving schema here on the following page:
 * https://developer.ironcladapp.com/reference/list-all-records-metadata
 */
const recordPayload = () => {
  // Using the current date for example purposes.
  const now = Date();

  // The date needs to be formatted for the API.
  const formattedDate = dateFormat(now, `yyyy-mm-dd'T'HH:mm:ssp`);

  return {
    type: 'contract',
    name: 'My API Generated Record',
    properties: {
      agreementDate: {
        type: 'date',
        value: formattedDate,
      },
      counterpartyName: {
        type: 'string',
        value: 'Example Company',
      },
    },
  };
};

// Create the record.
const createRecord = async () => {
  const createRecordUrl = `${apiUrl}/records`;
  const record = recordPayload();
  const response = await axios.post(
    createRecordUrl,
    JSON.stringify(record),
    {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiToken}`,
      },
    },
  );
  return response;
};

createRecord()
  .then((response) => console.log(
    `Created record with ID: ${response.data.id}`,
  ))
  .catch((err) => console.log(err));