Stefan Wöhrer, view all articles
25.02.2022
5 min read
Programmcode mit Zahnradsymbol im Hintergrund, das die Automatisierung und Ausführung von Aufgaben symbolisiert.

Hubspot Workflow Custom Code for Creating Tasks with Dynamic Due Dates

Short summary:

Hubspot is gaining popularity as a lean, cloud-based CRM and marketing automation platform, with new features being developed continuously. When out-of-the-box solutions fall short, custom code comes into play.

Hubspot is gaining popularity as a lean, cloud-based CRM and marketing automation platform, with new features being developed continuously. When out-of-the-box solutions fall short, custom code comes into play. In this article, we present a simple custom code solution that allows you to create tasks with a due date based on other date entries (for example, the start date of a deal).

Unfortunately, this is not possible in the standard interface; you can only set the "Days from task creation" option:

Hubspot Task Due Date Standard

The Problem

Our subsidiary, Lean Hive, provides staffing and freelancer placement services. Good support for candidates and clients is crucial in the placement process. We represent each placement in Hubspot as a Deal Each deal has a Start Date, which is filled with the date the hired person starts working.

To ensure a smooth project start and good follow-up, Lean Hive's business development consultants reach out at defined intervals:

  • 1 month and 3 days before the project starts, a call is made with the candidate to clarify any questions and prepare for a successful project start.
  • On the day of the project start, another call takes place, also with the client-side support.
  • 8 days after the project starts, a call is made to check how well the project start is going.
  • 1 month after the project starts, the candidate is invited to lunch for an exchange of experiences and feedback.

Once a deal moves to the Closed Won stage, the corresponding tasks for the mentioned calls/meetings should be created.

The Solution

What is not possible through the GUI can be easily achieved with custom code. First, we need to create our Hubspot API key as a secret and select it for the workflow step:

Next, we need to define 2 properties. These will be passed from the workflow to the custom code:

  • We use the hubspot_owner_id, which is the ID of the deal owner, as the task owner. This way, the task is assigned to the deal owner.
  • We use the start_date as a reference point for our date calculations.

Now we can write the code. First, we write a function called createTask that creates a task in Hubspot:

const hubspot = require('@hubspot/api-client');

const createTask = async (hubspotClient, taskBodyObject) => {    
    const url = `/engagements/v1/engagements`;
    hubspotClient.apiRequest({
        path: url,
        method: 'POST',
        body: taskBodyObject,
        json: true
    });
};

Then we write another helper function that can perform the date calculations. It expects a timestamp (in Hubspot, date entries are stored as timestamps) and adds a number of days to this timestamp. To subtract days, i.e., to create a date that is before the given timestamp, you simply pass a negative number in days. Then we write one last helper function that provides the body for the task to be created:

// Adds "days" days to the timestamp "ts" and returns the new timestamp
const addDaysToTimeStamp = (ts, days) => {
    let ret = new Date(ts);
    ret.setDate(ret.getDate() + days);
    return ret.getTime();
}

In the main method, we can now create new tasks simply as follows:

const buildDealTaskObject = (taskOwner, timestamp, dealId, subject) => {
    return {
        engagement: {
            active: true,
            type: 'TASK',
            ownerId: taskOwner,
            timestamp: timestamp
        },
        associations: {
            dealIds: [dealId],
        },
        metadata: {
            body: subject,
            subject: subject,
            status: "NOT_STARTED",
            forObjectType: "DEAL"
        }
    };
}

Conclusion

exports.main = async (event, callback) => {
    const hubspotClient = new hubspot.Client({
        apiKey: process.env.HAPIKEY
    });

    const taskOwner = parseInt(event.inputFields['hubspot_owner_id']);
    const projectStart = parseInt(event.inputFields['start_date']);
    const dealId = event.object.objectId;
    
    const tasksToCreate = [
        buildDealTaskObject(taskOwner, projectStart, dealId, "Task bei Projektstart"),
        buildDealTaskObject(taskOwner, addDaysToTimeStamp(projectStart, -5), dealId, "Task 5 Tage vor Projektstart"),
        buildDealTaskObject(taskOwner, addDaysToTimeStamp(projectStart, 5), dealId, "Task 5 Tage nach Projektstart"),
    ];

    tasksToCreate.forEach(task => createTask(hubspotClient, task));
}

Custom code solutions should be the last resort. If something can be solved configuratively, it should generally be solved that way. In fact, this problem could also be solved configuratively. For that, you would need 2 additional workflows and 1 dynamic list PER TASK. In our opinion, this is too confusing and hard to maintain. If parameters change, you may need to intervene in 3 configured objects. Therefore, we prefer the custom code solution in this exceptional case.

Here again is

the complete code on Github. Hubspot Automation, Development & Consulting

We offer support around Hubspot in companies - from training to workshops to consulting and project support. If you're interested, just reach out via social media or at

hello@lean-coders.at hello@lean-coders.at

this is the end my friend

Who wrote it

Stefan Wöhrer CEO & Senior Software Architect

Stefan combines technical expertise with entrepreneurial thinking. As CEO and Senior Software Architect, he shapes systems and strategy, oversees projects from conception to implementation, and creates scalable, future-proof solutions with a focus on clear, sustainable structures.