Custom Code Workflow Actions Explained:

Kickbox Email Verification in HubSpot Workflows

Learn how to verify emails on-the-fly using custom code. It's easier than you think!

Kickbox email validation illustration

What is Kickbox?

Kickbox is an email verification service that helps you maintain a clean, healthy email list. Instead of verifying your entire database at once (which can be expensive), we'll verify emails one at a time as contacts enter your workflows. Smart, right?

The star of the show is the Sendex score — a quality rating from 0 to 1 that tells you how likely an email is to be deliverable. The higher the score, the safer it is to email that contact.

Before You Start

You'll need a few things set up in HubSpot before we dive into the code:

  1. A Kickbox API key — Sign up at kickbox.com and grab your API key
  2. A HubSpot Private App — Create one with crm.objects.contacts.write scope
  3. Two secrets in your workflow:
    • academy_secret — Your HubSpot Private App token
    • KickboxKey — Your Kickbox API key
  4. A custom contact property called kickbox_sendex (Number type)

Don't worry if you're not sure how to set these up — HubSpot's documentation walks you through each step.

Step 1: The Basic Structure

Let's start with the skeleton of our custom coded action. Every workflow action needs to import libraries, connect to HubSpot, and grab the contact's email. Here's what that looks like:

kickbox-verify.js
// Import libraries (Node.js 20 compatible) const hubspot = require('@hubspot/api-client'); const axios = require('axios'); exports.main = async (event, callback) => { // Connect to HubSpot API with a private app token stored as a secret. const hubspotClient = new hubspot.Client({ accessToken: process.env.academy_secret }); // Retrieve the email from the workflow input fields. const email = event.inputFields['email']; // We'll add more code here... }

Notice how we're using async on our main function? That's because we'll be making API calls, and we want to wait for them to complete. The event.inputFields['email'] gives us the contact's email — you'll need to add "email" as an input field when configuring your workflow action.

Step 2: Add Error Handling

Things don't always go according to plan. APIs can be slow, networks can hiccup, and rate limits can kick in. Let's wrap our code in a try-catch block so HubSpot knows to retry if something goes wrong:

kickbox-verify.js
// Import libraries (Node.js 20 compatible) const hubspot = require('@hubspot/api-client'); const axios = require('axios'); exports.main = async (event, callback) => { // Connect to HubSpot API with a private app token stored as a secret. const hubspotClient = new hubspot.Client({ accessToken: process.env.academy_secret }); // Retrieve the email from the workflow input fields. const email = event.inputFields['email']; try { // We'll add the Kickbox API call here... } catch (err) { console.error(err); // HubSpot will automatically retry if this fails due to rate limits. throw err; } }

Step 3: Call the Kickbox API

Now for the fun part! We'll call Kickbox's verify endpoint with the contact's email. We use encodeURIComponent to handle any special characters in email addresses (like + signs):

kickbox-verify.js
// Import libraries (Node.js 20 compatible) const hubspot = require('@hubspot/api-client'); const axios = require('axios'); exports.main = async (event, callback) => { // Connect to HubSpot API with a private app token stored as a secret. const hubspotClient = new hubspot.Client({ accessToken: process.env.academy_secret }); // Retrieve the email from the workflow input fields. const email = event.inputFields['email']; try { // Verify the email using the Kickbox v2 API. // Use encodeURIComponent to safely handle special characters in email addresses. const response = await axios.get( `https://api.kickbox.com/v2/verify?email=${encodeURIComponent(email)}&apikey=${process.env.KickboxKey}` ); const data = response.data; // Next: we'll store this data in HubSpot... } catch (err) { console.error(err); // HubSpot will automatically retry if this fails due to rate limits. throw err; } }

Kickbox returns a ton of useful data — including the sendex score we're after. The response also includes things like whether the email is disposable, a role address, or has obvious typos. You could store all of these if you wanted!

Step 4: Store the Result in HubSpot

We've got the sendex score — now let's save it to the contact record. We use the HubSpot client's basicApi.update method to patch the contact properties:

kickbox-verify.js
// Import libraries (Node.js 20 compatible) const hubspot = require('@hubspot/api-client'); const axios = require('axios'); exports.main = async (event, callback) => { // Connect to HubSpot API with a private app token stored as a secret. const hubspotClient = new hubspot.Client({ accessToken: process.env.academy_secret }); // Retrieve the email from the workflow input fields. const email = event.inputFields['email']; try { // Verify the email using the Kickbox v2 API. // Use encodeURIComponent to safely handle special characters in email addresses. const response = await axios.get( `https://api.kickbox.com/v2/verify?email=${encodeURIComponent(email)}&apikey=${process.env.KickboxKey}` ); const data = response.data; // Update the contact properties in HubSpot. // In current SDKs, basicApi.update is the correct method for patching contact properties. // Docs: https://developers.hubspot.com/docs/api/crm/contacts await hubspotClient.crm.contacts.basicApi.update(event.object.objectId, { "properties": { "kickbox_sendex": data.sendex } }); // Finally: we'll return the score so the workflow can use it... } catch (err) { console.error(err); // HubSpot will automatically retry if this fails due to rate limits. throw err; } }

The Complete Code

Here's the final version with everything put together. Notice we also use the callback function to return the sendex score as an output. This means you can use it in subsequent workflow actions — like branching based on the score!

kickbox-verify.js
// Import libraries (Node.js 20 compatible) const hubspot = require('@hubspot/api-client'); const axios = require('axios'); exports.main = async (event, callback) => { // Connect to HubSpot API with a private app token stored as a secret. const hubspotClient = new hubspot.Client({ accessToken: process.env.academy_secret }); // Retrieve the email from the workflow input fields. const email = event.inputFields['email']; try { // Verify the email using the Kickbox v2 API. // Use encodeURIComponent to safely handle special characters in email addresses. const response = await axios.get( `https://api.kickbox.com/v2/verify?email=${encodeURIComponent(email)}&apikey=${process.env.KickboxKey}` ); const data = response.data; // we could deconstruct this in the line above by changing response to { data } // Update the contact properties in HubSpot. // In current SDKs, basicApi.update is the correct method for patching contact properties. // Docs: https://developers.hubspot.com/docs/api/crm/contacts // If you need to verify available methods, you can log them: // console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(hubspotClient.crm.contacts.basicApi))); await hubspotClient.crm.contacts.basicApi.update(event.object.objectId, { "properties": { "kickbox_sendex": data.sendex } }); // Send response back with the sendex score so the workflow can use it. callback({ outputFields: { sendex_score: data.sendex } }); } catch (err) { console.error(err); // HubSpot will automatically retry if this fails due to rate limits. throw err; } }

Using the Output in Your Workflow

After your custom coded action runs, the sendex_score output becomes available to the rest of your workflow. Here are some ideas for what to do with it:

  • Score ≥ 0.7: Safe to email — continue with your regular workflow
  • Score 0.4 - 0.7: Proceed with caution — maybe send to a re-engagement campaign first
  • Score < 0.4: High risk — consider removing from marketing emails

You can create an if/then branch in your workflow that checks the sendex score and routes contacts accordingly. Clean data, happy marketing team!