@doist/todoist-sdk

中文文档
17.0.1发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 7.1万

The official TypeScript SDK for the Todoist REST API.

此软件包已被标记为弃用

Moved to @todoist/sdk. Replace @doist/todoist-sdk with @todoist/sdk in your dependencies and imports.

原始使用文档
文档目录19 节
  1. Installation
  2. Usage
  3. Documentation
  4. Migration Guide
  5. Custom Headers
  6. Custom HTTP Clients
  7. Basic Usage
  8. Custom Fetch Interface
  9. OAuth with Custom Fetch
  10. Keeping Proxy Support and Response Decompression
  11. Important Notes
  12. Filter Queries
  13. Development and Testing
  14. Local API Requests With .env
  15. Releases
  16. For Contributors
  17. For Maintainers
  18. Feedback
  19. Contributions

Todoist SDK

The official TypeScript SDK for the Todoist REST API.

Installation

Requires Node 20.18.1+.

npm install @doist/todoist-sdk

Usage

An example of initializing the API client and fetching a user's tasks:

import { TodoistApi } from '@doist/todoist-sdk'

const api = new TodoistApi('YOURTOKEN')

api.getTasks()
    .then((tasks) => console.log(tasks))
    .catch((error) => console.log(error))

Documentation

For more detailed reference documentation, have a look at the Todoist API v1 Documentation.

Migration Guide

If you're migrating from an older version of the Todoist API (v9), please refer to the official migration guide for detailed information about the changes and breaking updates.

Key changes in v1 include:

  • Updated endpoint structure
  • New pagination system
  • Unified error response format
  • Object renames (e.g., items → tasks, notes → comments)
  • URL renames and endpoint signature changes

Custom Headers

Pass headers to send extra headers with every API request, for example to tell the backend which client is calling:

const api = new TodoistApi('YOURTOKEN', {
    headers: { 'Doist-Platform': 'cli' },
})

For values that change between requests, pass a function instead. The SDK calls it once per request, and a retried request reuses its result:

import { randomUUID } from 'node:crypto'

const api = new TodoistApi('YOURTOKEN', {
    headers: () => ({ 'Doist-Platform': 'cli', 'Request-Id': randomUUID() }),
})

These headers cannot replace Authorization, X-Request-Id or the multipart Content-Type; the SDK's own values always win. They are not sent on attachment downloads (viewAttachment), which redirect to a third-party CDN. The OAuth helpers (getAuthToken, refreshAuthToken, revokeToken, …) take their own options and do not send them.

Custom HTTP Clients

The Todoist API client supports custom HTTP implementations to enable usage in environments with specific networking requirements, such as:

  • Obsidian plugins - Desktop app with strict CORS policies
  • Browser extensions - Custom HTTP APIs with different security models
  • Electron apps - Requests routed through IPC layer
  • React Native - Different networking stack
  • Enterprise environments - Proxy configuration, custom headers, or certificate handling

Basic Usage

import { TodoistApi } from '@doist/todoist-sdk'

// Using the new options-based constructor
const api = new TodoistApi('YOURTOKEN', {
    baseUrl: 'https://custom-api.example.com', // optional
    customFetch: myCustomFetch, // your custom fetch implementation
})

// Legacy constructor (deprecated but supported)
const apiLegacy = new TodoistApi('YOURTOKEN', 'https://custom-api.example.com')

Custom Fetch Interface

Your custom fetch function must implement this interface:

type CustomFetch = (
    url: string,
    options?: RequestInit & { timeout?: number },
) => Promise<CustomFetchResponse>

type CustomFetchResponse = {
    ok: boolean
    status: number
    statusText: string
    headers: Record<string, string>
    text(): Promise<string>
    json(): Promise<unknown>
}

OAuth with Custom Fetch

OAuth authentication functions (getAuthToken, revokeAuthToken, revokeToken) support custom fetch through an options object:

