Box Integration with Smart Import

Overview

This guide demonstrates the principle steps involved in creating an integration between Ironclad and the Box file sharing/storage platform. The guide uses
the Ironclad public APIs and Box's native integration capabilities, including Box Custom Skills.

The use case we demonstrate in this guide shows a contract intake process in which executed agreements are stored in Box folders, and these
agreements need to be automatically fed into your Ironclad repository using Ironclad Smart Import. This is a useful example use case in general,
but it also works well as a general demonstration of integrating Box into Ironclad that can be adjusted to work for other use cases as well.

Please note that the approach shown here is only meant to demonstrate an example solution for building this integration -- it is a custom integration
and not an out-of-the-box supported Ironclad integration. To view a list of out-of-the-box integrations that Ironclad supports, check out our Help Center.

The figure below shows the high-level interactions between Ironclad and Box implemented in this example. Files stored in specific Box folders
will trigger a Box Custom Skill that will in turn load the files into the Ironclad repository using Ironclad's Smart Import API.

Box / Ironclad Integration

This guide has the following sections:

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.

Background

Ironclad

  • API Access: Your Ironclad environment will need to have API access enabled, since our example makes use of the Ironclad public APIs to enable the integration.
  • Smart Import: You will need to have Smart Import entitlements on your Ironclad instance in order to make use of the Smart Import API. You can check the Smart Import entitlements for your instance in the Settings section of your Company Settings area in Ironclad.
  • Reference Documentation:

Box

This example makes use of Box Skills, which are a platform feature only available in Box "Business Plus" and higher plans. Check your Box account type in the Box admin settings.

You will also need to have an admin account on your Box environment in order to make the configuration updates described in this guide.

Google Cloud

Our example solution for this integration uses an HTTP-triggered Google Cloud function as the handler for the Box Custom Skill that will trigger the import into Ironclad. Once you deploy
a Google Cloud Function, a URL will be generated for the function by GCP. This URL will be used as the Invocation URL for the Box custom skill we configured in the section above.

Box Custom Skills can be configured to use any server-side function that can expose a URL to be called with a JSON event payload. Depending on your own architecture and technical skills, you can replace the Google Cloud function here with
an AWS Lambda function, Azure function, Node.js app, etc.

If you do want to use a Google Cloud function similar to the one in our example, you will need a GCP account login with privileges allowing for the creation and running of Google Cloud Functions.

Ironclad Configuration

In our example, we are creating new Ironclad records using the default Smart Import record type of "imported". If you wanted to import into other existing record types, you
would need to use the name of the record type in the calls to the Ironclad Smart Import API described in the Google Cloud function section below.

Box Configuration

Create Custom App

As described above, we will use a Box Custom Skill to trigger the import of files into Ironclad records. A Box Custom Skill requires an app to execute the custom logic you need, so you'll need to create one.
Login to your Box account and go to the Dev Console, where you can create and manage custom apps for your Box environment.

  • Create a new app of type "Box Custom Skill", giving it whatever name you prefer.
  • In the "General Settings" section of the app settings, set the fields as you prefer.
  • In the "Configuration" section of the app settings:
    • You will eventually need the generated Client ID here to configure the Google Cloud function you will setup in the next section. This Client ID will also be used to authorize the app in your Box environment, and to configure the Custom Skill that will actually invoke your app based on user actions in the Box environment.
    • The Invocation URL will be set to the endpoint for the Google Cloud function once it is deployed, in order to have the skill events sent to the cloud function.
    • You should set the File Extensions field to limit the skill to only trigger on files that are supported by Ironclad Smart Import.
  • You will also need the Primary Key and Secondary Key values in the "Security Keys" sections when you configure the Google Cloud function.

Authorize the Custom App

In order for your custom app to have access to your Box users and content, you'll need to authorize it in your Box Environment.

Go to the Admin Console in your Box environment, and go to the Apps section. Go to the Custom Apps Manager tab in this section, and click on "Add App" to create a new Server Authentication App. Use the Client ID from your custom app in the dialog box that appears.

Adding the Custom App

Configure the Custom Skill

Now that you have a custom app, you can configure a Custom Skill that can be mapped to files and folders in your Box environment to trigger the custom app.

