Automating task creation in ToDoIst

I am a person who likes to have to-do lists to make sure that I stay on top of my activities and that I am moving them forward. In the past, I have tried a dozen various task management tools, but ultimately I have fallen in love with the one called ToDoIst. A pretty simple, yet powerful task manager. There are however some interactions that I don’t like which is why I have used my skills to fill in the holes (metaphorically speaking).

Introduction to ToDoIst

ToDoIst is an all-purpose task manager application that is pretty simple and easy to use, yet it offers a lot of functionality if a user is willing to dive deep into it. The pricing is acceptable and the company behind the app updates it regularly. It also includes extensions and various automation features that allow you to create tasks easily. I particularly like their pattern recognition. For example, if I create a new task with #Personal, it will automatically put the task under Personal project. On top of that, I can type @Reading which adds the tag Reading to the card. Project and tags can both be used for more detailed filtering of the list. After that, we can type our task name and set the due date. If, for example, you would the task to be run every day at 2 PM, just type it. ToDoIst will naturally recognize this pattern and automagically create the task for you.

My problem with ToDoIst scheduled actions

There are many things that I like about ToDoIst, but at the same time, there are some of them that are bugging me. For example, if I create a recurring task that occurs daily and I forget to complete it, the task becomes overdue and it will no longer get generated on the new day. What I would like to have is to have the scheduled tasks generate a new instance every time instead of refreshing the due date.

Unfortunately, ToDoIst doesn’t have this built-in. Luckily for us, this could be achieved using tools such as Zapier. But what if I don’t want to use the Zapier? Then I would need the same kind of a scheduler that would be able to create new events and send them to the ToDoIst via an API. So let’s do just that.

ToDoIst API

Almost all the services today have an available and accessible API and ToDoIst is no different. You can send the requests to this URL:

https://api.todoist.com/rest/v2/tasks

To authenticate yourself the API key is needed. The key can be obtained in the Settings -> Integrations -> Developer -> API token:

Create a task(s)

Tasks in ToDoIst are stored as a dictionary. There are some predefined keys such as contentpriority or labels. Most of the keys are not mandatory, but each task should have a non-empty content and project_id. In this example, you can see, how I have created two tasks and stored them in an array called tasksArray. If you are interested in how to get the value for project_id, you can retrieve it by displaying the output of the API request in your browser.

var tasksArray = [
  {
        "content": "First task",
        "project_id": "2314367911",
        "priority": 2,
        "labels": [
            "Automation"
        ]
    },
    {
        "content": "Second task",
        "project_id": "2314367911",
        "labels": [
            "Automation",
            "Socials"
        ]
    },
];

Create a script for creating the events

Now that we know how to create new tasks, we can put together a simple script that will just push new events into the ToDoIst.

function createMultipleTodoistTasks(tasks) {
    if (!Array.isArray(tasks)) {
      Logger.log("Error: Expected an array of tasks as an input.");
      return;
    }

    // Connection
    var token = PropertiesService.getScriptProperties().getProperty('TODOIST_TOKEN');
    var endpoint = "https://api.todoist.com/rest/v2/tasks";

    // Format today's date as YYYY-MM-DD
    var today = new Date();
    var formattedDate = today.getFullYear() + '-' + (today.getMonth() + 1).toString().padStart(2, '0') + '-' + today.getDate().toString().padStart(2, '0');

    for (var i = 0; i < tasks.length; i++) {
        var taskData = tasks[i];

        if (!taskData.due_date) {
            taskData.due_date = formattedDate;
        }

        var options = {
            "method": "post",
            "headers": {
                "Authorization": "Bearer " + token,
                "Content-Type": "application/json"
            },
            "payload": JSON.stringify(taskData)
        };

        try {
            var response = UrlFetchApp.fetch(endpoint, options);
            Logger.log(response.getContentText());
        } catch (e) {
            Logger.log('Error creating task: ' + taskData.content + '. Error: ' + e.toString());
        }
    }
}

You might be curious about this line of code var token = PropertiesService.getScriptProperties().getProperty('TODOIST_TOKEN'); and the TODOIST_TOKEN part. Usually, it is not a good practice to store secrets such as API keys, usernames and passwords in the code as it would be easily readable. One of the better ways would be to use an environment property to store the API key which we did.

Running and scheduling a script

There are multiple ways to store, run and schedule our script. For projects like this one, I like to use Google Apps Scripts which allows for a limited amount of executions daily. Let’s start by creating a new project.

The code can be placed into the Code.gs file. Next, let’s set up the TODOIST_TOKEN by going into Settings and editing the script properties. Fill in the property name and the value of your API key that you have obtained in the ToDoIst settings.

Now the only thing left is to set up an automated scheduling. For that, please access the Triggers and select the Add Trigger button in the bottom right corner. Here we can set the time at which the script will be executed.

If you have read so far, you might want to follow me here on Hashnode. Feel free to connect with me over at LinkedIn or Mastodon.