// New options-based usage
const { accessToken } = await getAuthToken(args, {
    baseUrl: 'https://custom-auth.example.com',
    customFetch: myCustomFetch,
})

await revokeToken(args, {
    customFetch: myCustomFetch,
})

// Legacy usage (deprecated)
const { accessToken } = await getAuthToken(args, baseUrl)

When the authorization server issues a refreshToken, use refreshAuthToken to obtain a new access token once the current one expires, without sending the user back through the authorization flow:

const refreshed = await refreshAuthToken({
    clientId: 'your-client-id',
    clientSecret: 'your-client-secret',
    refreshToken: storedRefreshToken,
})

// The server may rotate the refresh token — persist refreshed.refreshToken
// when present, otherwise keep using the previous one.

Note: Refresh tokens are only issued to OAuth apps that have them enabled (the default for new apps). Apps without them receive a long-lived access token, so getAuthToken returns no refreshToken and there is nothing to refresh. For public clients (tokenEndpointAuthMethod: 'none'), omit clientSecret when calling refreshAuthToken.

Keeping Proxy Support and Response Decompression

On Node, the SDK's default transport reads the proxy environment variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY) and decodes compressed response bodies. Supplying a customFetch replaces that transport, so a custom implementation that still wants both can borrow it with getDefaultTransport:

import { type CustomFetch, getDefaultTransport, TodoistApi } from '@doist/todoist-sdk'

const customFetch: CustomFetch = async (url, options) => {
    const transport = await getDefaultTransport()
    // undici's `fetch` and the global one are the same call at runtime but
    // carry different types, so settle on one signature.
    const fetchImpl = (transport?.fetch ?? fetch) as typeof fetch

    const response = await fetchImpl(url, {
        ...options,
        headers: {
            ...(options?.headers as Record<string, string> | undefined),
            'x-my-header': 'value',
        },
        // `dispatcher` is a Node fetch option that the DOM types don't declare.
        dispatcher: transport?.dispatcher,
    } as RequestInit)

    // `CustomFetchResponse` wants plain-object headers, not a `Headers`.
    const headers: Record<string, string> = {}
    response.headers.forEach((value, key) => {
        headers[key] = value
    })

    return {
        ok: response.ok,
        status: response.status,
        statusText: response.statusText,
        headers,
        text: () => response.text(),
        json: () => response.json(),
        arrayBuffer: () => response.arrayBuffer(),
    }
}

const api = new TodoistApi('YOURTOKEN', { customFetch })

getDefaultTransport returns the dispatcher and the fetch it must be used with as a single value, and both halves have to be used together. The dispatcher decompresses the response body itself, so pairing it with a fetch from a different undici build — including the runtime's global fetch on Node 26 — decodes the body twice and the request fails mid-stream with terminated. A fetch of undefined means the global fetch is the correct partner; the whole value is undefined outside Node, where no dispatcher applies.

Important Notes

  • All existing transforms (snake_case ↔ camelCase) work automatically with custom fetch
  • Retry logic and error handling are preserved
  • File uploads work with custom fetch implementations
  • File upload bodies are a Blob, or a ReadableStream when uploading from a stream — a custom fetch must pass them through unchanged
  • Timeout parameter is optional and up to your custom implementation

Filter Queries

Use escapeFilterToken for user-provided search text, handling validation and trimming in your code. Pass complete filter queries directly to getTasksByFilter.

await api.getTasksByFilter({
    query: `search: ${escapeFilterToken(searchText)}`,
})

Development and Testing

Instead of having an example app in the repository to assist development and testing, we have included ts-node as a dev dependency. This allows us to have a scratch file locally that can import and utilize the API while developing or reviewing pull requests without having to manage a separate app project.

  • npm install
  • Add a file named scratch.ts in the src folder.
  • Configure your IDE to run the scratch file with ts-node (instructions for VSCode, WebStorm), or you can optionally run ts-node in a terminal using instructions here (npx ts-node ./src/scratch.ts should be enough).
  • Import and call the relevant modules and run the scratch file.

