Twist integrations don’t move to Todoist Comms. If your bot posts from a script or scheduled job, use the Todoist Comms CLI. If you’re building a custom integration, call the Todoist Comms API. In both cases, post from a dedicated account so your team can see which messages came from the bot.
Prepare for your move
- Keep a Twist API token: to convert stored Twist links later, you need a Twist API token for an account that stays in your Twist workspace, like the bot’s or your own. If you don’t have one, create a Twist app before the move and get a test token with the
workspaces:readpermission, as described in the Twist API documentation. - Plan for the read-only period: pause scheduled posts when your move starts. Twist becomes read-only and stays that way after a successful move. Keep track of any missed posts you’ll need to send later.
- Note the deadline: Twist closes on March 1, 2027. Convert your stored links before then.
Choose how your bot posts
Todoist Comms doesn’t have incoming webhooks. In Twist, many teams posted into a channel or thread through an incoming webhook URL. In Todoist Comms, your bot posts as a Todoist Comms account through one of these tools:
- Todoist Comms API: call the API directly from any language. See the Todoist Comms API documentation.
- Todoist Comms CLI: post from scripts, cron jobs, or CI pipelines with comms-cli.
- Todoist Comms SDK: build in TypeScript with comms-sdk-typescript.
- Model Context Protocol (MCP) server: in your AI app’s MCP settings, add the hosted server URL
https://ai.todoist.net/mcp/comms, or run comms-mcp locally. For local setup, configure your AI app to launchnpx -y @todoist/comms-mcpwith the bot’s Todoist API token in theCOMMS_API_KEYenvironment variable. - Todoist Automations: post on a schedule without writing code. See Create a Todoist automation.
If you’re a team admin or member, you can find these tools in Settings & members > Integrations.
If the old webhook ran from your own script or CI job, replace that step with a CLI command or an authenticated API call. If an alerting service only accepts a webhook URL, point it to a small service you control that receives the event and posts to Todoist Comms as the bot.
For a CLI script or direct API call, get the bot’s Todoist API token after setting up its account. For hosted MCP or Automations, connect the bot’s account instead:
- Hosted MCP server: when your AI app asks you to authorize Todoist, use a browser profile that’s logged in as the bot. Check the account before approving: posts use the identity that authorized the connection.
- Todoist Automations: connect Todoist Comms while logged in as the bot, since an automation posts as the person who connected it. Automations is in beta. The bot needs its own Pro plan, or an admin or member role in a team on the Business plan.
Примечание
hooks/subscribe), which send events to your app and require an OAuth app token.
Set up the bot’s account
Post as a dedicated bot account rather than as yourself. Your team sees a clear sender, and the bot keeps working when people change roles or leave.
- Bot with its own Twist account: if your script logs in as a regular Twist user and that account is still in the workspace, it moves with your team. A bot created by a Twist integration doesn’t get a Todoist team membership, even if its old posts appear in Todoist Comms. After the move, go to Log in as a bot that moved from Twist.
- Any other bot: this includes incoming webhooks, integration bots, and accounts removed from Twist before the move. If the bot already belongs to the destination Todoist team, add it to the channels it needs instead of inviting it again. Otherwise, go to Invite the bot to your team.
Invite the bot to your team
Предупреждение
For a bot that only posts to selected channels, start with the guest role. Check the role before sending the invitation:
- Admin or member: on the Business plan, each admin or member is a seat you’ll be charged for. The bot doesn’t need an admin role just to post. On a free team, the choices are Admin and Guest. The invitation defaults to Admin, so select Guest for a bot that only needs channel access.
- Guest: doesn’t take a seat, and needs at least one channel. If your team isn’t on the Business plan, your team can have up to five guests.
To use Todoist Automations, the bot needs an admin or member role on the Business plan, or its own Pro plan.
- Create a shared email address for the bot, like
alerts-bot@yourcompany.com. - Click the team menu in the top-left of Todoist Comms.
- Click Invite your team.
- Select the bot’s role under Invite by email. On the Business plan, Member is selected by default.
- Enter the bot’s email address.
- Click Edit/Add under Add to channels. For a guest, the channel list is already open.
- Select every channel the bot will post in. The bot can’t start threads in a channel it hasn’t been added to.
- Click Send invite (1).
You can only add the bot to channels you’re a member of and can add people to. Todoist Comms skips any other channels you select.
If the bot already belongs to your team or needs another channel later, add it from the channel:
- Open the channel.
- Click Channel options at the top.
- Select Manage members….
Accept the invitation as the bot
Open the invitation in a private browser window so you accept it as the bot. If its email already has a Todoist account, log in with that account’s usual method. If it’s new, follow the sign-up and verification steps below.
- Open the invitation email in the bot’s inbox.
- Copy the Join Todoist team link.
- Open a private browser window.
- Paste the link into the address bar.
- Enter a password for the bot.
- Save the password in your team’s password manager.
- Click Sign up with Email.
- Open the verification email in the bot’s inbox.
- Click the link in the email to verify the bot’s account. The private window moves on to the next step by itself. If the link opens in another window, close that window and go back to the private one.
- Enter the bot’s name, like Deploy Bot, when asked for your name. Your team sees this name on every post.
- Finish the remaining onboarding steps. Todoist Comms opens as the bot.
If you’re asked to log in instead of creating a new account, use the bot’s existing Todoist account. If you don’t know its password, reset it from the bot’s inbox. After joining, open Todoist Comms and check that the bot can see the channels you selected.
For the CLI, SDK, or a direct API call, get the bot’s Todoist API token.
Log in as a bot that moved from Twist
The bot’s Twist API token can’t post in Todoist Comms, so get its Todoist API token instead. Keep the Twist API token if you still need to convert stored links.
- Open a private browser window.
- Log in to Todoist with the bot’s Twist email address. If it already has a Todoist account, use that account’s usual login method. Otherwise, try its Twist password.
- Click Forgot your password? on the login page if the password doesn’t work.
- Reset the password from the bot’s inbox.
- Follow the steps in Get the bot’s Todoist API token to post with the CLI, SDK, or a direct API call.
On the Business plan, the bot takes a paid seat if it’s an admin or member on the destination Todoist team. If it was a guest in Twist but already had a higher role on that team, it keeps the higher role.
Get the bot’s Todoist API token
Todoist Comms accepts the bot’s Todoist API token, which you copy from Todoist settings. Copy it in a private window where you’re logged in as the bot, so you get the bot’s token and not your own.
- Go to Todoist in a private window. If you’re asked to log in, log in as the bot.
- Click your avatar in the top-left.
- Select Settings.
- Select the Integrations tab.
- Select the Developer tab at the top.
- Click Copy API token.
Предупреждение
Store the token in your secret store. When you call the API directly, send it in the Authorization header of every request: Authorization: Bearer <token>.
For a scheduled job that always posts as the same bot, use its personal API token. An app that connects accounts on behalf of different users should use OAuth.
Update your bot with an AI agent
Once the bot has its account and API token, an AI coding agent like Claude Code, Cursor, or GitHub Copilot can update your bot’s code for you. If your bot runs on Todoist Automations or the hosted MCP server, there’s no code to update, so skip this section. Otherwise, open your bot’s code in the agent and paste in this prompt:
I'm moving my team from Twist to Todoist Comms. Update this bot so it posts to Todoist Comms instead of Twist.
1. Read this guide first and follow it: [ARTICLE URL]
2. Find every place in this code that posts to Twist, like incoming webhook URLs or Twist API calls. List them for me before you change anything.
3. Ask me for the Todoist Comms link of each channel or thread the bot should post to. I'll open threads from their channel, not from Inbox, so the link includes the channel ID.
4. Replace each Twist post with a Todoist Comms CLI command, the Todoist Comms TypeScript SDK, or an authenticated Todoist Comms API call that posts as the bot's dedicated account. For API calls, send the token as Authorization: Bearer <token> with a JSON body. Read the bot's Todoist API token from an environment variable, and stop if it's empty. Never hard-code, log, or print the token.
5. For direct API calls, create a new id (UUIDv7, base58 encoded) for each post, save it with the event before sending, and reuse it when you retry the same post. Don't retry CLI commands automatically: each run creates a new post.
6. Ask me who each post should notify. Then set recipients and groups on API posts, or add --notify NONE to CLI replies that should be quiet.
7. If the code stores Twist links or thread IDs, write a one-time script that converts them with tdc migrate urls. It needs a Twist API token in TWIST_AUTH_TOKEN, and I'll run it after our move is complete and before Twist closes on March 1, 2027.
8. Don't remove the Twist job until I've tested the new version. Show me the changes and one test command I can run against a test thread. I'll switch the bot over once our move is complete.Check the changes before you run them, and test the bot in a test thread first.
Post a thread or comment
You’ll find the IDs you need in the Todoist Comms URL: comms.todoist.com/<team_id>/ch/<channel_id>/t/<thread_id>. Open the thread from its channel in the sidebar, not from Inbox, so the URL includes the channel ID.
Every thread and comment also needs an id that your integration creates: a UUIDv7, encoded as a base58 string. The SDK and CLI create it for you. When you call the API directly, generate a new id for each new message, and reuse the same id when you retry the same post after a timeout. Save the ID with the event before sending it. The SDK also accepts an ID you supply.
Send each request with a JSON body.
| Action | Endpoint | Required fields | Common optional fields |
|---|---|---|---|
| Start a new thread | POST https://comms.todoist.com/api/v1.0/threads/add | channel_id, title, id | content, groups, recipients |
| Comment on a thread | POST https://comms.todoist.com/api/v1.0/comments/add | thread_id, content, id | groups, recipients |
Write content in Markdown. On the web, single line breaks are kept and plain URLs become links.
Your bot can also send direct messages. Use conversations/get_or_create to open the conversation, then conversation_messages/add to post in it.
Post from the CLI
The Todoist Comms CLI requires Node.js 24 or later and npm 11 or later. Install the CLI with npm install -g @todoist/comms-cli. Its command is tdc.
The CLI reads the bot’s Todoist API token from the COMMS_API_TOKEN environment variable. In CI or a scheduler, store the token as a secret and set COMMS_API_TOKEN from that secret. Have the job stop if the variable is empty so the CLI can’t fall back to a saved login.
To try the CLI on your own computer, run tdc auth token and paste the token when asked. The CLI doesn’t show the token as you paste it, and it isn’t saved in your shell history.
To test the bot, open an existing test thread in Todoist Comms and copy its URL. Replace THREAD_URL below with that URL. Run the command once from the same CI or scheduler environment that will send the real posts, with the bot’s token loaded. The test comment is visible in the thread and sends no notifications.
tdc thread reply "THREAD_URL" "Migration test: bot connected." --notify NONE
For a thread in a private channel, add --include-private-channels. Open the link the CLI returns and check the sender, team, and thread. If a command times out, check the thread before rerunning it: each run creates a new post ID.
Choose who gets notified
By default, a comment from the API notifies everyone in the channel, and a comment from the CLI notifies only people who started, commented on, or reacted in the thread. Whether someone sees an unread thread, push notification, or email also depends on their mute and notification settings.
For alerts and routine reports sent directly through the API, set the audience with the recipients and groups fields:
"recipients": [], "groups": []: send a quiet post when the message has no group mentions"groups": ["EVERYONE_IN_THREAD"]: notify only people who started, commented on, or reacted in the thread"groups": ["EVERYONE"]: notify everyone in the channel
For a normal CLI reply, add --notify NONE to post without notifying anyone. Keep this flag on the scheduled reply if it should also be quiet.
The same fields work when you start a new thread. If you leave them out, a new thread notifies the channel’s default participants. If the channel has no default participants, it notifies everyone in the channel. EVERYONE_IN_THREAD doesn’t apply to new threads.
To notify one person, add their numeric user ID to recipients, like "recipients": [12345]. To mention them, add [Name](comms-mention://12345) to content. For a personal mention, include the person in the audience as well as the text. Group mentions can add their members to the audience even when the recipient lists are empty. For a quiet API post, leave mentions out of the text. Only channel members can be notified.
To find someone’s user ID, run tdc users --search "<name>", or call workspace_users/get_by_email in the API.
Where your bot can’t post
- Concluded threads: reopen the thread or start a new one.
- Channels where posting is limited: the bot gets a “Commenting is limited in this channel” or “Thread creation is limited in this channel” error. Post in another channel.
- Archived channels: the bot gets the same “limited in this channel” errors. Post in an active channel instead.
Switch your bot over after the move
Your team gets an email when the move starts and when it finishes. If the move doesn’t go ahead and Twist reopens, team admins get an email. Keep the old job paused while you check which service is ready.
While your move runs, your Twist workspace is read-only. Posting through the Twist API returns HTTP 403 with error code 217 (“Workspace is read only”).
To check the move from a script, call workspaces/getone in the Twist API with your workspace’s id. It’s the number after /a/ in your Twist links. Then check comms_migration.status:
in_progress: the move is still running. Keep the job paused and note its last successful run.completed: your team is ready in Todoist Comms. Set the new destination and bot credentials, then verify one test post. Check for queued retries before enabling the new schedule. Watch its first run and send only the posts you missed.not_started: no move is running or complete. This is also the status before a move starts. If a move was interrupted, resume the Twist job only after your admin confirms that Twist is writable again.
Update stored Twist links
Your links and IDs are different in Todoist Comms. If your bot stores Twist links or IDs, convert them after the move is done, and before Twist closes on March 1, 2027.
You need a Twist API token for an account that’s still in your Twist workspace. See Prepare for your move.
If you stored thread IDs instead of links, build a link for each one first, like https://twist.com/a/<workspace_id>/inbox/t/<thread_id>. Twist finds the thread’s channel for you, as long as the token’s account can see the thread.
To convert links with the CLI, set the TWIST_AUTH_TOKEN environment variable to your Twist API token. Then run tdc migrate urls with your links, separated by commas. To pipe the links in instead, like from a file, add --stdin.
In the TypeScript SDK, fetchNewCommsUrls returns a result for each link. Check for a new URL or an error before replacing the original. With the CLI, add --json to save the results. If any link fails, the command exits with a nonzero status. Keep the successful mappings and retry only the failed links.
To convert links with the API:
- Send a
POSTrequest tohttps://twist.com/api/comms_migration/fetch_new_urlwith the headerAuthorization: Bearer <twist_token>and a JSON body, like{"old_url": "<link>"}. Send one request for each link. - Save the
new_urlalongside the original Twist link. - Update the job’s destination only for successful conversions.
If a link doesn’t convert, check the error code:
- 400 (unsupported link): check the URL format.
- 404 (not found): check that the move finished and the Twist account can see the item.
- 503 (temporary error): retry later.
Keep the bot’s token valid
Common reasons you’ll need to replace the bot’s personal API token include:
- Someone changes the bot account’s password.
- Someone turns on two-factor authentication for the bot account and keeps Log out of all other devices selected. It’s selected by default.
- Someone clicks Issue a new API token in the bot’s Todoist settings.
Soon after the token changes, the old token stops working and your bot can’t post. To fix it, copy the new token as described in Get the bot’s Todoist API token, and update it in your secret store. Let your team know that changing the bot’s password or security settings will stop it from posting.
Removing the bot from a team stops it from posting to that team. Deleting the account stops all jobs that use it.
Get in touch
If you have trouble moving your bots to Todoist Comms, get in touch with us.