Build or update the BlueBubbles external channel plugin for Moltbot (extension package, REST...
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:
- Check environment variable
TODOIST_API_TOKEN - Check if the user has provided a token in the conversation context
- 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 body204- Success, no content400- Bad request (check parameters)401- Authentication failed (check token)403- Forbidden (insufficient permissions)404- Resource not found429- 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 dateGET /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
- Resolve token - Environment, context, or ask user
- Verify authentication - Test with a simple GET request
- Read operations - Execute directly without confirmation
- Write operations - Ask for confirmation before executing
- Handle pagination - Loop with cursor for complete data
- 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.