Example scratch.ts file:

/* eslint-disable no-console */
import { TodoistApi } from './todoist-api'

const token = 'YOURTOKEN'
const api = new TodoistApi(token)

api.getProjects()
    .then((projects) => {
        console.log(projects)
    })
    .catch((error) => console.error(error))

Local API Requests With .env

For live API verification, you can run raw requests with a local token:

  1. Copy .env.example to .env.
  2. Set TODOIST_API_TOKEN in .env.
  3. Run requests with npm run api:request -- ....
  4. Optional: set TODOIST_API_BASE_URL in .env (defaults to https://api.todoist.com).

Examples:

npm run api:request -- --path /api/v1/tasks
npm run api:request -- --method POST --path /api/v1/tasks --body '{"content":"API smoke test"}'
npm run api:request -- --method POST --path /api/v1/tasks/123 --body '{"due_string":"no date"}'
npm run api:request -- --path /api/v1/tasks --query '{"project_id":"123","limit":10}'

To see all options:

npm run api:request -- --help

Releases

This project uses Release Please to automate releases. Releases are created automatically based on Conventional Commits.

For Contributors

When making changes, use conventional commit messages:

  • feat: - New features (triggers a minor version bump)
  • fix: - Bug fixes (triggers a patch version bump)
  • feat!: or BREAKING CHANGE: - Breaking changes (triggers a major version bump)
  • chore:, docs:, refactor:, perf: - Other changes (included in changelog)

Example:

feat: add support for recurring tasks
fix: resolve issue with date parsing
feat!: remove deprecated getTask method

For Maintainers

The release process is fully automated:

  1. Automatic PR Creation: When commits are merged to main, Release Please automatically creates or updates a release PR with:

    • Updated version in package.json
    • Updated CHANGELOG.md
    • Aggregated changes since the last release
  2. Review and Merge: Review the release PR to ensure the version bump and changelog are correct, then merge it.

  3. Automatic Release: Upon merging the release PR:

    • A GitHub release is automatically created with the new version tag
    • The publish.yml workflow is triggered by the tag
    • The package is automatically published to NPM

Users of the API client can then update to the new version in their package.json.

Feedback

Any feedback, such as bugs, questions, comments, etc. can be reported as Issues in this repository, and will be handled by us in Todoist.

Contributions

We would also love contributions in the form of Pull requests in this repository.

版本与发布记录

@doist/todoist-sdk 共发布 83 个版本,首次发布于 2026/03/31;过去 12 个月发布了 83 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
17.0.1latest2026/11/112 天前
17.0.02026/11/067 天前
16.0.02026/11/0310 天前
15.13.12026/11/0211 天前
15.13.02026/10/3113 天前
15.12.02026/10/3113 天前

其他发布通道:next → 10.2.0-next.4。

关于 @doist/todoist-sdk 的常见问题

@doist/todoist-sdk 是什么?

The official TypeScript SDK for the Todoist REST API.注意:该包已被作者标记为弃用——Moved to @todoist/sdk. Replace @doist/todoist-sdk with @todoist/sdk in your dependencies and imports.

如何安装 @doist/todoist-sdk?

在项目目录运行 npm install @doist/todoist-sdk,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:type-fest(^4.12.0 || ^5.5.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@doist/todoist-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@doist/todoist-sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@doist/todoist-sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@doist/todoist-sdk 可以商用吗?

@doist/todoist-sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@doist/todoist-sdk 的下载量有多少?

根据 npm 官方下载统计,@doist/todoist-sdk 在 2026/10/13 – 2026/11/11 这 30 天内被下载 71,271 次,日均约 2,376 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@doist/todoist-sdk 还在维护吗?

最新版本 17.0.1 发布于 2026/11/11(2 天前);至今共发布 83 个版本,其中过去 12 个月发布了 83 个;首次发布于 2026/03/31。作者已将其标记为弃用,新项目建议寻找替代方案。