Back

Step by Step Guide to Building a Todoist API Integration in Python

Aug 11, 20247 minute read

Introduction

Hey there, fellow developer! Ready to supercharge your productivity with a custom Todoist integration? You're in the right place. We're going to walk through building a Python-based integration with the Todoist API. It's powerful, it's flexible, and by the end of this guide, you'll have it under your belt.

Prerequisites

Before we dive in, make sure you've got:

  • A Python environment (3.6+ recommended)
  • A Todoist account (obviously!)
  • Your Todoist API token (we'll cover where to find this)

Got all that? Great! Let's get our hands dirty.

Setting up the project

First things first, let's set up our project:

mkdir todoist_integration cd todoist_integration python -m venv env source env/bin/activate # On Windows, use `env\Scripts\activate` pip install requests

We're using requests to handle our HTTP calls. Simple and effective.

Authentication

Alright, let's get you authenticated:

  1. Head to Todoist's Integrations settings
  2. Copy your API token
  3. Create a config.py file and add:
API_TOKEN = "your_token_here"

Now, let's set up our headers:

headers = { "Authorization": f"Bearer {API_TOKEN}" }

Basic API Interactions

Time to make our first API call! Let's fetch your tasks:

import requests from config import API_TOKEN response = requests.get( "https://api.todoist.com/rest/v2/tasks", headers={"Authorization": f"Bearer {API_TOKEN}"} ) if response.status_code == 200: tasks = response.json() for task in tasks: print(f"Task: {task['content']}") else: print(f"Error: {response.status_code}")

Run this, and you should see your tasks printed out. Cool, right?

Creating Tasks

Let's add a new task:

new_task = { "content": "Buy milk", "due_string": "tomorrow at 12:00", "priority": 4 } response = requests.post( "https://api.todoist.com/rest/v2/tasks", headers=headers, json=new_task ) if response.status_code == 200: print("Task added successfully!") else: print(f"Error: {response.status_code}")

Updating Tasks

Forgot to buy almond milk instead? No worries, let's update that task:

task_id = "task_id_here" # You'll get this when creating or fetching tasks updated_task = { "content": "Buy almond milk" } response = requests.post( f"https://api.todoist.com/rest/v2/tasks/{task_id}", headers=headers, json=updated_task ) if response.status_code == 204: print("Task updated successfully!") else: print(f"Error: {response.status_code}")

Deleting Tasks

Decided you don't need milk after all? Let's delete that task:

task_id = "task_id_here" response = requests.delete( f"https://api.todoist.com/rest/v2/tasks/{task_id}", headers=headers ) if response.status_code == 204: print("Task deleted successfully!") else: print(f"Error: {response.status_code}")

Working with Projects

Let's fetch your projects:

response = requests.get( "https://api.todoist.com/rest/v2/projects", headers=headers ) if response.status_code == 200: projects = response.json() for project in projects: print(f"Project: {project['name']}") else: print(f"Error: {response.status_code}")

Advanced Features

Want to get fancy? Let's add a task with a specific due date and label:

new_task = { "content": "Finish Todoist integration", "due_datetime": "2023-06-30T12:00:00Z", "priority": 4, "label_ids": ["label_id_here"] } response = requests.post( "https://api.todoist.com/rest/v2/tasks", headers=headers, json=new_task ) if response.status_code == 200: print("Advanced task added successfully!") else: print(f"Error: {response.status_code}")

Error Handling and Best Practices

Always check those status codes! And remember, Todoist has rate limits. Be kind to their servers:

import time def make_request(url, method="GET", data=None): response = requests.request(method, url, headers=headers, json=data) if response.status_code == 429: # Too Many Requests retry_after = int(response.headers.get('Retry-After', 60)) print(f"Rate limited. Waiting {retry_after} seconds...") time.sleep(retry_after) return make_request(url, method, data) return response

Testing the Integration

Here's a quick test to make sure everything's working:

def test_integration(): # Create a task response = make_request("https://api.todoist.com/rest/v2/tasks", "POST", {"content": "Test task"}) assert response.status_code == 200 task_id = response.json()['id'] # Fetch the task response = make_request(f"https://api.todoist.com/rest/v2/tasks/{task_id}") assert response.status_code == 200 assert response.json()['content'] == "Test task" # Delete the task response = make_request(f"https://api.todoist.com/rest/v2/tasks/{task_id}", "DELETE") assert response.status_code == 204 print("All tests passed!") test_integration()

Conclusion

And there you have it! You've just built a Todoist API integration in Python. You can now create, read, update, and delete tasks, work with projects, and even handle advanced features. The sky's the limit from here!

Remember, this is just scratching the surface. The Todoist API has so much more to offer. Why not try integrating with labels next? Or maybe sync with a calendar app?

Resources

Happy coding, and may your tasks always be organized!