Adding Association Labels to Contacts Through a Workflow

[September 2023]

Using the HubSpot API within a custom element in a workflow we are able to add or change Association Labels for contacts with companies. In our example we use a form to trigger the workflow and to ensure we have the correct information needed.

For our client, we used association labels to send external email communication to specific contacts in a Company Object workflow.

Step 1:

The first step of this process is to create the form that will capture the information about the contact, the company, and the label to apply.

In our use case, we had a password protected page that was for a specific company (built with multilevel pages that pulled both company properties and data from HubDB tables. The form in this case was linked to from a URL that included parameters from the company’s properties. This allowed us to have a form without dropdowns like in the example here. In this example, we use a form that allows a user to select from a dropdown, which then dynamically is used in the workflow to create an association and set the correct label for the association.

Tip: This is a Contact object form, but you will need to record the Company ID to then reference in the workflow. We achieve this through a new Contact Property to store the Company ID. 

Step 2:

If you have not yet already, once the form is made it is time to make sure your association labels are created. You can do this a few ways. We had already created the labels directly through a contact record, but you can also go to Settings > Data Management > Contacts > Associations and click the “Create association label” button. It should default to “Contacts-to-Companies” in the Objects you’re associating dropdown.

Step 3:

Once the labels are created and a test contact has been added with a company association for each of the association labels, you can create the workflow.

This will be a Contact Object workflow with the enrollment trigger set to be the form submission.

Rather than jumping right into creating branches for the different labels, we need to first know how Hubspot refers to these labels. We need to know their TypeID.

This is achieved through creating a Custom Code Element and utilizing the GET method. This is described on HubSpot.

The code used is below. In this code, the contactId and companyId variables are included along with the fromObjectType and toObjectType variables. You can replace 'your_api_key_here', contactId, and companyId with the actual values you want to use.

This code will not only fetch the association types between the specified object types but will also include the contact and company IDs that you enter.

const axios = require('axios');

exports.main = async (event, callback) => {
  const apiKey = 'your_api_key_here'; // Replace with your API key
  const contactId = 'CONTACTID'; // Replace with the actual contact ID
  const companyId = 'COMPANYID'; // Replace with the actual company ID
  const fromObjectType = 'contact'; // Replace with your source object type
  const toObjectType = 'company'; // Replace with your target object type

  try {
    // Make a GET request to retrieve association types
    const response = await axios.get(
      `https://api.hubapi.com/crm/v4/associations/${fromObjectType}/${toObjectType}/labels`,
      {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiKey}`
        }
      }
    );

    const associationTypes = response.data;
    console.log('Association Types:', associationTypes);

    // Rest of your code here...

  } catch (error) {
    console.error('Error fetching association types:', error.response.data);
    callback({
      outputFields: {
        message: 'Error fetching association types'
      }
    });
  }
};

To test this code, insert the contact ID of the individual who has associations with each of the labels and the Company ID from one of the companies the contact is associated to.

Then, in the Test feature, select that individual. The Log with identify the typeID and label for each of the associations. See below for an example log.

2023-09-13T11:30:42.371Z	INFO	Association Types: {
  results: [
    { category: 'USER_DEFINED', typeId: 19, label: 'Label 2' },
    { category: 'USER_DEFINED', typeId: 17, label: 'Label 1' },
    { category: 'HUBSPOT_DEFINED', typeId: 1, label: 'Primary' },
]
}

Memory: 70/128 MB
Runtime: 759.60 ms

A second way to find the typeID for the label is with the URL of the association label itself.

  • Click to the Association Labels for the Object
  • Click Edit for the specific association label
  • The URL will look like: https://app.hubspot.com/association-settings/your-account-number/edit-association-label/17
  • In this case, the typeID is ’17’

Step 4:

Now that we have the individual label’s typeID we can create the workflow. Because accounts are restricted to 10 labels per object pair (see HubSpot for more), I decided to create a branch for each possible label. Because of this, I repeat the code element multiple times.

An alternative to this, and a ‘cleaner’ way to achieve the same result is to have a new contact property store the label’s typeID. The workflow would branch to set this property and then come back together inserting the value of this new property as the typeID.

Step 5:

The last step is to create the code element to set the association. The following code uses the contact’s Record ID and the Company ID for the company we want to use in the association.

When we built this for our client, we used parameters in the URL to automatically set the Company ID, however, if you have a smaller number of companies, you could create branches within the workflow to set the values (or conditional formatting in the form itself).

This example workflow does the latter. In our form, we use the field “Event Name” to identify which Company ID to insert. Ideally you would want this to be less open ended than a text-field, perhaps a dropdown. gain, in our actual solution, the company values were pre-filled with parameters in the URL.

Please note – we also are using a property “event_code” to store this Company ID – in reality we would want a parameter name that more closely relates to ‘company_id’ for clarity. 

const axios = require('axios');

exports.main = async (event, callback) => {
 const apiKey = 'your-api-key';  // Replace with your API key

 const associationTypeId = 17;  // For each branch, update this with the typeID or replace with the value from a contact property
 const associationLabel = 'Label 1';  // Replace with the actual association label name

 const contactId = event.inputFields['hs_object_id'];  // Replace with the actual contact ID
   
 const companyId = event.inputFields['event_code'];  // Replace with the actual contact ID

try {
    const response = await axios.put(
      `https://api.hubapi.com/crm/v4/objects/contact/${contactId}/associations/company/${companyId}`,
      [
        {
          "associationCategory": "USER_DEFINED",
          "associationTypeId": associationTypeId,
          "label": associationLabel
        }
      ],
      {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiKey}`
        }
      }
    );

    console.log('Association created successfully:', response.data);
    callback({
      outputFields: {
        message: 'Association created successfully'
      }
    });
  } catch (error) {
    console.error('Error creating association:', error.response.data);
    callback({
      outputFields: {
        message: 'Error creating association'
      }
    });
  }
};

Tip: If there is an error when you execute, it may be because the companyID or contactID aren’t being captured correctly. The following can be added to the code to see what values are being passed.

You can also log other values if needed, as well.

// Log contactId and companyId for debugging purposes
  console.log('contactId:', contactId);
  console.log('companyId:', companyId);