In order to create and configure Custom Skills, you need to navigate to a special URL in your Box Admin Console, https://app.box.com/master/skills.
Box, for some reason, does not provide a navigation option from the Admin Console to this page, so you will need to navigate to it directly in your browser once
you are logged into your Box account.

In the Skills section, click on the "Add Skill" link and enter the Client ID for your custom app.

Adding the Custom Skill

On the next screen, select the folders where you want the skill to be triggered. You can either apply the skill to all content, or to a specific list of folders.

Mapping the Skill to Folders

In the screens that follow this one, you can pick the folders for the skill (if you chose that option), and then enable the skill.

Once the skill is enabled, any files added to the selected content folders will trigger the custom skill, which will in turn send an event to the URL endpoint configured in your custom app.
The last piece of the solution is to put some custom code in place that will receive the event and perform the Ironclad Smart Import.

Google Cloud Configuration

As mentioned above, for our example we've chosen to use a Google Cloud function as the server app to drive our custom Box app. If you need details on how to develop and deploy Google Cloud Functions,
you can refer to their developer documentation on the subject. Here, we will just describe how the actual code for our Cloud Function handles the inbound event from Box and then imports the Box file into Ironclad using the Smart Import API.

Overview

Our Cloud Function is implemented using Node.js. In the main code file for our function, we import three external packages

  • box-node-sdk: The Box Node.js SDK is used to make calls to the Box environment to retrieve the file triggering the skill
  • axios: The Axios package is used to construct API calls to Ironclad.
  • form-data: The form-data package is used to compose a multi-part form payload for the Ironclad Smart Import API.
    const BoxSDK = require('box-node-sdk');
    const axios = require('axios');
    const FormData = require('form-data');
        . . .

