Introduction
# TickTick
Access the TickTick API with managed OAuth authentication. Manage tasks and projects with full CRUD operations.
## Quick Start
```bash # 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`:
```bash export MATON_API_KEY="YOUR_API_KEY" ```
### Getting Your API Key
1. Sign in or create an account at [maton.ai](https://maton.ai) 2. Go to [maton.ai/settings](https://maton.ai/settings) 3. Copy your API key
## Connection Management
Manage your TickTick OAuth connections at `https://ctrl.maton.ai`.
### List Connections
```bash 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
```bash 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
```bash 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
```bash 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:
```bash 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
```bash 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
```bash 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
```bash 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
```bash DELETE /ticktick/open/v1/project/{projectId} ```
Returns empty response on success (status 200).
### Task Operations
#### Get Task
```bash 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
```bash 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
```bash 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
```bash POST /ticktick/open/v1/project/{projectId}/task/{taskId}/complete ```
Returns empty response on success (status 200).
#### Delete Task
```bash 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
```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
```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 `status` values: 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`) - `viewMode` for projects: `list`, `kanban`, or `timeline` - The `columns` field in project data is used for Kanban board columns - IMPORTANT: When piping curl output to `jq` or other commands, environment variables like `$MATON_API_KEY` may 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
1. Check that the `MATON_API_KEY` environment variable is set:
```bash echo $MATON_API_KEY ```
2. Verify the API key is valid by listing connections:
```bash 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
1. 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`
## Resources
- [TickTick Developer Portal](https://developer.ticktick.com/) - [TickTick Help Center](https://help.ticktick.com/) - [Maton Community](https://discord.com/invite/dBfFAcefs2) - [Maton Support](mailto:[email protected])