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://gateway.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://gateway.maton.ai/ticktick/{native-api-path}
The gateway 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://ctrl.maton.ai.
List Connections
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://ctrl.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://ctrl.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://ctrl.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:
json
{
"connection": {
"connection_id": "1fd9c3aa-6b46-456f-aa21-ed154de23ab7",
"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://ctrl.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://gateway.maton.ai/ticktick/open/v1/project')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '1fd9c3aa-6b46-456f-aa21-ed154de23ab7')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If omitted, the gateway uses the default (oldest) active connection.
API Reference
Project Operations
List Projects
GET /ticktick/open/v1/project
Response:
json
[
{
"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:
json
{
"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:
json
{
"id": "69870cbe8f08b4a6770a38d3",
"name": "My New Project",
"sortOrder": 0,
"viewMode": "list",
"kind": "TASK"
}
viewMode options:
- list - List view
- kanban - Kanban board view
- timeline - 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:
json
{
"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:
json
{
"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 - None
- 1 - Low
- 3 - Medium
- 5 - High
Update Task
POST /ticktick/open/v1/task/{taskId}
Content-Type: application/json
{
"id": "69870cb08f08b86b38951175",
"projectId": "6984773291819e6d58b746a8",
"title": "Updated task title",
"priority": 1
}
Response:
json
{
"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://gateway.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://gateway.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://gateway.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://gateway.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://ctrl.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://gateway.maton.ai/ticktick/open/v1/project - Incorrect:
https://gateway.maton.ai/open/v1/project