The only export in our code is the main Cloud Function method, handleBoxFile. This method will be called whenever the Cloud Function's endpoint is invoked from our Box custom skill, and the request payload will contain the
event details sent from the Box custom skill:

    /**
    * HTTP Cloud Function.
    *
    * @param {Object} req Cloud Function request context.
    * @param {Object} res Cloud Function response context.
    */
    exports.handleBoxFile = async (req, res) => {
        . . .

Configure Box SDK and Custom App Keys

    try {
        let boxSDK = new BoxSDK({
            clientID: process.env.BOX_CLIENT_ID,
            clientSecret: process.env.BOX_CLIENT_SECRET
        });

        let skillPrimaryKey = process.env.BOX_SKILL_PRIMARY_KEY;
        let skillSecondaryKey = process.env.BOX_SKILL_SECONDARY_KEY;
        . . .

The first thing we do in our Cloud Function is configure the Box SDK to allow us to make API calls back to Box. The clientID parameter passed into the BoxSDK constructor is the Client ID field from the Box custom app that was configured in the section above. The clientSecret parameter is not validated by the BoxSDK, so you can set it to any value you like. We are reading both of these from runtime environment variables named BOX_CLIENT_ID and BOX_CLIENT_SECRET, so these variables will need to be configured on your Google Cloud Function deployment, and the values will need to be set appropriately.

After we configure the BoxSDK, we read in the security keys for our Box custom skill from two more environment variables, BOX_SKILL_PRIMARY_KEY and BOX_SKILL_SECONDARY_KEY. These variables should be set to be the values of the "Primary Key" and "Secondary Key" fields found in the "Security Keys" section of the Box custom app configuration. We will use these keys next in the Google Cloud Function to verify the inbound skill event.

Validate the Skill Event

        . . .
        if (!(skillPrimaryKey && skillSecondaryKey)) {
            let msg = "Box Smart Import: Unable to verify payload, missing skill primary and/or secondary key.";
            console.error(msg);
            return res.status(500).send(msg);
        }

        let validPayload = BoxSDK.validateWebhookMessage(req.body, req.headers, skillPrimaryKey, skillSecondaryKey);
        if (!validPayload) {
            let msg = `Box Smart Import: Unable to validate skill payload`;
            console.log(msg);
            return res.status(400).send(msg);
        }
        else {
            console.log(`Box Smart Import: Skill payload validated`);
        }
        
        // Make sure we have the right data to process the function or exit.
        if (!(req.body.source && req.body.source.type == "file")) {
            let msg = `Box Smart Import: Invalid or no source provided`;
            console.error(msg);
            return res.status(400).send(msg);
        }
        
        if (!req.body.token) {
            console.error(`Box Smart Import: No auth token provided`);
            return res.status(400).send(msg);
        }
        . . .

Before we try to load the Box file referenced in the inbound request, we first need to validate the payload using the BoxSDK.validateWebhookMessage method. This method takes the event payload and headers found in the request, along with the primary and secondary keys for our Box custom app. If the event is not validated, then we exit immediately with an HTTP 400 error.

Next we check to be sure that the "source type" provided in the event is an actual file. Events for custom skills can be triggered from both folders and files, and we only want to handle events for new files that need to be imported into Ironclad.

Finally, we check the Box event payload to be sure that an auth token object was provided. The access token contained in this object will be used to access the actual file content from Box so that we can pass the file to Ironclad to be imported.

Read the Box File Content

        . . .
        // Get a stream connected to the Box file content
        let fileReadToken = req.body.token.read.access_token;
        let fileReadClient = boxSDK.getBasicClient(fileReadToken);
        await fileReadClient.files.getReadStream(req.body.source.id, null, async (err, stream) => {
            if (err) {
                let msg = `Box Smart Import: Failed to read Box file: ${err}`;
                console.error(msg);
                res.status(500).send(msg);
            }
            else {
                console.log(`Stream to Box file ${boxFileID} established`);
                . . .

Once we have validated the inbound Box skill event, we then get a read stream to the Box file content. This is done by first using the BoxSDK to make an API client to call back to the Box server, passing the access token provided in the event payload. Once we have the API client, we use it to get the file stream using its getReadStream method, passing the ID of the Box file referenced in the inbound event.

Smart Import the Box File

                . . .
                if (!process.env.IRONCLAD_API_KEY || !process.env.IRONCLAD_DOMAIN) {
                    let msg = `Box Smart Import: Environment variable(s) missing: IRONCLAD_API_KEY and/or IRONCLAD_DOMAIN required`;
                    console.error(msg);
                    res.status(500).send(msg);
                }
                else {
                    let IC_SMART_IMPORT_ENDPOINT = `https://${process.env.IRONCLAD_DOMAIN}/public/api/v1/records/smart-import`;

                    let smartImportForm = new FormData();
                    smartImportForm.append('attachment', stream, req.body.source.name);
                    smartImportForm.append('recordType', 'imported');

                    let axiosCfg = {
                        method: "post",
                        url: IC_SMART_IMPORT_ENDPOINT,
                        data: smartImportForm,
                        headers: {
                            'Authorization': `Bearer ${process.env.IRONCLAD_API_KEY}`
                        }
                    };
        
                    await axios(axiosCfg).then(resp => {
                        let msg = `Box Smart Import: Box file ${boxFileID} imported as Ironclad record ${resp.data.recordId}`;
                        console.log(msg);
                        res.status(200).send(msg);
                    })
                    .catch(err => {
                        let msg = `Box Smart Import: Failed to import Box file ${boxFileID}: ${err}`;
                        console.error(msg);
                        if (err.response) {
                            console.error(`Box Smart Import: Ironclad API err response: ${JSON.stringify(err.response.data)}`);
                        }
                        res.status(200).send(msg);
                    });
                }        
                . . .

Finally, we can import the Box file into Ironclad using the Smart Import API.

We are using two more environment variables here: IRONCLAD_API_KEY is the value of a bearer token generated on your Ironclad instance, and IRONCLAD_DOMAIN is the full domain of the Ironclad stack where your Ironclad instance runs (e.g., ironcladapp.com for production, demo.ironcladapp.com for demo, etc.).

We compose the URL for the call the Smart Import API endpoint, and then we compose a multi-part form payload for the API call using an FormData object, passing in the file stream we made earlier to the Box file content.

We make the call to the Smart Import API using Axios, passing in the Ironclad API bearer token in the header, and the form data as the payload.

See It In Action

Once all of these pieces are in place (the Box custom app, the Box custom skill, and the Google Cloud function), any file that you drop into the configured Box folders will automatically trigger an event through the Box custom app to the Google Cloud function. If the import process is successful, a new imported record will appear in your Ironclad repository, allowing you to see and confirm the contract attributes that were automatically detected in the inbound file from Box:

Smart-Imported Ironclad Record