TickTick
Access the TickTick API with managed OAuth authentication. Manage tasks and projects with full CRUD operations.
Quick Start
# List all projects
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/ticktick/open/v1/project')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Base URL
https://api.maton.ai/ticktick/{native-api-path}
Maton proxies requests to api.ticktick.com and automatically injects your OAuth token.
Authentication
All requests require the Maton API key in the Authorization header:
Authorization: Bearer $MATON_API_KEY
Environment Variable: Set your API key as MATON_API_KEY:
export MATON_API_KEY="YOUR_API_KEY"
Getting Your API Key
- Sign in or create an account at maton.ai
- Go to maton.ai/settings
- Copy your API key
Connection Management
Manage your TickTick OAuth connections at https://api.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=ticktick&status=ACTIVE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Create Connection
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'ticktick'}).encode()
req = urllib.request.Request('https://api.maton.ai/connections', data=data, method='POST')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Content-Type', 'application/json')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Get Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Response:
{
"connection": {
"connection_id": "{connection_id}",
"status": "ACTIVE",
"creation_time": "2026-02-07T09:55:40.786711Z",
"last_updated_time": "2026-02-07T09:56:30.403237Z",
"url": "https://connect.maton.ai/?session_token=...",
"app": "ticktick",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
Delete Connection
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections/{connection_id}', method='DELETE')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Specifying Connection
If you have multiple TickTick connections, specify which one to use with the Maton-Connection header:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/ticktick/open/v1/project')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always include this header to ensure requests go to the intended account.
Security & Permissions
- Access is scoped to tasks, projects, and task lists within the connected TickTick account.
- All write operations require explicit user approval. Before executing any create, update, or delete call, confirm the target resource and intended effect with the user.
API Reference
Project Operations
List Projects
GET /ticktick/open/v1/project
Response:
[
{
"id": "6984773291819e6d58b746a8",
"name": "🏡Memo",
"sortOrder": 0,
"viewMode": "list",
"kind": "TASK"
},
{
"id": "6984773291819e6d58b746a9",
"name": "🦄Wishlist",
"sortOrder": -1099511627776,
"viewMode": "list",
"kind": "TASK"
}
]
Get Project with Tasks
GET /ticktick/open/v1/project/{projectId}/data
Response:
{
"project": {
"id": "69847732b8e5e969f70e7460",
"name": "👋Welcome",
"sortOrder": -3298534883328,
"viewMode": "list",
"kind": "TASK"
},
"tasks": [
{
"id": "69847732b8e5e969f70e7464",
"projectId": "69847732b8e5e969f70e7460",
"title": "Sample task",
"content": "Task description",
"priority": 0,
"status": 0,
"tags": [],
"isAllDay": false
}
],
"columns": [
{
"id": "69847732b8e5e969f70e7463",
"projectId": "69847732b8e5e969f70e7460",
"name": "Getting Start",
"sortOrder": -2199023255552
}
]
}
Create Project
POST /ticktick/open/v1/project
Content-Type: application/json
{
"name": "My New Project",
"viewMode": "list"
}
Response:
{
"id": "69870cbe8f08b4a6770a38d3",
"name": "My New Project",
"sortOrder": 0,
"viewMode": "list",
"kind": "TASK"
}
viewMode options:
list- List viewkanban- Kanban board viewtimeline- Timeline view
Delete Project
DELETE /ticktick/open/v1/project/{projectId}
Returns empty response on success (status 200).
Task Operations
Get Task
GET /ticktick/open/v1/project/{projectId}/task/{taskId}
Response:
{
"id": "69847732b8e5e969f70e7464",
"projectId": "69847732b8e5e969f70e7460",
"sortOrder": -1099511627776,
"title": "Task title",
"content": "Task description/notes",
"timeZone": "Asia/Shanghai",
"isAllDay": true,
"priority": 0,
"status": 0,
"tags": [],
"columnId": "69847732b8e5e969f70e7461",
"etag": "2sayfdsh",
"kind": "TEXT"
}
Create Task
POST /ticktick/open/v1/task
Content-Type: application/json
{
"title": "New task",
"projectId": "6984773291819e6d58b746a8",
"content": "Task description",
"priority": 0,
"dueDate": "2026-02-15T10:00:00+0000",
"isAllDay": false
}
Response:
{
"id": "69870cb08f08b86b38951175",
"projectId": "6984773291819e6d58b746a8",
"sortOrder": -1099511627776,
"title": "New task",
"timeZone": "America/Los_Angeles",
"isAllDay": false,
"priority": 0,
"status": 0,
"tags": [],
"etag": "gl7ibhor",
"kind": "TEXT"
}
Priority values:
0- None1- Low3- Medium5- High
Update Task
POST /ticktick/open/v1/task/{taskId}
Content-Type: application/json
{
"id": "69870cb08f08b86b38951175",
"projectId": "6984773291819e6d58b746a8",
"title": "Updated task title",
"priority": 1
}
Response:
{
"id": "69870cb08f08b86b38951175",
"projectId": "6984773291819e6d58b746a8",
"title": "Updated task title",
"priority": 1,
"status": 0,
"etag": "hmb7uk8c",
"kind": "TEXT"
}
Complete Task
POST /ticktick/open/v1/project/{projectId}/task/{taskId}/complete
Returns empty response on success (status 200).
Delete Task
DELETE /ticktick/open/v1/project/{projectId}/task/{taskId}
Returns empty response on success (status 200).
Task Fields
| Field | Type | Description |
|---|---|---|
id | string | Task ID |
projectId | string | Parent project ID |
title | string | Task title |
content | string | Task description/notes (Markdown supported) |
priority | integer | Priority: 0=None, 1=Low, 3=Medium, 5=High |
status | integer | 0=Active, 2=Completed |
dueDate | string | Due date in ISO 8601 format |
startDate | string | Start date in ISO 8601 format |
isAllDay | boolean | Whether task is all-day |
timeZone | string | Timezone (e.g., "America/Los_Angeles") |
tags | array | List of tag names |
columnId | string | Kanban column ID (if applicable) |
sortOrder | number | Sort order within project |
kind | string | Task type: "TEXT", "CHECKLIST" |
Code Examples
JavaScript
// List all projects
const response = await fetch(
'https://api.maton.ai/ticktick/open/v1/project',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
const projects = await response.json();
// Create a task
const createResponse = await fetch(
'https://api.maton.ai/ticktick/open/v1/task',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
title: 'New task',
projectId: 'PROJECT_ID'
})
}
);
Python
import os
import requests
# List all projects
response = requests.get(
'https://api.maton.ai/ticktick/open/v1/project',
headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
)
projects = response.json()
# Create a task
response = requests.post(
'https://api.maton.ai/ticktick/open/v1/task',
headers={
'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}',
'Content-Type': 'application/json'
},
json={
'title': 'New task',
'projectId': 'PROJECT_ID'
}
)
Notes
- The Open API provides access to tasks and projects only
- Habits, focus/pomodoro, and tags are not available through the Open API
- Task
statusvalues: 0 = Active, 2 = Completed - Priority values: 0 = None, 1 = Low, 3 = Medium, 5 = High
- Dates use ISO 8601 format with timezone offset (e.g.,
2026-02-15T10:00:00+0000) viewModefor projects:list,kanban, ortimeline- The
columnsfield in project data is used for Kanban board columns - IMPORTANT: When piping curl output to
jqor other commands, environment variables like$MATON_API_KEYmay not expand correctly in some shell environments
Error Handling
| Status | Meaning |
|---|---|
| 400 | Missing TickTick connection or invalid request |
| 401 | Invalid or missing Maton API key |
| 404 | Resource not found |
| 429 | Rate limited |
| 4xx/5xx | Passthrough error from TickTick API |
Troubleshooting: API Key Issues
- Check that the
MATON_API_KEYenvironment variable is set:
echo $MATON_API_KEY
- Verify the API key is valid by listing connections:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
Troubleshooting: Invalid App Name
- Ensure your URL path starts with
ticktick. For example:
- Correct:
https://api.maton.ai/ticktick/open/v1/project - Incorrect:
https://api.maton.ai/open/v1/project