intellectronica

todoist-api

144
10
# Install this skill:
npx skills add intellectronica/agent-skills --skill "todoist-api"

Install specific skill from multi-skill repository

# Description

This skill provides instructions for interacting with the Todoist REST API v2 using curl and jq. It covers authentication, CRUD operations for tasks/projects/sections/labels/comments, pagination handling, and requires confirmation before destructive actions. Use this skill when the user wants to read, create, update, or delete Todoist data via the API.

# SKILL.md


name: todoist-api
description: This skill provides instructions for interacting with the Todoist REST API v2 using curl and jq. It covers authentication, CRUD operations for tasks/projects/sections/labels/comments, pagination handling, and requires confirmation before destructive actions. Use this skill when the user wants to read, create, update, or delete Todoist data via the API.


Todoist API Skill

This skill provides procedural guidance for working with the Todoist REST API v2 via curl and jq.

Authentication

Token Resolution

Resolve the API token in this order:

  1. Check environment variable TODOIST_API_TOKEN
  2. Check if the user has provided a token in the conversation context
  3. If neither is available, use AskUserQuestion (or similar tool) to request the token from the user

To verify a token exists in the environment:

[ -n "$TODOIST_API_TOKEN" ] && echo "Token available" || echo "Token not set"

Making Authenticated Requests

All requests require the Authorization header with Bearer token:

curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/ENDPOINT"

For POST requests with JSON body, include Content-Type:

curl -s -X POST \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}' \
  "https://api.todoist.com/rest/v2/ENDPOINT"

Base URL

All REST API v2 endpoints use: https://api.todoist.com/rest/v2/

Confirmation Requirement

Before executing any destructive action (DELETE, close, update, archive), always ask the user for confirmation using AskUserQuestion or similar tool. A single confirmation suffices for a logical group of related actions.

Destructive actions include:
- Deleting tasks, projects, sections, labels, or comments
- Closing (completing) tasks
- Updating existing resources
- Archiving projects

Read-only operations (GET requests) do not require confirmation.

Endpoints Reference

Tasks

Operation Method Endpoint
List active tasks GET /tasks
Get task GET /tasks/{id}
Create task POST /tasks
Update task POST /tasks/{id}
Close task POST /tasks/{id}/close
Reopen task POST /tasks/{id}/reopen
Delete task DELETE /tasks/{id}

Task filters (query params for GET /tasks):
- project_id - Filter by project
- section_id - Filter by section
- label - Filter by label name
- filter - Todoist filter query (e.g., "today", "overdue")

Task creation/update fields:
- content (required for creation) - Task text
- description - Additional details
- project_id, section_id, parent_id - Organisation
- priority - 1 (normal) to 4 (urgent)
- due_string - Natural language ("tomorrow", "every monday")
- due_date - YYYY-MM-DD format
- due_datetime - RFC3339 format
- labels - Array of label names
- assignee_id - For shared projects
- duration, duration_unit - Estimated time

Projects

Operation Method Endpoint
List projects GET /projects
Get project GET /projects/{id}
Create project POST /projects
Update project POST /projects/{id}
Archive project POST /projects/{id}/archive
Unarchive project POST /projects/{id}/unarchive
Delete project DELETE /projects/{id}
List collaborators GET /projects/{id}/collaborators

Project fields:
- name (required for creation)
- parent_id - For nested projects
- color - Colour name (e.g., "berry_red", "blue")
- is_favorite - Boolean
- view_style - "list" or "board"

Sections

Operation Method Endpoint
List sections GET /sections
Get section GET /sections/{id}
Create section POST /sections
Update section POST /sections/{id}
Delete section DELETE /sections/{id}

Section filters (query params for GET):
- project_id - Filter by project (recommended)

Section fields:
- name (required)
- project_id (required for creation)
- order - Position within project

Labels

Operation Method Endpoint
List personal labels GET /labels
Get label GET /labels/{id}
Create label POST /labels
Update label POST /labels/{id}
Delete label DELETE /labels/{id}
List shared labels GET /shared_labels
Rename shared label POST /shared_labels/{name}/rename
Remove shared label DELETE /shared_labels/{name}

Label fields:
- name (required)
- color - Colour name
- order - Display order
- is_favorite - Boolean

