Skip to content

pyticktick: A Robust Python Client for TickTick#

The Implementation

The implementation of this client can be found in the GitHub repository sebpretzer/pyticktick.

It follows the general structure as described in the design doc, although improvements have been made since the design doc was written. If you want the latest documentation for the extension, you can read rst-in-md's docs.

Background and Motivation#

TickTick is a powerful task management app. I use it daily to manage my tasks, and checklists. While it has great features, it's integrations and statistics/visualizations are limited. Building custom dashboards or integrations with other tools like Jira, GitHub, etc. would require custom code to interact with TickTick's API.1

Two APIs#

TickTick provides developers with an API spec that is relatively easy to use, but it is limited in functionality. This will be referred to as the V1 API.1 It allows you to do standard CRUD operations on projects/lists and simple tasks.

TickTick's web app uses a different API that is not documented, but is much more robust. This will be referred to as the V2 API. It allows you to do everything that the web app can do, including managing more complex tasks, project folders, tags, habits, pomodoro timers, and more. This is not documented, so the only ways to understand it are to monitor the network requests made by the web app, or to read other projects' code that have reverse-engineered the API already.

It is near impossible to use just the V1 API to do everything that you want to do. You cannot manage many major features of TickTick. Within the scope of just projects and tasks, you cannot control all properties of a task, you cannot access a user's inbox/completed tasks, and you are rate limited more quickly with inefficient endpoints. For almost all use cases, you will need to use the V2 API.

3rd Party Clients#

TickTick does not have any official clients for their API, so the community has rolled a few of their own. Some clients support the V1 API, some support the V2 API, and some support both. They have different levels of maintenance, documentation, and features. None seem to provide a complete solution for all use cases.

Python Clients#

  • ticktick-py has some support for the V1 API and has some support for the V2 API, but neither is completely supported. It does not seem maintained anymore, and attempting to use it may result in auth errors, like when I tried to use it. There is some documentation, but it is limited.
  • dida365 supports the V1 API but does not support the V2 API at all. It has good features overall, including some retry logic, pydantic support, async support, and more.
  • tickthon supports the V2 API but does not support the V1 API at all. It has no documentation, making it difficult to use.

Other Clients#

  • TickTickSync which is a Typescript sync plugin for Obsidian. This seems to support the V2 API.
  • ticktick-mcp-server which is a model context protocol (MCP) server for TickTick. This only appears to support the V1 API.

Goals and Non-Goals#

Goals#

  1. Provide a Python client for the V1 API and V2 API that is easy to use and understand. Users should be able to:
    • quickly get started with the client, with minimal setup
    • know which API they are using
    • easily switch between the two APIs if they want to
  2. Provide support for all major features related to task management, including:
    • Projects/Lists
    • Project Folders
    • Tasks
    • Task Tags
  3. Provide thorough documentation, including guides and explanations, to help users understand all aspects of the client.
  4. Provide robust typechecking and validation of data being passed to and from the APIs. This will help the user understand what data is required/allowed, without needing to guess on undocumented endpoints.

Non-Goals#

  1. Provide asynchronous support for the client. This is not a goal because TickTick is not a high-throughput application, and the V2 API already has batch endpoints that allow you to perform multiple operations in a single request.
  2. Provide support for all features of the V2 API, outside of task management. This is not a goal because the V2 API is undocumented, and it would be difficult to provide support for all features. Instead, we will focus on the most commonly used features, and triage any requests for additional features after the initial release.

Design#

Overview#

The goal of this work is to provide a Python client. Python is a very flexible language, and has a large ecosystem, making integrations with other tools easier. For example, there are libraries for GitHub2, Jira34, and many other tools that can be used to build custom integrations with TickTick. The push from the community for many implementations of a TickTick client is proof that there is some demand. Python is also great for data visualization, so users can build custom dashboards and visualizations of their tasks and projects.

Functions#

The client will provide a set of functions that allow users to interact with the TickTick APIs. The functions will be named clearly to indicate what they do, so that users can easily understand what API endpoint they are using. For example, get_project() will GET from the /project endpoint, and delete_task() will DELETE from the /project/{project_id}/task endpoint.

The functions will be organized by API version and will be clearly named to indicate which API they are using. Users will not need to worry about having to authenticate and work with an API they do not want to use. For example, the get project function will be named get_project_v1() for the V1 API. If the V2 API had a similar endpoint, it would be named get_project_v2().

Data Models#

The client will use Pydantic to define data models for the data being passed to and from the APIs. This will allow users to easily understand what data elements are necessary, and fail early if the data is not valid. TickTick's error handling is not very helpful, so Pydantic's validation will smooth out the rough edges.

Similar to functions, the data models' names will closely match the API endpoints they represent. For example, the data model for the payload to create a tag will be named CreateTagV2.

Settings#

One key aspect of the design is to build a useful interface for authentication and settings management. If the user cannot authenticate easily, they will not be inclined to use the client. As much of the heavy lifting should be done up front, so the user can focus on accessing the data they need, rather than worrying about authentication.

Pydantic provides a great foundation for this with pydantic-settings. It allows us to define our settings in a variety of ways, including environment variables, and is backed by Pydantic's powerful data validation features. This will allow the user's instantiation to fail early and noisily if there are any issues.

Drawbacks#

Strictness of Pydantic#

One of the main drawbacks of this design is the strictness of Pydantic. For the most part, Pydantic models will help catch errors early, but it can also be a hindrance. Models might be unnecessarily strict, or the API might change and the models will need to be updated. In either case, this can hinder the user's experience. Other libraries get around this issue by passing in all data, and letting TickTick handle the errors.

Best-Guess Documentation#

Another drawback is that since the V2 API is undocumented, it is difficult to provide useful documentation for those endpoints. The documentation will be a best guess based on field names, and patterns observed in the web app, but it may not be accurate. It can lead to user confusion. Other libraries avoid this issue by not providing documentation at all, and putting the onus on the user to figure out how to use the API.

Alternatives Considered#

Adapt Existing Libraries#

Another alternative is to adapt the best existing libraries, such as ticktick-py or dida365. ticktick-py is not maintained anymore, so it would have to be forked. It also conflates the V1 API and V2 API into a single set of functions. dida365 is a good library, but it does not support the V2 API at all. The difficulty of adapting these libraries on top of extending them to fully support the undocumented V2 API made this option less appealing.

Switch to Todoist#

Another alternative is just to switch to the other great task management app, Todoist. They support a Python client themselves, rather than relying on the community to build one. They also have a more robust API, and better documentation. This is probably the correct choice, but then I would miss out on learning and building something new. Where's the fun in that? 😉