Todoist ExecModule
Overview
TodoistModule connects ValkyrAI workflows to Todoist API v1 through the native map I/O ExecModule ABI. Workflow Studio discovers it as TodoistModule; API and OAuth access tokens are resolved only from an encrypted IntegrationAccount.
This release provides project, collaborator, section, task, and comment operations:
list_projects,get_project,list_collaborators,list_sectionslist_tasks,get_task,create_task,update_taskclose_task,reopen_task,delete_tasklist_comments,add_comment
List operations follow Todoist's opaque cursor pagination. Provider errors are bounded and redacted. Only reads are eligible for automatic retry; creates, updates, close/reopen actions, comments, and deletion run once so an ambiguous timeout cannot repeat a mutation.
Usage
- Create a dedicated Todoist automation identity or OAuth application.
- Grant only the project and task access needed by the workflow.
- Store the Todoist API token or OAuth access token in the encrypted
apiKeyfield of anIntegrationAccount. - Bind that account through
ExecModuleConfig.authConfig.integrationAccount. - Add
TodoistModuleto a workflow, select an operation, and use IDs returned by discovery operations.
Workflow inputs can provide resource IDs, task fields, filters, pagination controls, and explicit destructive confirmation. They cannot provide credentials or redirect requests away from Todoist's trusted API endpoint.
Inputs
| Name | Type | Requirement | Default | Description | Constraints |
|---|---|---|---|---|---|
operation | string | Required | None | Operation to execute. | One of the thirteen operations above. |
projectId | string | Operation-specific | None | Todoist project ID. | Required for project reads/collaborators; optional task, section, and comment scope. |
sectionId | string | Optional | None | Todoist section ID. | Filters tasks or assigns a created task. |
taskId | string | Operation-specific | None | Todoist task ID. | Required for task reads/updates/close/reopen/delete and task comments. |
parentId | string | Optional | None | Parent task ID. | Filters subtasks or assigns a created task. |
content | string | Required for create | None | Task title/content. | 1–500 characters for creation. |
description | string | Optional | None | Plain-text task description. | Maximum 16,384 characters. |
task | object or JSON string | Optional | None | Additional Todoist task fields. | 256 KiB cap; allowlisted fields only. |
labels | array or JSON string | Optional | None | Task label names. | At most 100 bounded strings. |
priority | integer | Optional | Omitted | Todoist priority. | 1–4. |
dueString | string | Optional | None | Natural-language due expression. | Maximum 1,024 characters. |
dueDate | date | Optional | None | Due date. | YYYY-MM-DD. |
dueDatetime | timestamp | Optional | None | Due timestamp. | ISO 8601 with an offset. |
label | string | Optional | None | Task-list label filter. | Maximum 255 characters. |
commentText | string | Required for comment | None | Plain-text task or project comment. | 1–15,000 characters. |
cursor | string | Optional | None | Opaque continuation token. | Maximum 4,096 characters. |
limit | integer | Optional | 50 | Maximum returned items. | 1–10,000; provider page size is at most 200. |
returnAll | boolean | Optional | false | Continue until exhaustion. | Safety-capped at 10,000 items. |
requestId | string | Optional | None | Caller correlation/idempotency key. | Maximum 128 characters; sent as X-Request-Id. |
confirmDelete | boolean | Required for deletion | false | Permanent-delete acknowledgement. | Must be true before delete_task sends a request. |
The task object accepts only content, description, project_id, section_id, parent_id, order, labels, priority, assignee_id, due_string, due_date, due_datetime, due_lang, duration, duration_unit, and deadline_date. Typed inputs override matching fields. Only one due selector may be present.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation name. |
attempts | integer | Always | Total Todoist HTTP attempts across all pages. |
httpStatus | integer | Provider response received | Last HTTP status. |
data | object | Single-resource/mutation success | Resource or empty object for 204 responses. |
id / url | string | Resource response includes it | Convenience resource fields. |
items / count | array / integer | List success | Returned resources and count. |
hasMore / nextCursor | boolean / string | List success | Continuation state and opaque cursor. |
requestId | string | Provider supplies one | Provider trace/correlation reference. |
error | object | Failure | Safe {code, message, httpStatus?, retryable} details. |
Tokens and authorization headers never enter outputs. Provider messages pass through the shared workflow sensitive-data policy.
IntegrationAccount Requirements
| Setting | API token or OAuth requirement |
|---|---|
| Provider | Todoist or Todoist OAuth 2.0 |
| Authentication | Authorization: Bearer <token> |
accountName | Human-readable automation identity label |
apiKey | Preferred encrypted SecureField containing the token |
password | Legacy token fallback only; prefer apiKey |
status | ready or unset legacy status; closed and error fail closed |
An API token acts with its owning user's permissions. Prefer a dedicated automation identity and explicitly shared projects. Use data:read for read-only OAuth workflows and data:read_write for task/comment mutations. Token refresh happens before execution; workflow payloads cannot replace credentials.
Configuration
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:todoist-release-ops"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000,
"jitter": false
},
"executionConfig": {"timeoutMs": 30000},
"payloadConfig": {
"parameters": "{\"operation\":\"list_tasks\",\"projectId\":\"6XGgm6PHrGgMpCFX\",\"label\":\"next_action\",\"limit\":50}"
}
}
The integration account value is symbolic. Persisted workflows use the generated relationship, never a plaintext token.
Operations
| Operation | Todoist behavior | Side effect |
|---|---|---|
list_projects / get_project | Lists active projects or reads one project. | Read-only; safe retries. |
list_collaborators | Lists project collaborators. | Read-only; safe retries. |
list_sections | Lists sections, optionally by project. | Read-only; safe retries. |
list_tasks / get_task | Lists filtered active tasks or reads one task. | Read-only; safe retries. |
create_task | Creates a bounded task. | New task; single attempt. |
update_task | Updates explicitly supplied fields. | Mutation; single attempt. |
close_task / reopen_task | Completes or restores a task. | Reversible mutation; single attempt. |
delete_task | Permanently deletes a task. | Irreversible; confirmation required. |
list_comments | Lists one task's or project's comments. | Read-only; safe retries. |
add_comment | Creates one task or project comment. | New comment; single attempt. |
Errors and Failure Modes
| Code | Typical cause | Retryable | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Missing ID/content, invalid date/JSON, unsupported field, ambiguous comment scope, empty update, or absent confirmation. | No | Correct the input; no unsafe request was sent. |
UNSUPPORTED_OPERATION | Unknown operation. | No | Select a documented operation. |
INTEGRATION_ACCOUNT_REQUIRED | No account bound. | No | Bind a Todoist IntegrationAccount. |
INTEGRATION_ACCOUNT_NOT_READY | Account status is closed/error. | No | Repair or reconnect the account. |
TODOIST_HTTP_400 | Invalid field or provider validation. | No | Correct the request using the bounded message. |
TODOIST_HTTP_401 / 403 | Invalid token, scope, or shared-project access. | No | Rotate/refresh credentials or grant minimum access. |
TODOIST_HTTP_404 | ID is wrong, completed, archived, or hidden. | No | Re-run discovery under the same account. |
TODOIST_HTTP_429 / 5xx | Rate limit or transient failure. | Yes for reads | Honor Retry-After; reconcile writes before retry. |
NETWORK_ERROR | Timeout, DNS, TLS, or connectivity failure. | Yes for reads | Verify connectivity and inspect writes before retry. |
RESPONSE_TOO_LARGE | Response exceeded 5 MiB. | No | Narrow filters or lower the limit. |
INVALID_PROVIDER_RESPONSE | Paginated response lacked results. | No | Use requestId and verify API compatibility. |
Example
{
"operation": "create_task",
"projectId": "6XGgm6PHrGgMpCFX",
"sectionId": "6fFPHV272WWh3gpW",
"content": "Verify public Todoist ExecModule launch",
"description": "Confirm documentation, article, image, and public READ grants.",
"labels": ["execmodule", "release"],
"priority": 4,
"dueDate": "2026-08-14",
"requestId": "todoist-launch-verification-20260807"
}
Expected result:
{
"status": "success",
"operation": "create_task",
"attempts": 1,
"httpStatus": 200,
"id": "6XGgmFVcrG5RRjVr",
"data": {
"id": "6XGgmFVcrG5RRjVr",
"content": "Verify public Todoist ExecModule launch",
"priority": 4
}
}
Notes
- Pagination: list operations request at most 200 items per page and stop at
limit, provider exhaustion, or 10,000 items. ReusenextCursoronly with identical filters. - Rate limits: reads retry HTTP 408, 429, 500, 502, 503, and 504 per policy and
Retry-After. Mutations never retry automatically. - API limits: Todoist applies a 1 MiB POST-body limit and plan-specific limits. The module caps structured tasks at 256 KiB and responses at 5 MiB.
- Idempotency: writes are single-attempt. Supply a durable
requestIdand reconcile state before repeating an ambiguous write. - Consistency: a created or reopened task may take time to appear in every filtered view. Use its returned ID immediately.
- Destructive behavior:
delete_taskis permanent and requiresconfirmDelete=true. Preferclose_taskfor reversible completion. - Authentication: bearer tokens remain in IntegrationAccount SecureFields and are redacted from errors and outputs.
- External verification: request construction, cursor pagination, validation, redaction, retry safety, and metadata discovery are tested locally. Live service permissions require a real Todoist account and are deferred.
- Deferred operations: project/section mutations, filter queries, completed-task history, labels, reminders, attachments, activity logs, triggers, OAuth refresh, and arbitrary raw requests.
- Functional reference: n8n's Todoist integration demonstrates agent-oriented project and task automation; this module implements its highest-value semantics through ValkyrAI's secure native ABI against Todoist API v1.