Comments

Operation Method Endpoint
List comments GET /comments
Get comment GET /comments/{id}
Create comment POST /comments
Update comment POST /comments/{id}
Delete comment DELETE /comments/{id}

Comment filters (query params for GET):
- task_id - Comments on a task (required if no project_id)
- project_id - Comments on a project (required if no task_id)

Comment fields:
- content (required) - Markdown supported
- task_id or project_id (one required for creation)

Pagination

Some endpoints return paginated results. Handle pagination by checking for a next_cursor field in the response and making subsequent requests with the cursor parameter.

Pagination Pattern

# Initial request
response=$(curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/ENDPOINT")

# Check for more results
next_cursor=$(echo "$response" | jq -r '.next_cursor // empty')

# If cursor exists, fetch next page
if [ -n "$next_cursor" ]; then
  curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
    "https://api.todoist.com/rest/v2/ENDPOINT?cursor=$next_cursor"
fi

Complete Data Retrieval Loop

To retrieve all data when pagination is involved:

all_results="[]"
cursor=""

while true; do
  if [ -z "$cursor" ]; then
    response=$(curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
      "https://api.todoist.com/rest/v2/ENDPOINT")
  else
    response=$(curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
      "https://api.todoist.com/rest/v2/ENDPOINT?cursor=$cursor")
  fi

  # Merge results (adjust .items or root array based on endpoint)
  items=$(echo "$response" | jq '.items // .')
  all_results=$(echo "$all_results $items" | jq -s 'add')

  # Check for next page
  cursor=$(echo "$response" | jq -r '.next_cursor // empty')
  has_more=$(echo "$response" | jq -r '.has_more // false')

  if [ "$has_more" != "true" ] || [ -z "$cursor" ]; then
    break
  fi
done

echo "$all_results"

Common Patterns

List All Tasks in a Project

curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/tasks?project_id=PROJECT_ID" | jq '.'

Create a Task with Due Date

curl -s -X POST \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content": "Task name", "due_string": "tomorrow", "priority": 2}' \
  "https://api.todoist.com/rest/v2/tasks"

Complete a Task

curl -s -X POST \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/tasks/TASK_ID/close"

Get Today's Tasks

curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/tasks?filter=today" | jq '.'

Get Overdue Tasks

curl -s -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/tasks?filter=overdue" | jq '.'

Error Handling

Check HTTP status codes and handle errors appropriately:

  • 200 - Success with response body
  • 204 - Success, no content
  • 400 - Bad request (check parameters)
  • 401 - Authentication failed (check token)
  • 403 - Forbidden (insufficient permissions)
  • 404 - Resource not found
  • 429 - Rate limited (wait and retry)
  • 5xx - Server error (safe to retry)

Example with Error Handling

response=$(curl -s -w "\n%{http_code}" \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  "https://api.todoist.com/rest/v2/tasks")

http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')

if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
  echo "$body" | jq '.'
else
  echo "Error: HTTP $http_code"
  echo "$body"
fi

Idempotency

For safe retries on write operations, include the X-Request-Id header (max 36 characters):

curl -s -X POST \
  -H "Authorization: Bearer $TODOIST_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Request-Id: $(uuidgen)" \
  -d '{"content": "New task"}' \
  "https://api.todoist.com/rest/v2/tasks"

Duplicate requests with the same X-Request-Id are discarded by the server.

Completed Tasks

The REST API v2 /tasks endpoint returns only active tasks. For completed tasks, use the Sync API or the newer unified API v1 endpoints:

  • GET /tasks/completed/by_completion_date - Retrieve by completion date
  • GET /tasks/completed/by_due_date - Retrieve by original due date

See references/completed-tasks.md for details on retrieving completed task history.

Additional Reference

For detailed information on specific topics, consult:
- references/completed-tasks.md - Retrieving completed task history
- references/filters.md - Todoist filter query syntax

Workflow Summary

  1. Resolve token - Environment, context, or ask user
  2. Verify authentication - Test with a simple GET request
  3. Read operations - Execute directly without confirmation
  4. Write operations - Ask for confirmation before executing
  5. Handle pagination - Loop with cursor for complete data
  6. Parse responses - Use jq to extract and format data

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.