| name | todoist |
| description | Manage Todoist tasks, projects, sections, labels, and comments via the Todoist API v1. Use when the user asks to add/list/complete/update tasks, manage projects, check what's due today, or anything related to their Todoist task manager. |
Todoist Skill
Manage Todoist via the REST API v1. Zero dependencies — just curl.
Authentication
The API key is stored in $OC_TODOIST_API_KEY (loaded from ~/.openclaw/.env via BWS).
All requests use:
Authorization: Bearer $OC_TODOIST_API_KEY
API Base URL
https://api.todoist.com/api/v1
Important: The old /rest/v2/ endpoints are deprecated (HTTP 410). Always use /api/v1/.
Pagination
The v1 API uses cursor-based pagination. Responses include:
{
"results": [...],
"next_cursor": "string or null"
}
Pass ?cursor=<next_cursor> to get the next page. null means no more results.
Confirmation Requirement
Always ask the user for confirmation before:
- Deleting tasks, projects, sections, labels, or comments
- Completing tasks (mark as done)
- Bulk updates
No confirmation needed for:
- Listing/reading tasks, projects, labels
- Creating new tasks, projects, sections
- Viewing task details
Quick Reference
Tasks
List tasks (all or filtered):
curl -s "https://api.todoist.com/api/v1/tasks" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results'
List tasks by filter (today, overdue, etc.):
curl -s "https://api.todoist.com/api/v1/tasks/filter?query=today" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results'
Common filter queries:
today — due today + overdue
overdue — only overdue
tomorrow — due tomorrow
next 7 days — upcoming week
#ProjectName — tasks in a project
@label — tasks with a label
p1 / p2 / p3 / p4 — by priority
assigned to: me — assigned to user
no date — tasks without due dates
Get a single task:
curl -s "https://api.todoist.com/api/v1/tasks/<TASK_ID>" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq
Quick add (natural language parsing):
curl -s -X POST "https://api.todoist.com/api/v1/tasks/quick_add" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"text": "Buy milk tomorrow p1 #Personal"}' | jq
Quick add supports: due dates (tomorrow, next monday, Jan 15), priority (p1-p4), project (#ProjectName), labels (@label), section (/SectionName).
Create task (explicit fields):
curl -s -X POST "https://api.todoist.com/api/v1/tasks" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Task title",
"description": "Optional details",
"project_id": "PROJECT_ID",
"section_id": "SECTION_ID",
"parent_id": "PARENT_TASK_ID",
"labels": ["label1", "label2"],
"priority": 4,
"due_string": "tomorrow at 3pm",
"duration": 30,
"duration_unit": "minute"
}' | jq
Priority mapping (API vs UI):
- API
priority: 4 = Todoist UI p1 (urgent/red)
- API
priority: 3 = Todoist UI p2 (orange)
- API
priority: 2 = Todoist UI p3 (blue)
- API
priority: 1 = Todoist UI p4 (no color/normal)
Due date fields (use only ONE):
due_string — natural language: "tomorrow at 3pm", "every friday"
due_date — date only: "2026-03-15"
due_datetime — with time: "2026-03-15T15:00:00Z"
Update task:
curl -s -X POST "https://api.todoist.com/api/v1/tasks/<TASK_ID>" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Updated title", "priority": 3}' | jq
Complete task:
curl -s -X POST "https://api.todoist.com/api/v1/tasks/<TASK_ID>/close" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY"
Reopen task:
curl -s -X POST "https://api.todoist.com/api/v1/tasks/<TASK_ID>/reopen" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY"
Delete task:
curl -s -X DELETE "https://api.todoist.com/api/v1/tasks/<TASK_ID>" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY"
Move task to another project:
curl -s -X POST "https://api.todoist.com/api/v1/tasks/<TASK_ID>/move" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"project_id": "TARGET_PROJECT_ID"}' | jq
Projects
List all projects:
curl -s "https://api.todoist.com/api/v1/projects" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results[] | {id, name, color}'
Create project:
curl -s -X POST "https://api.todoist.com/api/v1/projects" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "New Project", "color": "blue", "view_style": "list"}' | jq
Colors: berry_red, red, orange, yellow, olive_green, lime_green, green, mint_green, teal, sky_blue, light_blue, blue, grape, violet, lavender, magenta, salmon, charcoal, grey, taupe.
Delete project:
curl -s -X DELETE "https://api.todoist.com/api/v1/projects/<PROJECT_ID>" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY"
Sections
List sections in a project:
curl -s "https://api.todoist.com/api/v1/sections?project_id=<PROJECT_ID>" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results[] | {id, name, order}'
Create section:
curl -s -X POST "https://api.todoist.com/api/v1/sections" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Section Name", "project_id": "PROJECT_ID"}' | jq
Labels
List all labels:
curl -s "https://api.todoist.com/api/v1/labels" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results[] | {id, name, color}'
Create label:
curl -s -X POST "https://api.todoist.com/api/v1/labels" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "urgent", "color": "red"}' | jq
Comments
List comments on a task:
curl -s "https://api.todoist.com/api/v1/comments?task_id=<TASK_ID>" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results'
Add comment to a task:
curl -s -X POST "https://api.todoist.com/api/v1/comments" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" \
-H "Content-Type: application/json" \
-d '{"task_id": "<TASK_ID>", "content": "Comment text"}' | jq
Completed Tasks
Get recently completed tasks:
curl -s "https://api.todoist.com/api/v1/tasks/completed_by_completion_date?since=2026-03-01T00:00:00Z" \
-H "Authorization: Bearer $OC_TODOIST_API_KEY" | jq '.results'
Adhish's Todoist Setup
| Project | ID | Purpose |
|---|
| Inbox | 6V6m8jrmfCgJC6wF | Default capture |
| Personal | 6g8JfXRCRq3h6w23 | Personal tasks |
| Elastic | 6g8Jc632MgFMRXX5 | Work tasks |
Labels: read
Best Practices
- Use quick_add for natural language — it handles date parsing, project matching, and priority better than manual field construction
- Prefer filter queries for listing tasks — they mirror what the user sees in Todoist
- Always parse jq output — present tasks in a clean, readable format to the user
- Priority is inverted in the API vs UI — remember
4 = urgent (p1), 1 = normal (p4)
- Don't put due dates in content or description — always use
due_string/due_date/due_datetime
- Don't put duration in due_string — use
duration + duration_unit fields separately
- Task IDs are alphanumeric strings in v1 (not numeric like v2)
Fallback: Pending Tasks Queue
When a Todoist API call fails (network, rate limit, auth error), never silently drop the task. Write it to the local pending queue:
File: memory/todoist-pending.md
Format:
## Pending Todoist Tasks
- [ ] `Create` | project: Elastic | content: "Fix ElasticGPT metrics" | priority: p2 | due: 2026-03-15 | source: heartbeat 13:30
- [ ] `Create` | project: Personal | content: "Book dentist appointment" | due: tomorrow | source: email scan 09:20
Rules:
- On any Todoist write failure → append to
memory/todoist-pending.md immediately
- Daily self-review cron checks if
memory/todoist-pending.md exists and has entries
- Retries each pending task against the API
- On success → remove the line and log to daily notes
- On repeated failure (3+ retries across cycles) → notify Adhish via Telegram
This ensures zero task loss. Worst case: delayed by one review cycle (~24h).
Error Handling
- 401 — Invalid or expired API token
- 403 — Insufficient permissions
- 404 — Resource not found
- 410 — Deprecated endpoint (you're hitting /rest/v2 — switch to /api/v1)
- 429 — Rate limited (respect
Retry-After header)
- 500+ — Server error, retry with backoff
Rate limit: ~450 requests per 15 minutes per user.
Output Formatting
When presenting tasks to the user, format as:
☐ Task name (p1) — due: tomorrow — #Project
Description text if any
For completed tasks:
☑ Task name — completed: Mar 12
Keep it scannable. Don't dump raw JSON unless the user asks for it.