Our Sync API has only three entry points:
-
/TodoistSync/v2/get:Used to retrieve data (both all and only updated data). -
/TodoistSync/v2/sync:Used to sync changes that are made to the model. Changes are specified via special JSON objects. Should not be used directly,syncAndGetUpdatedis preferred as it will fetch new data as well! -
/TodoistSync/v2/syncAndGetUpdated:A combined call that syncs updates and fetches the latest data. Use this for performance reasons as you can save a request. You should probably always use this call!
Older versions
A deprecated version 1 can be seen here here. Don't use this as it will be discontinued in the future.
Recommended workflow with the API
This is the recommend way to work with the API.Creating and updating the full model (on login or relaunch of your app):
Updating changes and getting updated data (iterative sync):
/TodoistSync/v2/get
Used to retrieve data (both all and only updated). Do note that at this time onlyProjects, Labels, Filters, DayOrders supports partially fetching, this is because only these will grow a lot, the other data is small and does not change that much.
- Optional parameters:
- project_timestamps:
A JSON object containing a mapping from project ids to theirlast_updatedtimestamps.last_updatedis a property of a project, it's an unix timestamp of when the project was last updated (name changed, tasks added, etc.)
If you omit project_timestamps then all the projects will be fetched! If you specifyproject_timestampsthen only updated projects will be fetched (i.e. new projects or projects where last_updated is different).
{ "121214": "1325774561.4", "132424": "1325888134.8", ... }- labels_timestamp:
The/getand/syncAndGetUpdatedrequests returnLabelsTimestampthat specifies when the labels were last updated. If you omit labels_timestamp then all the labels will be fetched by/getrequest and none of then will be fetched by/syncAndGetUpdatedrequest. If you specifylabels_timestampthen labels will be returned if your timestamp is different from the servers.
If you send labels_timestamp and the labels have not been updated then the server won't return theLabelsentry at all.- filters_timestamp:
The/getand/syncAndGetUpdatedrequests returnFiltersTimestampthat specifies when the custom filters were last updated. If you omit filters_timestamp then all the filters will be fetched by/getrequest and none of then will be fetched by/syncAndGetUpdatedrequest. If you specifyfilters_timestampthen filters will be returned if your timestamp is different from the servers.
If you send filters_timestamp and the filters have not been updated then the server won't return theFiltersentry at all.- day_orders_timestamp:
The/getand/syncAndGetUpdatedrequests returnDayOrdersTimestampthat specifies when the day orders were last updated. If you omit day_orders_timestamp then all the day orders will be fetched by/getrequest and none of then will be fetched by/syncAndGetUpdatedrequest. If you specifyday_orders_timestampthen day orders will be returned if your timestamp is different from the servers.
If you send day_orders_timestamp and the day orders have not been updated then the server won't return theDayOrdersentry at all.- reminders_timestamp:
The/getand/syncAndGetUpdatedrequests returnRemindersTimestampthat specifies when reminders were last updated. If you omit reminders_timestamp then all the reminders will be fetched by/getrequest and none of then will be fetched by/syncAndGetUpdatedrequest. If you specifyreminders_timestampthen reminders will be returned if your timestamp is different from the servers.
If you send reminders_timestamp and reminders have not been updated then the server won't return theRemindersentry at all.- api_token:
User's API token (returned on successful login from /API/Users/login). Else the session cookie is used. - labels_timestamp:
- Curl example:
-
curl -X POST -d "api_token=..." https://api.todoist.com/TodoistSync/v2/get curl -X POST -d 'api_token=...&project_timestamps={"15":"1325774561.4"}' https://api.todoist.com/TodoistSync/v2/get - Successful return:
-
HTTP 200 OK with a JSON object of the data:
{ "FetchedAllData": true/false, "Projects": [ ... ], "ActiveProjectIds": [ ... ], "ActiveProjectTimestamps": { ... }, "Labels": [ ... ], "LabelsTimestamp": "1344642992.1", "Filters": [ ... ], "FiltersTimestamp": "1363335992.1", "DayOrders": { ... }, "DayOrdersTimestamp": "1322399993.1", "Reminders": { ... }, "RemindersTimestamp": "1322399993.1", "Settings": { ... }, "User": {...}, "UserId": User's id }
-
- User:
-
A JSON object with a user's information
Example: { "start_day":1, "start_page":"7 days, overdue", "date_format":1, "is_premium":true, "sort_order":0, "full_name":"Amir Salihefendic", "mobile_number":"...", "mobile_host":"elsewhere", "timezone":"America\/Santiago", "id":1, "time_format":0, "premium_until":"Mon, 20 Nov 2017 16:02:13 +0000", "completed_count":267, "join_date":null, "default_reminder":"mobile", "email":"amix@amix.dk" } - FetchedAllData:
- Is
trueif all the data has been fetched, otherwisefalse(indicates that only partial data has been retrieved). - Projects:
-
A list of JSON objects of projects.
Example: [{ "user_id": 1, "name": "Babu", "color": 2, "collapsed": 0, "item_order": 1, "cache_count": 13, "indent": 1, "id": 455831, "last_updated": "1325774561.4", "items": [...] }, ...] - Projects[X].items:
-
A list of items (tasks) for a project.
Example: [{ "due_date": null, "due_date_utc": null, "user_id": 1, "collapsed": 0, "in_history": 1, "priority": 1, "item_order": 2, "content": "Fluffy ferret", "indent": 1, "project_id": 22073, "id": 210873, "checked": 1, "date_string": "" "notes": [...] }, ...]Note that each task hasnotes. - ActiveProjectIds:
-
A complete list of currently active project ids. Can be used to sync client's local model (e.g. to remove projects from the local model that have been deleted).
Example: [ 1212, 114131, 121241, ... ] - ActiveProjectTimestamps:
-
A object specifying the timestamps of all the active projects. When syncing it's important that the local model's project last_updated fields are updated and this object can be used to ensure that.
Example: { ... "ActiveProjectTimestamps":{ "1181826":"1342723105.4", "976647":"1342723063.5", "976648":"1342215248.7", "1271768":"1342215248.6", "1271769":"1342215248.6", "1271770":"1342215248.6", "1271391":"1342907605.7", "976612":"1342740016.4", "1199851":"1342215248.6" }, ... } - Labels:
-
A JSON list of objects (including things like color, id etc.)
Example: [ { "color":4, "count":0, "uid":1, "id":721, "name":"followup" }, ... ]IfLabelsTimestampis sent and the labels have not been updated thenLabelswon't be returned at all! - LabelsTimestamp:
-
A string specifying when labels where last updated. Use this to not fetch all the labels on every request.
Example: "1344642992.1" - Filters:
-
A JSON list of custom filters
Example: [ { "name":"Priority 1", "query":"q1", "id":1212, "user_id":1, "item_order":1 }, ... ]IfFiltersTimestampis sent and the filters have not been updated thenFilterswon't be returned at all! - FiltersTimestamp:
-
A string specifying when filters where last updated. Use this to not fetch all the filters on every request.
Example: "1344642994.1" - DayOrders:
-
An object specifying the order of items in daily agenda.
Example: {"12345": 1, "12346": 2, "12347": 2, "12348": -1}IfDayOrdersTimestampis sent and day orders have not been updated thenDayOrderswon't be returned at all! - DayOrdersTimestamp:
-
A string specifying when day orders where last updated. Use this to not fetch day orders on every request.
Example: "1344642994.1" - Reminders:
-
An object containing all reminders for all items in the project. The key contains reminder_id the value contains reminder information.
Example: { "12345": {"item_id": 12346, "service": "email", "minute_offset": 30}, "6789": {"item_id": 12346, "service": "email", "due_date": "Fri 01 Jan 2100 09:00:00 +0000", "date_string": "2100-01-01 at 9am", "mm_offset": 0}, ... }IfRemindersTimestampis sent and reminders have not been updated thenReminderswon't be returned at all! - RemindersTimestamp:
-
A string specifying when day orders where last updated. Use this to not fetch day orders on every request.
Example: "1344642994.1" - Settings:
-
Includes user's settings as a JSON object, including things like start page query and timezone information.
Example: { "START_PAGE":"7 days, overdue", "AMPM":false, "SORT_ORDER":0, "US_DATES":false, "TIMEZONE":"America/Santiago" } - UserId:
- Includes the id of the user we are fetching data from. Do note that other user data is returned on login from /API/Users/login.
/TodoistSync/v2/sync
/TodoistSync/v2/sync takes a list of JSON object commands which specify which changes should be done to the model. These changes could be adding projects, deleting tasks, adding notes etc.It supports two big features which can make syncing easier:
- temporary ids: Ability to use and resolve temporary ids.
- duplication protection: Ensures that a command isn't run two times.
- Required parameters:
- items_to_sync:
A list of JSON object commands. These commands are specified later in the documentation.Example: [{ "type": "project_add", "temp_id": "$1326467493134", "timestamp": 1326467500523, "args": { "name": "Test", "item_order": 1, "indent": 1, "color": 1 } }, { "type": "project_update", "timestamp": 1326467500573, "args": { "id": "$1326467493134", "name": "Test new", "item_order": 5, "color": 2 } }]- api_token:
User's API token (returned on successful login from /API/Users/login). Else the session cookie is used. - api_token:
- Curl example:
-
curl -X POST -d 'api_token=...&items_to_sync=[{ "type": "project_add", "temp_id": "$1326467493134", "timestamp": 1326467500523, "args": { "name": "Test", "item_order": 1, "indent": 1, "color": 1 } }]' https://api.todoist.com/TodoistSync/v2/sync - Successful return:
-
HTTP 200 OK with a JSON object of temporary id to real id mappings:
{ "$1326467493134": 232323, ..., "$1326467493152": 2323234 } - Error return:
-
Same as successful return, but with an extra errors mapping that specifies which commands were not processed correctly:
{ "$1326467493134": 232323, ..., {"errors": ["Could not be processed (ignored!): {'args': {'blah': 'blah'}, 'type': 'item_update'}"]}, ..., "$1326467493152": 2323234 }
/TodoistSync/v2/syncAndGetUpdated
syncAndGetUpdated is a combined call that syncs updates and fetches the latest data. This is useful because you don't have to do 2 requests.- Required parameters:
- api_token:
User's API token (returned on successful login from /API/Users/login). Else the session cookie is used. - Optional parameters:
- items_to_sync:
A list of JSON object commands. It's theitems_to_syncparameter of/v2/synccall.- project_timestamps:
A JSON object containing a mapping from project ids to theirlast_updatedtimestamps. It's theActiveProjectTimestampsparameter of/v2/getcall. Please see that documentation for further details.- labels_timestamp:
A string value specifying when labels where last updated. It's theLabelsTimestampparameter of/v2/getcall. Please see that documentation for further details.- filters_timestamp:
A string value specifying when filters where last updated. It's theFiltersTimestampparameter of/v2/getcall. Please see that documentation for further details.- day_orders_timestamp:
A string value specifying when day_orders where last updated. It's theDayOrdersTimestampparameter of/v2/getcall. Please see that documentation for further details.- reminders_timestamp: A string value specifying when reminders were last updated.
- project_timestamps:
- Curl example:
-
curl -X POST -d 'api_token=...&items_to_sync=[{ "type": "project_add", "temp_id": "$1326467493134", "timestamp": 1326467500523, "args": { "name": "Test", "item_order": 1, "indent": 1, "color": 1 } }]' https://api.todoist.com/TodoistSync/v2/syncAndGetUpdated - Successful return:
-
HTTP 200 OK with a JSON object of temporary id to real id mappings:
{ "TempIdMapping: { "$1326467493134": 232323, }, "FetchedAllData": { ... Same data as /v2/get ... }, "ActiveProjectIds": { ... Same data as /v2/get ... }, "ActiveProjectTimestamps": { ... Same data as /v2/get ... }, "Projects": { ... Data of the updated projects, same as /v2/get ... }, "Settings": { ... Same data as /v2/get ... }, "User": { ... Same data as /v2/get ... }, "SyncErrors": [ ... Only set if some of the updates could not be processed ... ], "LabelsTimestamp": "1344642992.1", "Labels": ... Only sent if LabelsTimestamp is sent and your LabelsTimestamp is different from the backends ... , "FiltersTimestamp": "1322598231.1", "Filters": ... Only sent if FiltersTimestamp is sent and your FiltersTimestamp is different from the backends ... , "DayOrdersTimestamp": "1833298299.1", "DayOrders": ... Only sent if DayOrdersTimestamp is sent and your DayOrdersTimestamp is different from the backends ... , "RemindersTimestamp": "1833298299.1", "Reminders": ... Only sent if RemindersTimestamp is sent and your RemindersTimestamp is different from the backends ... , "UserId": ... Same data as /v2/get ... }
Why do I need to supply timestamps?
timestamp should be a unix timestamp of when the command was created. This is used for duplication protection, i.e. we want to ensure that same command isn't executed twice! This check works by keeping track of command types, temporary ids and timestamps. By just supplying timestamps the system does these checks automatically and will ignore duplicated commands!
How does temporary ids work?
Your application will use temporary ids and the Sync API has special support for them. We suggest that you use unix timestamps to generate these ids to give them uniquness (maybe also prefixing them with a special number). An example shows how temporary ids can be used and referenced:
[{
"type": "project_add",
"temp_id": "$1326467493134",
"args": {
"name": "Test",
"item_order": 1,
"indent": 1,
"color": 1
},
"timestamp": 1326467500523
},
{
"type": "project_update",
"args": {
"id": "$1326467493134",
"name": "Test new",
"color": 2
},
"timestamp": 1326467500573
}]
In the above example you can see that project_add command has a temp_id property - - which specifies which temporary id this new project has. project_update command later references this temporary id. The API will automatically resolve these ids.
Additionally /TodoistSync/v2/sync will return the real id of $1326467493134 in the result. Remember to update your local model with these real ids e.g.:
{"$1326467493134": 21314212}
While the system remembers temporary ids and their mappings to real ids, it's important to use real ids when they are available to you (typically after a sync). This is important since the API only remembers the last 500 temporary ids for each user!
JSON object commands
Projects
- project_add: Adding a project
-
{ "type": "project_add", "temp_id": "$1326467493134", "timestamp": 1326467500523, "args": { "name": "Test", "color": 1, "indent": 1, "item_order": 1 } } - project_update: Updating a project
-
{ "type": "project_update", "timestamp": 1326467976310, "args": { "name": "New name", "indent": 1, "color": 7, "id": "$1326467493134" } } - project_delete: Deleting projects
-
{ "type": "project_delete", "timestamp": 1326468118911, "args": { "ids": [1272425] } } - project_archive: Archive a project
-
Only available for premium users.
{ "type": "project_archive", "timestamp": 1326468118912, "args": { "id": 1272426 } } - project_unarchive: Unarchive a project
-
Only available for premium users.
{ "type": "project_unarchive", "timestamp": 1326468118913, "args": { "id": 1272426 } } - project_update_orders_indents: : Updating orders/indents of multiple projects at once
-
{ "type":"project_update_orders_indents", "timestamp":1342922613464, "args":{ "ids_to_orders_indents":"{\"15\":[22,2],\"1437\":[9,2],\"14681\":[26,2],\"20656\":[6,1],\"20657\":[8,2],\"20658\":[12,2],\"750222\":[10,2],\"1271770\":[23,1],\"1271816\":[27,1],\"1276938\":[21,1],\"1276944\":[25,1],\"1277096\":[24,1],\"1277097\":[2,1],\"1277098\":[3,1],\"1277099\":[1,1]}" } } - item_add: Adding a task
-
{ "type": "item_add", "temp_id": "$1326468158202", "timestamp": 1326468806307, "args": { "content": "Test", "project_id": 1272426, "indent": 1, "priority": 1, "date_string": "tom", "due_date_utc": "2012-3-24T20:59", "item_order": 1 } }When passingdate_stringanddue_date_utcthey should be formatted as following:-
date_string: Can beevery day @ 10. Look at our reference to see which formats are supported -
due_date_utc: Should be formatted as'YYYY-M-DDT00:00', example:'2012-3-24T23:59'. Value ofdue_date_utcmust be in UTC. -
due_date: Alternative (backward compatible, not recommended) way of providing item due date. Format is the same as fordue_date_utc, must be in UTC for due dates containing time fragments, and in the format'YYYY-M-DDT23:59:59'(hardcoded timestamp) for whole-day entries.
date_stringis required, whiledue_date_utc(due_date) can be omitted. Ifdate_stringis provided, it will be parsed as local timestamp, and converted to UTC internally, according to user profile settings. -
- item_update: Updating a task None of the properties are requried (i.e. you can only supply some of them). It's much fast to use
-
{ "type": "item_update", "timestamp": 1326470294735, "args": { "content": "New task text", "project_id": 1272426, "indent": 1, "priority": 1, "date_string": "", "due_date_utc": null, "item_order": 5, "day_order": 7, "id": "$1326468158202" } } - item_delete: Deleting tasks
-
{ "type": "item_delete", "timestamp": 1326470379977, "args": { "ids": [11466961] } } - item_move: Moving a task from one project to another
-
{ "type": "item_move", "timestamp": 1326470524258, "args": { "project_items": { "1272426": [11466963] }, "to_project": 1272419 } } - item_complete: Completing a task
-
{ "type": "item_complete", "timestamp": 1326470662137, "args": { "project_id": 1272426, "ids": [11466964], "force_history": 1 } } - item_uncomplete: Uncompleting a task
-
{ "type": "item_uncomplete", "timestamp": 1326470707104, "args": { "project_id": 1272426, "ids": [11466964], "update_item_orders": 1 } } - item_update_date_complete: When completing/uncompleting a recurring task (needs special handling!)
-
{ "timestamp":1342920333612, "args":{ "id":11482124, "new_date_utc":"2012-7-25T23:59", "date_string":"every day", "is_forward":1 }, "type":"item_update_date_complete" }is_forwardindicates if it's a complete (1) or uncomplete (0). The reason why this is a special case is because we need to mark a recurring completion (and usingitem_updatewon't do this!) Argumentnew_dateis a backward-compatible replacement fornew_date_utc. It's treated the same way asdue_dateinitem_update/item_addmethods. - item_update_orders_indents: Updating orders/indents of multiple items at once
-
{ "type":"item_update_orders_indents", "timestamp":1342920577620, "args":{ "ids_to_orders_indents":"{\"11478113\":[2,1],\"11478114\":[1,1],\"11482125\":[4,1],\"11482126\":[3,1],\"11482127\":[5,1]}" } } - item_update_day_orders: Updating day ordering on today or 7 days views
-
{ "type":"item_update_day_orders", "timestamp":1342920577622, "args":{ "ids_to_orders":"{\"11477867\":2,\"11478271\":3,\"11478272\":1}" } } - label_register: Register a label
-
{ "type": "label_register", "timestamp": 1326471017745, "temp_id": "$1326470987640", "args": { "name": "home", "color": 5 } } - label_delete: Delete a label
-
{ "type": "label_delete", "timestamp": 1326471017756, "args": { "id": "$1326470987640" } } - label_update: Updating a label
-
{ "type": "label_update", "timestamp": 1326471017757, "args": { "id": "$1326470987640", "name": "New name", "color": 3 } }nameandcolorare optional (i.e. you can just update name or color). - note_add: Add a note
-
{ "type": "note_add", "timestamp": 1326471017748, "temp_id": "$1326470987549", "args": { "item_id": "$1326470987649", "content": "This is a test" } } - note_update: Updating a note
-
{ "type": "note_update", "timestamp": 1326471017749, "args": { "note_id": "$1326470987549", "content": "This is a test" } } - note_delete: Deleting a note
-
{ "type": "note_delete", "timestamp": 1326471017759, "args": { "note_id": "$1326470987549", "item_id": "$1326470987649" } } - filter_add: Add a filter
-
{ "type": "filter_add", "timestamp": 1426471017750, "temp_id": "$1426470987550", "args": { "name": "Priority 1", "query": "p1", "item_order": 1 } } - filter_update: Update a filter
-
{ "type": "filter_update", "timestamp": 1426471017751, "args": { "id": "$1426470987551", "name": "Priority 2", "query": "p2", } } - filter_delete: Delete a filter
-
{ "type": "filter_delete", "timestamp": 1426471017752, "args": { "id": "$1426470987551", } } - reminder_add: Add a reminder
-
For a reminder with a relative timestamp (calculated as the
offset from the item timestamp)
{ "type": "reminder_add", "timestamp": 1426471017750, "temp_id": "$1426470987550", "args": { "item_id": "$1326470987649", "service": "email", "minute_offset": 30 } }For a reminder with an absolute timestamp. The due date should be converted to UTC timezone.{ "type": "reminder_add", "timestamp": 1426471017750, "temp_id": "$1426470987550", "args": { "item_id": "$1326470987649", "service": "email", "due_date_utc": "2013-01-01T14:00", "date_string": "tod @ 6pm" } } - reminder_update: Update a reminder
-
{ "type": "reminder_update", "timestamp": 1426471017751, "args": { "id": "$1426470987551", "minute_offset": null, "due_date_utc": "2013-01-01T15:00", "date_string": "tod @ 7pm" } } - reminder_delete: Delete a reminder
-
{ "type": "reminder_delete", "timestamp": 1426471017752, "args": { "id": "$1426470987551", } }
Items
item_update_orders_indents and item_update_day_orders if you need to do multiple updates of indents, item_orders or day_orders.