Overview
This is the official documentation for Todoist Sync API. A reference to the functionality our public API provides with detailed description of each API endpoint, parameters, and examples.
Summary of contents
In the Getting started section we will try to present to you the Todoist API, in the simplest possible way, by using real examples, based on common tasks that many users want to accomplish.
After reading this section you should continue with the Authorization, in order to learn all the details on the best way to authenticate to our server.
The most important section is the Sync section, and you should read it next, where the way that the API works is explained.
The other sections are the reference documentation of the different Todoist objects and endpoints, and you can continue reading them in the order you need them.
Python library
We currently have an official Python library supported by Doist to make the developer life easier.
You can install todoist python library via pip:
$ pip install todoist-python
You can find the Python library source code at its repository at Github.
You can also read the Python library documentation online.
Finally, there’s also a PyPI package ready for you to install.
Getting started
In this section we will do some common things, that many of our users ask for
help on accomplishing them. We will mostly use the sync call, which is
described in detail at the Sync section. For now this can be
considered as just an endpoint, and you will soon figure some of the things it can
do, just by having a look at some examples.
Get all projects
The example of how we get all projects:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token=* \
-d resource_types='["projects"]'
{
"projects" : [
{
"is_archived" : 0,
"color" : 7,
"shared" : false,
"inbox_project" : true,
"id" : 176637162,
"collapsed" : 0,
"child_order" : 0,
"name" : "Inbox",
"is_deleted" : 0,
"parent_id" : null
}
],
"full_sync" : true,
"temp_id_mapping" : {},
"sync_token" : "aLGJg_2qwBE_kE3j9_Gn6uoKQtvQeyjm7UEz_aVwF8KdriDxw7e_InFZK61h"
}
>>> from todoist.api import TodoistAPI
>>> api = TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.sync()
>>> print(api.state['projects'])
[
Project({
'collapsed': 0,
'color': 7,
'id': 176637162,
'inbox_project': True,
'parent_id': None,
'is_archived': 0, 2
'is_deleted': 0,
'child_order': 0,
'name': 'Inbox',
'shared': False
})
]
First, let’s see how we can get all projects a user has.
Using curl
We send a request to the sync endpoint, and then specify the following
arguments:
- The user’s API token, which here is set to
token=0123456789abcdef0123456789abcdef01234567. You can find out your token from the Todoist Web app, atTodoist Settings -> Integrations -> API token. - A special sync token, which denotes that we want a full sync, in contrast to
an incremental sync, which is denoted with the
*symbol, so we setsync_token=*. - That we want to get back only the
projects, and not any other data, so we setresource_types='["projects"]'.
In the results we get back, we notice the following data:
- All the user’s projects, which in this case it’s only the
Inboxproject. - A special flag
full_syncwhich is set totruehere, and denotes we did a full sync. - A new
sync_tokenwhich we can use later on, in order to do incremental syncs. - An empty
temp_id_mappingobject which we’ll look at later on.
Using the Python library
We need to import the TodoistAPI class from the todoist module, create a
TodoistAPI object which we store to the api variable, and specify our user
API token, that is 0123456789abcdef0123456789abcdef01234567.
After that we can just do a sync by calling api.sync(), and we can access the
user’s projects through the api.state object, so for projects that is:
api.state['projects'].
Excluding resource types
An example of how to exclude projects from our query:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token=* \
-d resource_types='["all", "-projects"]'
{
"filters": [],
"temp_id_mapping": {},
"labels": [],
"locations": [],
"project_notes": [],
"user": {},
"full_sync": true,
"sync_token": "V-ZiRSIcXY5VUWzxCfWNClj81Qatg6hhrczNHIvROQKEpr7ARxU7cX09hENmXu1FF8w6qCY0_7ZjQ64k4pLWrvjVvjgKcY3e7LLapln-NLVJifE",
"day_orders": {},
"collaborators": [],
"day_orders_timestamp": "1523557037.93",
"live_notifications_last_read_id": 1192062233,
"items": [],
"notes": [],
"reminders": [],
"live_notifications": [],
"collaborator_states": []
}
We’ve seen how we can get items selecting them with resource_types, but at the same time we can also exclude items. This can be done by adding a - before the name of the item you want to exclude.
For example, if we were making a request for everything but notes and labels, it’d look like this: resource_types=["all", "-notes", "-labels"].
Using curl
Similar to our previous example, we’re sending a request to the sync endpoint with the following arguments:
- The user’s API token, which is set to
token=0123456789abcdef0123456789abcdef01234567. You can find out your token from the Todoist Web app, atTodoist Settings -> Account -> API token. - A special sync token, which denotes that we want a full sync, in contrast to an incremental sync, which is done with the * symbol, so we set
sync_token=*. - The use of
resource_types='["all", "-projects"]'allows us to specify that we want everything but projects.
We then get back the following results:
- All of the resource items except
projects. - A special flag
full_syncwhich is set totruehere, and denotes we did a full sync. - A new
sync_tokenwhich we can use later on, in order to do incremental syncs. - An empty
temp_id_mappingobject which we’ll look at later on.
Add a new project
The example of how we create a new project:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token="aLGJg_2qwBE_kE3j9_Gn6uoKQtvQeyjm7UEz_aVwF8KdriDxw7e_InFZK61h" \
-d resource_types='["projects"]' \
-d commands='[
{ "type": "project_add",
"temp_id": "24a193a7-46f7-4314-b984-27b707bd2331",
"uuid": "e23db5ec-2f73-478a-a008-1cb4178d2fd1",
"args": { "name": "Project1" } }
]'
{
"projects" : [
{
"is_deleted" : 0,
"parent_id" : null,
"child_order" : 1,
"name" : "Project1",
"collapsed" : 0,
"shared" : false,
"id" : 176637191,
"is_archived" : 0,
"color" : 7
}
],
"temp_id_mapping" : {
"24a193a7-46f7-4314-b984-27b707bd2331" : 176637191
},
"sync_status" : {
"e23db5ec-2f73-478a-a008-1cb4178d2fd1" : "ok"
},
"sync_token" : "VRyFHr0Qo3Hr--pzINyT6nax4vW7X2YG5RQlw3lB-6eYOPbSZVJepa62EVhO",
"full_sync" : false
]
}
>>> project1 = api.projects.add('Project1')
>>> api.commit()
>>> print(project1)
Project({
'collapsed': 0,
'color': 7,
'id': 176637191,
'parent_id': None,
'is_archived': 0,
'is_deleted': 0,
'child_order': 1,
'name': 'Project1',
'shared': False})
Let’s create a new project, and observe the result of our action.
Using curl
We use the sync call, and then specify the following arguments:
- The user’s API token which is set to
token=0123456789abcdef0123456789abcdef01234567. - The sync token that we received on the reply of our previous request, and
which denotes that we want an incremental sync, so we set
sync_token="aLGJg_2qwBE_kE3j9_Gn6uoKQtvQeyjm7UEz_aVwF8KdriDxw7e_InFZK61h". - That we want to get back only the
projectsand not any other data, so we setresource_types='["projects"]'. - We send a single
project_addcommand that will create a new project, and we specify as the only argument to that command thenameof the project which is set toProject1. - We also need to specify 2 UUIDs: the
uuidthat that will uniquely identify our command, and thetemp_idwhich is a temporary ID we set to our new project, and we can use that later on to identify it to the server, without a need to know its real ID, which is assigned at the time of creation on the server. Note that in these examples we’re using UUID values, but you could also use a shorter strings containing letters and/or numbers, but you need to make sure they will be random and unique.
In the results we get back, we notice the following data:
- The new project we added is returned as part of the user’s
projects. - The
temp_id_mappingobject which tells us that the new object with UUID24a193a7-46f7-4314-b984-27b707bd2331has a real ID176637191. Notice that we can use both of these IDs to refer to that project, and while the latter should be used whenever possible, the former can be also utilized on a temporary basis. - The
sync_statusobject which tells us whether our command with UUIDe23db5ec-2f73-478a-a008-1cb4178d2fd1was successful, or in case of error what exactly was the problem. - The special flag
full_syncwhich is set tofalsehere, and denotes we did an incremental sync. - A new
sync_tokenwhich we can use later on to continue doing incremental syncs.
Using the Python library
We call the api.projects.add() call, supplying the name of the new project,
and as a return value we get a new project object. This object holds the newly
created project, and we store it in the project1 variable.
This object is only temporary, it only exists on our local state, so in order to
ask the server to add it remotely on the system, too, we use the api.commit()
call, which does all the work of sending the request to add the project, and
getting back the new project’s properties.
Finally we print the new project1 object.
Add two new tasks
The example of how we create two new tasks:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token="VRyFHr0Qo3Hr--pzINyT6nax4vW7X2YG5RQlw3lB-6eYOPbSZVJepa62EVhO" \
-d resource_types='["projects", "items"]' \
-d commands='[
{ "type": "item_add",
"temp_id": "fdef5d16-a40a-475e-bd4a-0ccbd6fd8c3f",
"uuid": "a3aa2f44-23b4-4986-b513-ef7663bbb752",
"args": { "project_id": "24a193a7-46f7-4314-b984-27b707bd2331", "content": "Task1" } },
{ "type": "item_add",
"temp_id": "6f5e0b50-af7a-4133-bfc0-e8c041b819d2",
"uuid": "d16ad84a-e10b-4894-af7d-93ba6adf7a1e",
"args": { "project_id": 176637191, "content": "Task2" } },
]'
{
"projecs": [],
"items" : [
{
"collapsed" : 0,
"date_added" : "2016-08-01T13:19:45Z",
"child_order" : 2,
"parent_id" : null,
"all_day" : false,
"day_order" : 1,
"added_by_uid": 1,
"assigned_by_uid" : 1,
"responsible_uid" : null,
"sync_id" : null,
"checked" : 0,
"user_id" : 1,
"labels" : [],
"is_deleted" : 0,
"due" : null,
"project_id" : 176637191,
"in_history" : 0,
"content" : "Task2",
"id" : 102835617,
"priority" : 1
},
{
"priority" : 1,
"id" : 102835615,
"content" : "Task1",
"in_history" : 0,
"is_deleted" : 0,
"due" : null,
"project_id" : 176637191,
"checked" : 0,
"labels" : [],
"user_id" : 1,
"responsible_uid" : null,
"sync_id" : null,
"added_by_uid": 1,
"assigned_by_uid" : 1,
"day_order" : -1,
"parent_id" : null,
"all_day" : false,
"child_order" : 1,
"collapsed" : 0,
"date_added" : "2016-08-01T13:19:45Z"
}
],
"temp_id_mapping" : {
"1c0f8453-32f0-4bf1-8c31-2faf8fa59ef1" : 176637191,
"6f5e0b50-af7a-4133-bfc0-e8c041b819d2" : 102835617,
"fdef5d16-a40a-475e-bd4a-0ccbd6fd8c3f" : 102835615
},
"sync_status" : {,
"a3aa2f44-23b4-4986-b513-ef7663bbb752" : "ok",
"d16ad84a-e10b-4894-af7d-93ba6adf7a1e" : "ok"
},
"sync_token" : "Gm7DEx2RBn-mW9xGIJhAPOGRPWSlewfxGm0aY_W6IhThCp_8DDXmPU8ERu8u",
"full_sync" : false
}
>>> project1 = api.projects.add('Project1')
>>> task1 = api.items.add('Task1', project_id=project1['id'])
>>> task2 = api.items.add('Task2', project_id=project1['id'])
>>> api.commit()
>>> print(task1, task2)
(
Item({
'all_day': False,
'assigned_by_uid': 1,
'checked': 0,
'collapsed': 0,
'content': 'Task1',
'date_added': '2016-08-01T13:19:45Z',
'due': None,
'day_order': -1,
'id': 102835615,
'in_history': 0,
'parent_id': None,
'is_deleted': 0,
'child_order': 1,
'labels': [],
'priority': 1,
'project_id': 176637191,
'responsible_uid': None,
'sync_id': None,
'user_id': 1
}),
Item({
'all_day': False,
'assigned_by_uid': 1,
'checked': 0,
'collapsed': 0,
'content': 'Task2',
'date_added': '2016-08-01T13:19:45Z',
'due': None,
'day_order': 1,
'id': 102835617,
'in_history': 0,
'parent_id': None,
'is_deleted': 0,
'child_order': 2,
'labels': [],
'priority': 1,
'project_id': 176637191,
'responsible_uid': None,
'sync_id': None,
'user_id': 1
})
)
Let’s create two new tasks in one go, and observe the result of our action.
Using curl
We use the sync call, and then specify the following arguments:
- The user’s API token, same as on the previous requests.
- The sync token that we received as reply on our previous request.
- For this example we get back both projects and items changed since last sync,
so we set
resource_types='["projects", "items"]'. - We send two
item_addcommands that will create a new task each, and we also specify theproject_idand thecontentof each new task, and for one of the tasks we use thetemp_idof the previously created project, while for the other task we use the project’s real ID, and we do that just to show that it has the same result. - We also need to specify the
uuidandtemp_id, for the two commands and the two new tasks respectively.
In the results we get back, we notice the following:
- An empty
projectsarray, which is expected as no new projects were added by our commands. - The new tasks we added are returned as part of the user’s
itemsarray. - The
temp_id_mappingobject which tells us the real IDs of the new tasks, for each of thetemp_ids we sent. - The
sync_statusobject which tells us whether each command was successful. - The special flag
full_syncwhich is set tofalsehere, and denotes we did an incremental sync. - A new
sync_tokenwhich we can use later on to do more incremental syncs.
Using the Python library
We call the api.items.add() call, supplying the content of each new task and
the project it should be added to, and as a return value we get a new item
object, that holds the new task, and which we store to a variable. Notice that
we can get the project ID from the project1 object we created on the previous
step, and specifically from the project1['id'] value.
In order to actually add the tasks on the server, we do an api.commit() call,
and so both item objects are populated with the properties these new tasks have.
Finally we print the new task1 and task2 objects.
Update the content and due date of a task
The example of how we update the content and due date of a task:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token="Gm7DEx2RBn-mW9xGIJhAPOGRPWSlewfxGm0aY_W6IhThCp_8DDXmPU8ERu8u" \
-d resource_types='["items"]' \
-d commands='[
{ "type": "item_update",
"uuid": "aca17834-da6f-4605-bde0-bd10be228878",
"args": { "id": "102835615", "content": "NewTask1", "due": {"string": "tomorrow at 10:00" } } },
]'
{
"items" : [
{
"sync_id" : null,
"project_id" : 176637191,
"labels" : [],
"is_deleted" : 0,
"child_order" : 1,
"checked" : 0,
"priority" : 1,
"id" : 102835615,
"added_by_uid": 1,
"assigned_by_uid" : 1,
"all_day" : false,
"day_order" : -1,
"collapsed" : 0,
"due": {
"date": "2016-08-05T07:00:00Z",
"timezone": null,
"is_recurring": false,
"string": "tomorrow at 10:00",
"lang": "en"
},
"responsible_uid" : null,
"content" : "NewTask1",
"user_id" : 1,
"in_history" : 0,
"parent_id" : null,
"date_added" : "2016-08-01T13:19:45Z"
}
],
"sync_status" : {
"aca17834-da6f-4605-bde0-bd10be228878" : "ok"
},
"temp_id_mapping" : {}
"sync_token" : "Zs1ahJjWROqjBMIJGCAmsToOXOEP-wa9x3HiuBEyr6ymUYoyAyhIHeXkS9HE9HfFXcAO",
"full_sync" : false,
}
>>> task2 = api.items.add('Task2', project_id=project1['id'])
>>> task1.update(content='NewTask1', due={'string': 'tomorrow at 10:00'})
>>> api.commit()
>>> print(task1)
Item({
'all_day': False,
'assigned_by_uid': 1,
'checked': 0,
'collapsed': 0,
'content': 'NewTask1',
'date_added': '2016-08-01T13:19:45Z',
'day_order': -1,
'id': 102835615,
'in_history': 0,
'parent_id': None,
'is_deleted': 0,
'child_order': 1,
'labels': [],
'priority': 1,
'project_id': 176637191,
'responsible_uid': None,
'sync_id': None,
'user_id': 1,
'due': {
'date': '2016-08-05T07:00:00Z',
'timezone': None,
'is_recurring': False,
'string': 'tomorrow at 10:00',
'lang': 'en'
}
})
Let’s update the content and due date of the first task we created in the previous step.
Using curl
We use the sync call, and then specify the following arguments:
- The user’s API token same as on the previous requests.
- The sync token that we received as reply on our previous request.
- For this example lets get back only items changed since our last sync, so we
set
resource_types='["items"]'. - We send an
item_updatecommand that will update the task we created earlier, so we specify theidof the task, its newcontent, and its new due date by setting thedueproperty with a new due date instance. - We also need to specify the
uuidfor this command.
In the results we get back, we notice the following:
- The updates to all items since our last sync are returned as part of the
user’s
itemsarray. - The updated item which contains a fully populated due object.
- The
temp_id_mappinghere is empty since no new object was created. - The
sync_statusobject which tells us whether our command was successful. - The special flag
full_syncwhich is set tofalsehere, and denotes we did an incremental sync. - A new
sync_tokenwhich we can use later on to do more incremental syncs.
Using the Python library
We call the update() call on the task1 object that we got in the previous
step, so we call task1.update(), and we specify the new content=NewTask1 and
due='{'string': 'tomorrow at 10:00'} parameters, in order to change these specific
properties of the task.
In order to update the task on the server, we do an api.commit() call.
Finally we print the task1 object, which has now its properties automatically
updated.
Complete a task and delete another task
The example of how we complete a task an delete another task:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token="Gm7DEx2RBn-mW9xGIJhAPOGRPWSlewfxGm0aY_W6IhThCp_8DDXmPU8ERu8u" \
-d resource_types='["items"]' \
-d commands='[
{ "type": "item_complete",
"uuid": "7d9355c5-bd28-4d39-8b8b-0b7a7682eaa2",
"args": { "ids": ["102835615"] } },
{ "type": "item_delete",
"uuid": "c27ee0dd-71b8-4725-af5c-3f6327bacdb4",
"args": { "ids": ["102835617"] } },
]'
{
"items" : [
{
"date_added" : "2016-08-01T13:19:45Z",
"added_by_uid": 1,
"assigned_by_uid" : 1,
"priority" : 1,
"user_id" : 1,
"all_day" : false,
"responsible_uid" : null,
"labels" : [],
"checked" : 0,
"day_order" : -1,
"project_id" : 176637191,
"due" : null,
"child_order" : 2,
"collapsed" : 0,
"in_history" : 0,
"parent_id" : null,
"content" : "Task2",
"sync_id" : null,
"id": 102835617,
"is_deleted" : 1
},
{
"date_added" : "2016-08-01T13:19:45Z"
"labels" : [],
"responsible_uid" : null,
"all_day" : false,
"added_by_uid": 1,
"assigned_by_uid" : 1,
"priority" : 1,
"user_id" : 1,
"parent_id" : null,
"in_history" : 1,
"collapsed" : 0,
"child_order" : 32,
"due": {
"date": "2016-08-05T07:00:00Z",
"timezone": null,
"is_recurring": false,
"string": "tomorrow at 10:00",
"lang": "en"
},
"project_id" : 176637191,
"day_order" : 0,
"checked" : 1,
"is_deleted" : 0,
"id": 102835615,
"content" : "NewTask1",
"sync_id" : null
}
],
"sync_status" : {
"7d9355c5-bd28-4d39-8b8b-0b7a7682eaa2" : "ok"
"c27ee0dd-71b8-4725-af5c-3f6327bacdb4" : "ok"
},
"temp_id_mapping" : {}
"sync_token" : "zjx5pDbKKJGYFZ1VBYlLvvBdZOBvrY_8QNKaMXoE4Vcp_WyLevfDJ4ebsFiu",
"full_sync" : false,
}
>>> task1.complete()
>>> task2.delete()
>>> api.commit()
>>> print(task1, task2)
(
Item({
'all_day': False,
'assigned_by_uid': 1,
'checked': 1,
'collapsed': 0,
'content': 'NewTask1',
'date_added' : '2016-08-01T13:19:45Z'
'day_order': 0,
'due': {
'date': '2016-08-05T07:00:00Z',
'timezone': None,
'is_recurring': False,
'string': 'tomorrow at 10:00',
'lang': 'en'
},
'id': 102835615,
'in_history': 1,
'parent_id': None,
'is_deleted': 0,
'child_order': 2,
'labels': [],
'priority': 1,
'project_id' : 176637191,
'responsible_uid': None,
'sync_id': None,
'user_id': 1
}),
Item({
'all_day': False,
'assigned_by_uid': 1,
'checked': 0,
'collapsed': 0,
'content': 'Task2',
'date_added' : '2016-08-01T13:19:45Z',
'day_order': 1,
'due': None,
'id': 102835617,
'in_history': 0,
'parent_id': None,
'is_deleted': 1,
'child_order': 2,
'labels': [],
'priority': 1,
'project_id' : 176637191,
'responsible_uid': None,
'sync_id': None,
'user_id': 1
})
)
Let’s complete the task we updated in the previous step, and delete the task we created earlier.
Using curl
We use the sync call, and then specify the following arguments:
- The user’s API token same as on the previous requests.
- The sync token that we received as reply on our previous request.
- For this example lets get back only items changed since last sync, so we set
resource_types='["items"]'. - We send an
item_completecommand that will completed the task, and we specify only theidsparameter with the ID of the task, and also we send anitem_deletecommand that will delete the other task, and this command also expects anidsparameter. - We also need to specify the
uuids for these commands.
In the results we get back, we notice the following:
- The updates to all items since our last sync are returned as part of the
user’s
itemsarray, where we can observe that the task we completed has achecked=1property which denotes it’s now completed, while the other task has ais_deleted=1property which denotes it’s now deleted. - The
temp_id_mappinghere is empty since no new object was created. - The
sync_statusobject which tells us whether our command was successful. - The special flag
full_syncwhich is set tofalsehere, and denotes we did an incremental sync. - A new
sync_tokenwhich we can use later on to do more incremental syncs.
Using the Python library
We call the complete() method on the task1 object that we have already
stored from earlier, and also the delete() method on the task2 object.
In order to actually complete and delete the tasks on the server, we do an
api.commit() call.
Finally we print the task1 and task2 objects, and we can observe that their
checked=1 and is_deleted=1 properties have been set accordingly.
Add a new task with a note and a reminder
The example of how we create a new task with a note and a reminder:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token="VRyFHr0Qo3Hr--pzINyT6nax4vW7X2YG5RQlw3lB-6eYOPbSZVJepa62EVhO" \
-d resource_types='["projects", "items"]' \
-d commands='[
{ "type": "item_add",
"temp_id": "160070ed-79a9-4e6b-988b-169052e9ef22",
"uuid": "cf6c3ef7-5579-40c2-87e1-b30a1f3cbefe",
"args": { "project_id": "176637191", "content": "Task3", "date": {"string": "monday 11am"} } },
{ "type": "note_add",
"temp_id": "7f4de51a-3b12-4364-a98b-26f041293eba",
"uuid": "0d9a0925-067e-47fb-9a86-c0cf359afd9f",
"args": { "item_id": "160070ed-79a9-4e6b-988b-169052e9ef22", "content": "Comment3" } },
{ "type": "reminder_add",
"temp_id": "cda5ffcd-5035-47d9-a683-5dddce096811",
"uuid": "843a5719-b204-4f6e-9ff3-f55cb9140ba1",
"args": { "item_id": "160070ed-79a9-4e6b-988b-169052e9ef22","date": {"string": "monday 10:45am"}} },
]'
{
"items" : [
{
"date_added" : "2016-08-05T11:47:58Z",
"all_day" : false,
"day_order" : 2,
"user_id" : 1,
"project_id" : 176637191,
"sync_id" : null,
"responsible_uid" : null,
"parent_id" : null,
"content" : "Task3",
"collapsed" : 0,
"in_history" : 0,
"labels" : [],
"child_order" : 1,
"due": {
"date": "2016-08-08T11:00:00Z",
"timezone": null,
"is_recurring": false,
"string": "8 Aug 11:00 AM",
"lang": "en"
},
"id" : 103184669,
"checked" : 0,
"added_by_uid": 1,
"assigned_by_uid" : 1,
"priority" : 1,
"is_deleted" : 0
}
],
"notes" : [
{
"project_id" : 176637191,
"content" : "Comment3",
"posted_uid" : 1,
"file_attachment" : null,
"is_deleted" : 0,
"id" : 24124658,
"posted" : "2016-08-05T11:47:58Z",
"uids_to_notify" : null,
"item_id" : 103184669
}
],
"reminders" : [
{
"mm_offset" : 180,
"notify_uid" : 1,
"service" : "email",
"is_deleted" : 0,
"type" : "absolute",
"id" : 29173254,
"due": {
"date": "2016-08-08T10:45:00Z",
"timezone": null,
"is_recurring": false,
"string": "8 Aug 10:45 AM",
"lang": "en"
},
"item_id" : 103184669
}
],
"temp_id_mapping" : {
"160070ed-79a9-4e6b-988b-169052e9ef22" : 103184669,
"cda5ffcd-5035-47d9-a683-5dddce096811" : 29173254,
"7f4de51a-3b12-4364-a98b-26f041293eba" : 24124658,
},
"sync_status" : {
"cf6c3ef7-5579-40c2-87e1-b30a1f3cbefe" : "ok",
"0d9a0925-067e-47fb-9a86-c0cf359afd9f" : "ok",
"843a5719-b204-4f6e-9ff3-f55cb9140ba1" : "ok"
},
"full_sync" : false,
"sync_token" : "Fg9VYMugYcPg2PPLDQMyFuvI3XxeL3moh5NsrakQbhpU8ld0AdN6KbZJhwrz",
}
# quick/add
$ curl https://api.todoist.com/sync/v8/quick/add \
-d token=0123456789abcdef0123456789abcdef01234567
-d content="Task3 Monday 11am" \
-d note="Comment3" \
-d reminder="Monday 10:45am"
>>> task3 = api.items.add('Task3', project_id=project1['id'], due={'string': 'Monday 11am'})
>>> comment3 = api.notes.add(task3['id'], 'Comment3')
>>> reminder3 = api.reminders(task3['id'], due={'string': 'Monday 10:45am'})
>>> api.commit()
print(task3, comment3, reminder3)
(
Item({
'all_day': False,
'assigned_by_uid': 1,
'checked': 0,
'collapsed': 0,
'content': 'Task3',
'due': {
'date': '2016-08-08T11:00:00Z',
'timezone': None,
'is_recurring': False,
'string': '8 Aug 11:00 AM',
'lang': 'en'
},
'date_added' : '2016-08-05T11:47:58Z',
'day_order': -1,
'id' : 103184669,
'in_history': 0,
'parent_id': None,
'is_deleted': 0,
'child_order': 1,
'labels': [],
'priority': 1,
'project_id' : 176637191,
'responsible_uid': None,
'sync_id': None,
'user_id': 1
}),
Note({
'content': 'Comment3',
'file_attachment': None,
'id' : 24124658,
'is_deleted': 0,
'item_id': 103184669,
'posted' : '2016-08-05T11:47:58Z',
'posted_uid': 1,
'project_id' : 176637191,
'uids_to_notify': None
}),
Reminder({
'due': {
'date': '2016-08-08T10:45:00Z',
'timezone': None,
'is_recurring': False,
'string': '8 Aug 10:45 AM',
'lang': 'en'
},
'id' : 29173254,
'is_deleted': 0,
'item_id': 103184669,
'mm_offset': 180,
'notify_uid': 1,
'service': 'email',
'type': 'absolute'
})
)
Let’s create a new task, add a new comment, and also set a reminder based on its due date.
Using curl
We use the sync call, and then specify the following arguments:
- The user’s API token same as on the previous requests.
- The sync token that we received as reply on our previous request.
- For this example lets get back items, notes and reminders, changed since last
sync, so we set
resource_types='["items", "notes", "reminders"]'. - We send an
item_addcommand that will add the new task, anote_addcommand that will add a note to the new task, and we do that by specifying thetemp_idof the new task as theitem_idfor thenote_addcommand, and areminder_addcommand that will create a reminder for our task, again using thetemp_idof the task as theitem_idof thereminder_addcommand. - We also need to specify the
uuidfor all commands.
In the results we get back, we notice the following:
- The updates to all items, notes and reminders since our last sync, are returned as the equivalent arrays, and we can observe all three new objects created.
- The
temp_id_mappinghere contains the real IDs of the task, note and reminder. - The
sync_statusobject which tells us whether our commands were successful. - The special flag
full_syncwhich is set tofalsehere, and denotes we did an incremental sync. - A new
sync_tokenwhich we can use later on to do more incremental syncs.
Using the Python library
We call the api.items.add() method to create the new task. and we store the
object in the task3 variable. We then use the value of task3['id'] as the
argument to the api.notes.add() and api.reminders.add() methods that create
the new note and reminder respectively. And we store the results to the
comment3 and reminder3 variables.
In order to actually create all the objects on the server, we do an
api.commit() call.
Finally we print the task3, comment3 and reminder3 objects.
Authorization
In order to make authorized calls to Todoist APIs, your application must first obtain an access token from the users. This section describes the different ways of obtaining such a token.
For the sake of simplicity we decided to not list the token on every parameter table but please note that the token is required for every resource.
Note that we encourage your application to use the OAuth protocol to obtain the access token from the user.
OAuth
External applications could obtain a user authorized API token via the OAuth2
protocol. Before getting started, developers need to create their applications
in App Management Console and configure a valid OAuth
redirect URL. A registered Todoist application is assigned a unique Client ID
and Client Secret which are needed for the OAuth2 flow.
This procedure is comprised of 3 steps, which will be described below.
Step 1: The authorization request
An example of the URL to the authorization endpoint:
https://todoist.com/oauth/authorize?client_id=0123456789abcdef&scope=data:read,data:delete&state=secretstring
Redirect users to the authorization URL at the endpoint
https://todoist.com/oauth/authorize, with the specified request parameters.
Here follow the required parameters:
| Name | Description |
|---|---|
| client_id String | The unique Client ID of the Todoist application that you registered. |
| scope String | A comma separated list of permissions that you would like the users to grant to your application. See below a table with more details about this. |
| state String | A unique and unguessable string. It is used to protect you against cross-site request forgery attacks. |
Here are the scope parameters mentioned before:
| Name | Description |
|---|---|
| task:add | Grants permission to add tasks to the Inbox project (the application cannot read tasks data). This is only used by the helper method of adding an item. |
| data:read | Grants read-only access to application data, including tasks, projects, labels, and filters. |
| data:read_write | Grants read and write access to application data, including tasks, projects, labels, and filters. This scope includes task:add and data:read scopes. |
| data:delete | Grants permission to delete application data, including tasks, labels, and filters. |
| project:delete | Grants permission to delete projects. |
And here are some common errors that you may encounter:
| Error | Description |
|---|---|
| User Rejected Authorization Request | When the user denies your authorization request, Todoist will redirect the user to the configured redirect URI with the error parameter: http://example.com?error=access_denied. |
| Redirect URI Not Configured | This JSON error will be returned to the requester (your user’s browser) if redirect URI is not configured in the App Management Console. |
| Invalid Application Status | When your application exceeds the maximum token limit or when your application is being suspended due to abuse, Todoist will redirect the user to the configured redirect URI with the error parameter: http://example.com?error=invalid_application_status. |
| Invalid Scope | When the scope parameter is invalid, Todoist will redirect the user to the configured redirect URI with error parameter: http://example.com?error=invalid_scope. |
Step 2: The redirection to your application site
When the user grants your authorization request, the user will be redirected to
the redirect URL configured in your application setting. The redirect request
will come with two query parameters attached: code and state.
The code parameter contains the authorization code that you will use to
exchange for an access token. The state parameter should match the state
parameter that you supplied in the previous step. If the state is unmatched,
your request has been compromised by other parties, and the process should be
aborted.
Step 3: The token exchange
An example of exchanging the token:
$ curl "https://todoist.com/oauth/access_token" \
-d "client_id=0123456789abcdef" \
-d "client_secret=secret" \
-d "code=abcdef" \
-d "redirect_uri=https://example.com"
On success, Todoist returns HTTP 200 with token in JSON object format:
{
"access_token": "0123456789abcdef0123456789abcdef01234567",
"token_type": "Bearer"
}
Once you have the authorization code, you can exchange it for the access token
by doing a POST request to the following endpoint:
https://todoist.com/oauth/access_token.
Here follow the required parameters:
| Name | Description |
|---|---|
| client_id String | The unique Client ID of the Todoist application that you registered. |
| client_secret String | The unique Client Secret of the Todoist application that you registered. |
| code String | The unique string code that you obtained in the previous step. |
And here are some common errors that you may encounter (all the error responses will be in JSON format):
| Error | Description |
|---|---|
| Bad Authorization Code Error | Occurs when the code parameter does not match the code that is given in the redirect request: {"error": "bad_authorization_code"} |
| Incorrect Client Credentials Error | Occurs when the client_id or client_secret parameters are incorrect: {"error": "incorrect_application_credentials"} |
Revoke Access Tokens
curl -X POST https://api.todoist.com/sync/v8/access_tokens/revoke \
-H "Content-Type: application/json" \
-d '{"client_id":"xyz", "client_secret":"xyz", "access_token":"xyz"}'
Access tokens obtained via OAuth could be revoked making a JSON request (HTTP POST) to the following endpoint:
https://api.todoist.com/sync/v8/access_tokens/revoke
Parameters:
| Name | Required | Description |
|---|---|---|
| client_id String | Yes | The unique Client ID of the Todoist application that you registered. |
| client_secret String | Yes | The unique Client Secret of the Todoist application that you registered. |
| access_token String | Yes | Access token obtained from the OAuth authentication |
Upon successful request, a HTTP 204 response will be returned.
Migrate Personal Tokens to OAuth Tokens
curl -X POST https://api.todoist.com/sync/v8/access_tokens/migrate_personal_token \
-H "Content-Type: application/json" \
-d '{"client_id":"xyz", "client_secret":"xyz", "personal_token":"xyz", "scope": "data:read"}'
{"access_token": "....", "token_type": "Bearer"}
Tokens obtained via the old email/password authentication method could be migrated to the new OAuth access token. Migrating your users’ personal tokens will allow users to see your app in their Todoist Settings page and give them the ability to manage their app authorization.
Here is the migration API endpoint (HTTP POST, with JSON request parameters):
https://api.todoist.com/sync/v8/access_tokens/migrate_personal_token
Parameters:
| Name | Required | Description |
|---|---|---|
| client_id String | Yes | The unique Client ID of the Todoist application that you registered. |
| client_secret String | Yes | The unique Client Secret of the Todoist application that you registered. |
| personal_token String | Yes | Token obtained from the email/password authentication |
| scope String | Yes | Scopes of the OAuth token. Please refer to the OAuth section for the detailed list of available scopes. |
Upon successful request, a HTTP 200 response will be returned with a new OAuth token in JSON format:
{"access_token": "....", "token_type": "Bearer"}
Cross Origin Resource Sharing
CORS headers example:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-H 'Origin: http://example.com'
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: false
Access-Control-Allow-Origin: *
>>> import requests
>>> requests.post('https://api.todoist.com/sync/v8/sync',
... data={'token': '0123456789abcdef0123456789abcdef01234567'},
... headers={'Origin': 'https://example.com'}).headers
{'Access-Control-Allow-Credentials': 'false', 'Access-Control-Allow-Origin': '*', <...>}
All API endpoints not related to the 3 OAuth steps support Cross Origin Resource
Sharing (CORS) for requests from any origin. The header
Access-Control-Allow-Origin: * is set for successfully authenticated requests.
Sync
Todoist API (also known as the “Sync API”) is specially designed for efficient data sync between clients (e.g. our mobile apps) and Todoist.
All Sync API requests share the same endpoint URL: https://api.todoist.com/sync/v8/sync
Sync API requests should be made in HTTP POST (application/x-www-form-urlencoded). Sync API responses, including errors, will be returned in JSON.
Sync API supports the following features:
- Batching: reading and writing of multiple resources can be done in a single HTTP request. Batch requests help clients reduce the number of network calls needed to sync resources.
- Incremental sync: You only retrieve data that are updated since the last time you performed a sync request.
Refer to limits to learn more about the number of requests/commands you have for the Sync API
Read resources
An example response of a read request.
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d sync_token='*' \
-d resource_types='["all"]'
{
"collaborators": [ ... ],
"collaborator_states": [ ... ],
"day_orders": { ... },
"filters": [ ... ],
"full_sync" : true,
"items": [ ... ],
"labels": [ ... ],
"live_notifications": [ ... ],
"live_notifications_last_read_id": 0,
"notes": [ ... ],
"project_notes": [ ... ],
"projects": [ ... ],
"reminders": [ ... ],
"sections": [ ... ],
"settings_notifications": { ... },
"sync_token": "JLlaPv840mDQK4PLl6-hmjYMbP2h_RHsfPmIXuqmJI_zRiQHFww9olfDvSSpw74nrdvS",
"temp_id_mapping": { ... },
"user": { ... },
"user_settings": { ... }
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.sync()
{
'collaborators': [ ... ],
'collaborator_states': [ ... ],
'day_orders': { ... },
'filters': [ ... ],
'full_sync' : True,
'items': [ ... ],
'labels': [ ... ],
'live_notifications': [ ... ],
'live_notifications_last_read_id': 0,
'notes': [ ... ],
'project_notes': [ ... ],
'projects': [ ... ],
'reminders': [ ... ],
'sections': [ ... ],
'settings_notifications: { ... },
'sync_token': 'JLlaPv840mDQK4PLl6-hmjYMbP2h_RHsfPmIXuqmJI_zRiQHFww9olfDvSSpw74nrdvS',
'temp_id_mapping': { ... },
'user': { ... },
'user_settings': { ... }
}
Note that the following parameters mostly make sense when sending commands in the shell with curl, and not with the Python library, as many things are automated there. For example by default the Python library fetches all resource types and then always does incremental syncs, so there’s no need to specify most of the following parameters.
To retrieve your user resources, make a Sync API request with the following parameters:
Parameters
| Parameter | Required | Description |
|---|---|---|
| token String | Yes | The user’s API token |
| sync_token String | Yes | A special string, used to allow the client to perform incremental sync. Pass * to retrieve all active resource data. More details about this below. |
| resource_types JSON array of strings | Yes | Used to specify what resources to fetch from the server. It should be a JSON-encoded array of strings. Here is a list of available resource types: labels, projects,items, notes, sections, filters, reminders, locations, user, live_notifications, collaborators, user_settings, notification_settings, user_plan_limits. You may use all to include all the resource types. Resources can also be excluded by prefixing a - prior to the name, for example, '-projects' |
Incremental sync
Note that the Python library always does incremental syncs under the hood, so there’s no reason to worry about them if you use it.
The Sync API allows clients to retrieve only updated resources, and this is done
by using the “synchronization token”, sync_token, in your Sync API request.
On your initial sync request, specify sync_token=* in your request, and all
the user’s active resource data will be returned. Todoist API server will also
return a new sync_token in the Sync API response.
In your subsequent Sync request, use the sync_token that you received from
your previous sync response, and the Todoist API server will return only the
updated resource data.
Response
When the request succeeds, an HTTP 200 response will be returned with a JSON
object containing the requested resources and also a new sync_token.
| Field | Description |
|---|---|
| sync_token | A new synchronization token. Used by the client in the next sync request to perform an incremental sync. |
| full_sync | Whether the response contains all data (a full synchronization) or just a part of them since the last sync. |
| user | A user object. |
| projects | An array of project objects. |
| items | An array of item objects. |
| notes | An array of item note objects. |
| project_notes | An array of project note objects. |
| sections | An array of section objects. |
| labels | An array of label objects. |
| filters | A array of filter objects. |
| day_orders | A JSON object specifying the order of items in daily agenda. |
| reminders | An array of reminder objects. |
| collaborators | A JSON object containing all collaborators for all shared projects. The projects field contains the list of all shared projects, where the user acts as one of collaborators. |
| collaborators_states | An array specifying the state of each collaborator in each project. The state can be invited, active, inactive, deleted. |
| live_notifications | An array of live_notification objects |
| live_notifications_last_read | What is the last live notification the user has seen? This is used to implement unread notifications. |
| user_settings | A JSON object containing user settings. |
| user_plan_limits | A JSON object containing user plan limits. |
Write resources
Example API call that creates a new project.
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "project_add", "temp_id": "381e601f-0ef3-4ed6-bf95-58f896d1a314", "uuid": "ed1ce597-e4c7-4a88-ba48-e048d827c067", "args": {"name": "Project1", "color": 1}}]'
{
"sync_token": "JLlaPv840mDQK4PLl6-hmjYMbP2h_RHsfPmIXuqmJI_zRiQHFww9olfDvSSpw74nrdvS",
"sync_status": {"ed1ce597-e4c7-4a88-ba48-e048d827c067": "ok"},
"temp_id_mapping": {"381e601f-0ef3-4ed6-bf95-58f896d1a314": 128501470}
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.sync(commands=[{'type': 'project_add', 'temp_id': '381e601f-0ef3-4ed6-bf95-58f896d1a314', 'uuid': 'ed1ce597-e4c7-4a88-ba48-e048d827c067', 'args': {'name': 'Project1', 'color': 1}}]
{
'sync_status': {'ed1ce597-e4c7-4a88-ba48-e048d827c067': 'ok'},
'temp_id_mapping': {'381e601f-0ef3-4ed6-bf95-58f896d1a314': 128501470},
'sync_token': 'JLlaPv840mDQK4PLl6-hmjYMbP2h_RHsfPmIXuqmJI_zRiQHFww9olfDvSSpw74nrdvS'
}
Note that the Python example is only there to show what is the equivalent for sending commands, but actually there’s no need to use that with the Python library, as it has its own object oriented API which is a lot easier to do various things, so many of the parameters mentioned below do not make much sense for the Python library, and instead you can just use the methods described in the following sections.
To write to your user’s Todoist resources, make a Sync API request with the following parameters
Parameters
| Parameter | Required | Description |
|---|---|---|
| commands JSON | Yes | A JSON array of Command object. Each command will be processed in the specified order. |
| token String | Yes | The user’s API token |
Command object
| Field | Description |
|---|---|
| type String | The type of the command. |
| args Object | The parameters of this specific command. |
| uuid String | Command UUID. More details about this below. |
| temp_id String | Temporary resource ID, Optional. Only specified for commands that create new resource (item_add command). More details about this below. |
Command UUID
Note that the Python library takes care of sending UUIDs, so there’s no need to worry about them if you use it.
API clients should generate a unique string ID for each command and specify it
in the uuid field. The Command UUID will be used for two purposes:
- Command result mapping: Each command’s result will be stored in the
sync_statusfield of the response JSON object. Thesync_statusobject has its key mapped to a command’suuidand its value containing the result of a command. - Command idempotency: Todoist will not execute command that has same UUID as the previously executed commands. This will allow clients to safely retry each command without accidentally performing the command twice.
Temporary resource id
An example that shows how temporary ids can be used and referenced:
[
{ "type": "project_add",
"temp_id": "c7beb07f-b226-4eb1-bf63-30d782b07b1a",
"args": {
"name": "Test Project"
},
"uuid": "ac417051-1cdc-4dc3-b4f8-14526d5bfd16"
},
{
"type": "item_add",
"temp_id": "43f7ed23-a038-46b5-b2c9-4abda9097ffa",
"args": {
"content": "This is a test task",
"project_id": "c7beb07f-b226-4eb1-bf63-30d782b07b1a"
},
"uuid": "849fff4e-8551-4abb-bd2a-838d092775d7"
}
]
You can see that the
project_addcommand specified atemp_idproperty (“c7beb07f-b226-4eb1-bf63-30d782b07b1a”) as placeholder of the actualproject_id. Theitem_addcommand can refrence to this temporary project id. The API will automatically resolve these ids.
Note that the Python library takes care of handling temporary ids, so there’s no reason to worry about them if you use it.
Some commands depend on the result of previous command. For instance, you have a
command sequence: "project_add" and "item_add" which first creates a project
and then add a new task to the newly created project. In order to run the later
item_add command, we need to obtain the project ID returned from the previous
command. Therefore, the normal approach would be to run these two commands in
two separate HTTP requests.
The temporary resource ID feature allows you to run two or more dependent
commands in a single HTTP request. For commands that are related to creation of
resources (i.e. item_add, project_add), you can specify an extra temp_id
as a placeholder for the actual ID of the resource. The other commands in the
same sequence could directly refer to temp_id if needed.
Response / Error
An example of a single request sync return value:
{
"sync_status": {"863aca2c-65b4-480a-90ae-af160129abbd": "ok"}
}
An example of a multiple requests sync return value:
{
"sync_status": {
"32eaa699-e9d7-47ed-91ea-e58d475791f1": "ok",
"bec5b356-3cc1-462a-9887-fe145e3e1ebf": {"error_code": 15, "error": "Invalid temporary id"}
}
}
The result of command executions will be stored in the following response JSON object field:
| Data | Description |
|---|---|
| temp_id_mapping Object | A dictionary object that maps temporary resource ids to real resource ids. |
| sync_status Object | A dictionary object containing result of each command execution. The key will be the command’s uuid field and the value will be the result status of the command execution. |
The status result of each command execution is in the sync_status dictionary
object. The key is a command uuid and the value will be the result status of
the command execution. There are two possible values for each command status -
- an “ok” string which signals success of the command
- an error object containings error information of a command.
Please see the adjacent code examples for the possible format of the
sync_status.
Response status codes
The server uses the HTTP status codes to indicate the success or failure of a request. And as is customary in web servers, a 2xx code indicates - success, a 4xx code - an error due to incorrect user provided information, and a 5xx code - an internal, possibly temporary, error.
| Status code | Description |
|---|---|
| 200 OK | The request was processed successfully. |
| 400 Bad Request | The request was incorrect. |
| 401 Unauthorized | Authentication is required, and has failed, or has not yet been provided. |
| 403 Forbidden | The request was valid, but for something that is forbidden. |
| 404 Not Found | The requested resource could not be found. |
| 429 Too Many Requests | The user has sent too many requests in a given amount of time. |
| 500 Internal Server Error | The request failed due to a server error. |
| 503 Service Unavailable | The server is currently unable to handle the request. |
Projects
An example project object
{
"id": 396936926,
"legacy_id": 128501470,
"name": "Project1",
"color": 30,
"parent_id": null,
"child_order": 1,
"collapsed": 0,
"shared": false,
"parent_id": null,
"legacy_parent_id": null,
"sync_id": null,
"is_deleted": 0,
"is_archived": 0,
"is_favorite": 0
}
Properties
| Property | Description |
|---|---|
| id Integer | The id of the project. |
| legacy_id Integer | The legacy id of the project. (only shown for objects created before 1 April 2017) |
| name String | The name of the project. |
| color Integer | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| parent_id Integer | The id of the parent project. Set to null for root projects. |
| legacy_parent_id Integer | The legacy id of the parent project. Set to null for root projects. (only shown for objects created before 1 April 2017) |
| child_order Integer | The order of project. Defines the position of the task among all the projects with the same parent_id |
| collapsed Integer | Whether the project’s sub-projects are collapsed (where 1 is true and 0 is false). |
| shared Boolean | Whether the project is shared (a true or false value). |
| is_deleted Integer | Whether the project is marked as deleted (where 1 is true and 0 is false). |
| is_archived Integer | Whether the project is marked as archived (where 1 is true and 0 is false). |
| is_favorite Integer | Whether the project is favorite (where 1 is true and 0 is false). |
| sync_id integer | Identifier to find the match between different copes of shared projects. When you share a project, its copy has a different ID for your collaborators. To find a project in a different account that matches yours, you can use the “sync_id” attribute. For non-shared projects the attribute is set to null. |
| inbox_project Boolean | Whether the project is Inbox (true or otherwise this property is not sent). |
| team_inbox Boolean | Whether the project is TeamInbox (true or otherwise this property is not sent). |
Add a project
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "project_add", "temp_id": "4ff1e388-5ca6-453a-b0e8-662ebf373b6b", "uuid": "32774db9-a1da-4550-8d9d-910372124fa4", "args": {"name": "Project4"}}]'
{
...
"sync_status": {"32774db9-a1da-4550-8d9d-910372124fa4": "ok"},
"temp_id_mapping": {"4ff1e388-5ca6-453a-b0e8-662ebf373b6b": 128501815},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project = api.projects.add('Project4')
>>> api.commit()
Add a new project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| name String | Yes | The name of the project (a string value). |
| color Integer | No | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| parent_id Integer | No | The id of the parent project. Set to null for root projects |
| child_order Integer | No | The order of project. Defines the position of the task among all the projects with the same parent_id |
| is_favorite Integer | No | Whether the project is favorite (where 1 is true and 0 is false). |
Update a project
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "project_update", "uuid": "1ca42128-d12f-4a66-8413-4d6ff2838fde", "args": {"id": 128501815, "name": "foo"}}]'
{
...
"sync_status": {"1ca42128-d12f-4a66-8413-4d6ff2838fde": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project = api.projects.get_by_id(128501815)
>>> project.update(name='foo')
>>> api.commit()
Update an existing project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the project (could be temp id). |
| name String | No | The name of the project (a string value). |
| color Integer | No | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| collapsed Integer | No | Whether the project’s sub-projects are collapsed (where 1 is true and 0 is false). |
| is_favorite Integer | No | Whether the project is favorite (where 1 is true and 0 is false). |
Move a project
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "project_move", "uuid": "1ca42128-d12f-4a66-8413-4d6ff2838fde", "args": {"id": 1001, "parent_id": 1002}}]'
{
...
"sync_status": {"1ca42128-d12f-4a66-8413-4d6ff2838fde": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project = api.projects.get_by_id(1001)
>>> project.move(parent_id=1002)
>>> api.commit()
Update parent project relationships of the project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the project (could be temp id). |
| parent_id Integer or String (temp_id) | Yes | The id of the parent project (could be temp id). If set to null, the project will be moved to the root |
Delete a project
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "project_delete", "uuid": "367182ba-125f-4dbb-bff6-c1343fd751e4", "args": {"id": 128501815}}]'
{
...
"sync_status": {"367182ba-125f-4dbb-bff6-c1343fd751e4": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project = api.projects.get_by_id(128501815)
>>> project.delete()
>>> api.commit()
Delete an existing project and all its descendants.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer (id) or String (temp id) | Yes | Id of the project to delete (could be a temp id). |
Archive a project
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "project_archive", "uuid": "bbec1a60-2bdd-48ac-a623-c8eb968e1697", "args": {"id": 128501682}}]'
{
...
"sync_status": {"bbec1a60-2bdd-48ac-a623-c8eb968e1697": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project = api.projects.get_by_id(128501682)
>>> project.archive()
>>> api.commit()
Only available for Todoist Premium users.
Archive a project and its descendants.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer (id) or String (temp id) | Yes | id of the project to archive (could be a temp id). |
Unarchive a project
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "project_unarchive", "uuid": "7d86f042-e098-4fa6-9c1f-a61fe8c39d74", "args": {"id": 128501682}}]'
{
...
"sync_status": {"7d86f042-e098-4fa6-9c1f-a61fe8c39d74": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project = api.projects.get_by_id(128501815)
>>> project.unarchive()
>>> api.commit()
Only available for Todoist Premium users.
Unarchive a project. No ancestors will be unarchived along with the unarchived project. Instead, the project is unarchived alone, loses any parent relationship (becomes a root project), and is placed at the end of the list of other root projects.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer (id) or String (temp id) | Yes | id of the project to unarchive (could be a temp id). |
Reorder projects
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "project_reorder", "uuid": "bf0855a3-0138-4b76-b895-88cad8db9edc", "args": {"projects": [{"id": 128501472, "child_order": 1}, {"id": 128501471, "child_order": 2}]}}]'
{
...
"sync_status": {"bf0855a3-0138-4b76-b895-88cad8db9edc": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> project1 = api.projects.get_by_id(128501472)
>>> project1.reorder(child_order=1)
>>> project2 = api.projects.get_by_id(128501471)
>>> project2.reorder(child_order=2)
>>> api.commit()
The command updates child_order properties of items in bulk.
Command arguments
| Argument | Required | Description |
|---|---|---|
| projects Array of Objects | Yes | An array of objects to update. Each object contains two attribute: id of the project to update and child_order, the new order. |
Templates
Templates allow exporting of a projects tasks into a file or URL, and then importing of the complete task list to a new or existing project. Note that, templates are only available for Todoist Premium users.
Import into project
On success, an HTTP 200 OK with JSON data of file data is returned:
$ curl https://api.todoist.com/sync/v8/templates/import_into_project \
-F token=0123456789abcdef0123456789abcdef01234567 \
-F project_id=128501470 \
-F file=@example.csv
{
"status": "ok"
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.templates.import_into_project(128501470, 'example.csv')
{
'status': 'ok'
}
Upload a file suitable to be passed as a template to be imported into a project.
Export as file
On success, a CSV template is returned:
$ curl https://api.todoist.com/sync/v8/templates/export_as_file \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d project_id=128501470
TYPE,CONTENT,PRIORITY,INDENT,AUTHOR,RESPONSIBLE,DATE,DATE_LANG
task,Task1,4,1,Firstname (1),,,en
,,,,,,,
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.templates.export_as_file(128501470)
TYPE,CONTENT,PRIORITY,INDENT,AUTHOR,RESPONSIBLE,DATE,DATE_LANG
task,Task1,4,1,Firstname (1),,,en
,,,,,,,
Get a template for a project as a file.
Export as shareable URL
On success, a URL is returned:
$ curl https://api.todoist.com/sync/v8/templates/export_as_url \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d project_id=128501470
{
"file_name": "*_Project1.csv",
"file_url": "https://*.cloudfront.net/*_Project1.csv"
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.templates.export_as_url(128501470)
{
'file_name': '*_Project1.csv',
'file_url': 'https://*.cloudfront.net/*_Project1.csv'
}
Get a template for a project as a shareable URL.
The URL can then be passed to
https://todoist.com/importFromTemplate?t_url=<url> to make a shareable
template.
Items
An example item object
{
"id": 301946961,
"legacy_id": 33511505,
"user_id": 1855589,
"project_id": 396936926,
"legacy_project_id": 128501470,
"content": "Task1",
"priority": 1,
"due": null,
"parent_id": null,
"legacy_parent_id": null,
"child_order": 1,
"section_id": null,
"day_order": -1,
"collapsed": 0,
"children": null,
"labels": [12839231, 18391839],
"added_by_uid": 1855589,
"assigned_by_uid": 1855589,
"responsible_uid": null,
"checked": 0,
"in_history": 0,
"is_deleted": 0,
"sync_id": null,
"date_added": "2014-09-26T08:25:05Z"
}
Properties
| Property | Description |
|---|---|
| id Integer | The id of the task. |
| legacy_id Integer | The legacy id of the task (only shown for objects created before 1 April 2017) |
| user_id Integer | The owner of the task. |
| project_id Integer | Project that the task resides in |
| legacy_project_id Integer | Legacy project id for the project that the task resides in (only shown for objects created before 1 April 2017) |
| content String | The text of the task |
| due Object | The due date of the task. See the Due dates section for more details. |
| priority Integer | The priority of the task (a number between 1 and 4, 4 for very urgent and 1 for natural). Note: Keep in mind that very urgent is the priority 1 on clients. So, p1 will return 4 in the API. |
| parent_id Integer | The id of the parent task. Set to null for root tasks |
| legacy_parent_id Integer | The legacy id of the parent task. Set to null for root tasks (only shown for objects created before 1 April 2017) |
| child_order Integer | The order of task. Defines the position of the task among all the tasks with the same parent_id |
| section_id Integer | The id of the section. Set to null for tasks not belonging to a section. |
| day_order Integer | The order of the task inside the Today or Next 7 days view (a number, where the smallest value would place the task at the top). |
| collapsed Integer | Whether the task’s sub-tasks are collapsed (where 1 is true and 0 is false). |
| labels Array of Integer | The tasks labels (a list of label ids such as [2324,2525]). |
| added_by_uid Integer | The id of the user who created the current task. This makes sense for shared projects only. For tasks, created before 31 Oct 2019 the value is set to null. Cannot be set explicitly or changed via API. |
| assigned_by_uid Integer | The id of the user who assigns the current task. This makes sense for shared projects only. Accepts any user id from the list of project collaborators. If this value is unset or invalid, it will automatically be set up to your uid. |
| responsible_uid Integer | The id of user who is responsible for accomplishing the current task. This makes sense for shared projects only. Accepts any user id from the list of project collaborators or null or an empty string to unset. |
| checked Integer | Whether the task is marked as completed (where 1 is true and 0 is false). |
| in_history Integer | Whether the task has been marked as completed and is marked to be moved to history, because all the child tasks of its parent are also marked as completed (where 1 is true and 0 is false) |
| is_deleted Integer | Whether the task is marked as deleted (where 1 is true and 0 is false). |
| sync_id Integer | Identifier to find the match between tasks in shared projects of different collaborators. When you share a task, its copy has a different ID in the projects of your collaborators. To find a task in another account that matches yours, you can use the “sync_id” attribute. For non-shared tasks, the attribute is null. |
| date_completed String | The date when the task was completed (or null if not completed). |
| date_added String | The date when the task was created. |
Add an item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_add", "temp_id": "43f7ed23-a038-46b5-b2c9-4abda9097ffa", "uuid": "997d4b43-55f1-48a9-9e66-de5785dfd69b", "args": {"content": "Task1", "project_id": 128501470}}]'
{
...
"sync_status": {"997d4b43-55f1-48a9-9e66-de5785dfd69b": "ok"},
"temp_id_mapping": {"43f7ed23-a038-46b5-b2c9-4abda9097ffa": 33548400},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> item = api.items.add('Task1', project_id=128501470)
>>> api.commit()
Add a new task to a project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| content String | Yes | The text of the task. |
| project_id Integer or String (temp id) | No | The id of the project to add the task to (a number or a temp id). By default the task is added to the user’s Inbox project. |
| due Object | No | The due date of the task. See the Due dates section for more details. |
| priority Integer | No | The priority of the task (a number between 1 and 4, 4 for very urgent and 1 for natural). Note: Keep in mind that very urgent is the priority 1 on clients. So, p1 will return 4 in the API. |
| parent_id Integer | No | The id of the parent task. Set to null for root tasks |
| child_order Integer | No | The order of task. Defines the position of the task among all the tasks with the same parent_id |
| section_id Integer | No | The id of the section. Set to null for tasks not belonging to a section. |
| day_order Integer | No | The order of the task inside the Today or Next 7 days view (a number, where the smallest value would place the task at the top). |
| collapsed Integer | No | Whether the task’s sub-tasks are collapsed (where 1 is true and 0 is false). |
| labels Array of Integer | No | The tasks labels (a list of label ids such as [2324,2525]). |
| assigned_by_uid Integer | No | The id of user who assigns the current task. This makes sense for shared projects only. Accepts 0 or any user id from the list of project collaborators. If this value is unset or invalid, it will be automatically setup to your uid. |
| responsible_uid Integer | No | The id of user who is responsible for accomplishing the current task. This makes sense for shared projects only. Accepts any user id from the list of project collaborators or null or an empty string to unset. |
| auto_reminder Boolean | No | When this option is enabled, the default reminder will be added to the new item if it has a due date with time set. See also the auto_reminder user option for more info about the default reminder. |
| auto_parse_labels Boolean | No | When this option is enabled, the labels will be parsed from the task content and added to the task. In case the label doesn’t exist, a new one will be created. |
Update an item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_update", "uuid": "318d16a7-0c88-46e0-9eb5-cde6c72477c8", "args": {"id": 33548400, "priority": 2}}]'
{
...
"sync_status": {"318d16a7-0c88-46e0-9eb5-cde6c72477c8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> item = api.items.get_by_id(33548400)
>>> item.update(priority=2)
>>> api.commit()
Updates task attributes. Please note that updating the parent, moving,
completing or uncompleting tasks is not supported by item_update, more
specific commands have to be used instead.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | The id of the task. |
| content String | No | The text of the task. |
| due Object | No | The due date of the task. See the Due dates section for more details. |
| priority Integer | No | The priority of the task (a number between 1 and 4, 4 for very urgent and 1 for natural). Note: Keep in mind that very urgent is the priority 1 on clients. So, p1 will return 4 in the API. |
| collapsed Integer | No | Whether the task’s sub-tasks are collapsed (where 1 is true and 0 is false). |
| labels Array of Integer | No | The tasks labels (a list of label ids such as [2324,2525]). |
| assigned_by_uid Integer | No | The id of the user who assigns the current task. This makes sense for shared projects only. Accepts 0 or any user id from the list of project collaborators. If this value is unset or invalid, it will be automatically setup to your uid. |
| responsible_uid Integer | No | The id of user who is responsible for accomplishing the current task. This makes sense for shared projects only. Accepts any user id from the list of project collaborators or null or an empty string to unset. |
| day_order Integer | No | The order of the task inside the Today or Next 7 days view (a number, where the smallest value would place the task at the top). |
Move an item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_move", "uuid": "318d16a7-0c88-46e0-9eb5-cde6c72477c8", "args": {"id": 33548400, "parent_id": 1234}}]'
{
...
"sync_status": {"318d16a7-0c88-46e0-9eb5-cde6c72477c8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> item = api.items.get_by_id(33548400)
>>> item.move(parent_id=1234)
>>> api.commit()
Move task to a different location. Only one of parent_id, section_id or
project_id must be set.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | The id of the task. |
| parent_id Integer or String (temp id) | No | Id of the destination parent task. The task becomes the last child task of the parent task. |
| section_id Integer or String (temp id) | No | Id of the destination section. The task becomes the last root task of the section. |
| project_id Integer or String (temp id) | No | Id of the destination project. The task becomes the last root task of the project. |
Reorder items
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "item_reorder", "uuid": "bf0855a3-0138-4b76-b895-88cad8db9edc", "args": {"items": [{"id": 33548402, "child_order": 1}, {"id": 33548401, "child_order": 2}]}}]'
{
...
"sync_status": {"bf0855a3-0138-4b76-b895-88cad8db9edc": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> item1 = api.items.get_by_id(33548402)
>>> item1.reorder(child_order=1)
>>> item2 = api.items.get_by_id(33548401)
>>> item2.reorder(child_order=2)
>>> api.commit()
The command updates child_order properties of items in bulk.
Command arguments
| Argument | Required | Description |
|---|---|---|
| items Array of Objects | Yes | An array of objects to update. Each object contains two attribute: id of the item to update and child_order, the new order. |
Delete item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_delete", "uuid": "f8539c77-7fd7-4846-afad-3b201f0be8a5", "args": {"id": 33548400}}]'
{
...
"sync_status": {"f8539c77-7fd7-4846-afad-3b201f0be8a5": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> item = api.items.get_by_id(33548400)
>>> item.delete()
>>> api.commit()
Delete a task and all its descendants
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer (id) or String (temp id) | Yes | Id of the task to delete. |
Complete item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_complete", "uuid": "a74bfb5c-5f1d-4d14-baea-b7415446a871", "args": {"id": 33548400, "date_completed": "2017-01-02T01:00:00Z"}}]'
{
...
"sync_status": {"a74bfb5c-5f1d-4d14-baea-b7415446a871": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.get_by_id(33548400)
>>> item.complete()
>>> api.commit()
Complete a task and all its descendants. See also item_close for a
simplified version of the command.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | Task id to complete. |
| date_completed Date | No | RFC3339-formatted date of completion of the task (in UTC). If not set, the server will set the value to the current timestamp |
| force_history Boolean | No | When enabled the item is moved to history irregardless of whether it’s a sub-task or not (by default only root tasks are moved to history). |
Uncomplete item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_uncomplete", "uuid": "710a60e1-174a-4313-bb9f-4df01e0349fd", "args": {"id": 33548400}}]'
{
...
"sync_status": {"710a60e1-174a-4313-bb9f-4df01e0349fd": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.get_by_id(33548400)
>>> item.uncomplete()
>>> api.commit()
This command is used to uncomplete an unarchived item and all its ancestors.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | Task id to uncomplete |
Archive item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_archive", "uuid": "a74bfb5c-5f1d-4d14-baea-b7415446a871", "args": {"id": 33548400}}]'
{
...
"sync_status": {"a74bfb5c-5f1d-4d14-baea-b7415446a871": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.get_by_id(33548400)
>>> item.archive()
>>> api.commit()
Archive a task and all its descendants. It is mostly intended to allow users
to force sub-tasks to be moved to the history since root tasks are
automatically archived upon completion. See also item_close for a
simplified version of the command.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | Task id to archive. |
Unarchive item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_unarchive", "uuid": "710a60e1-174a-4313-bb9f-4df01e0349fd", "args": {"id": 33548400}}]'
{
...
"sync_status": {"710a60e1-174a-4313-bb9f-4df01e0349fd": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.get_by_id(33548400)
>>> item.unarchive()
>>> api.commit()
This command is used to unarchive an item that is in history. No ancestors will be restored from the history. Instead, the item is unarchived (and uncompleted) alone, loses any parent relationship (becomes a project root item), and is placed at the end of the list of other project root items.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | Task id to unarchive |
Complete a recurring task
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_update_date_complete", "uuid": "c5888360-96b1-46be-aaac-b49b1135feab", "args": {"id": 33548400, "due": {"date": "2014-10-30", "string": "every day"}, "is_forward": 1}}]
{
...
"sync_status": {"c5888360-96b1-46be-aaac-b49b1135feab": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.update_date_complete(33548400, '2014-10-30T23:59', 'every day', 1)
>>> api.commit()
Complete a recurring task, and the reason why this is a special case is because
we need to mark a recurring completion (and using item_update won’t do
this). See also item_close for a simplified version of the command.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String | Yes | The id of the item to update (a number or a temp id). |
| due Object | No | The due date of the task. See the Due dates section for more details. |
Close item
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_close", "uuid": "c5888360-96b1-46be-aaac-b49b1135feab", "args": {"id": 33548400}}]'
{
...
"sync_status": {"c5888360-96b1-46be-aaac-b49b1135feab": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.get_by_id(33548400)
>>> item.close()
>>> api.commit()
A simplified version of item_complete / item_update_date_complete. The command
does exactly what official clients do when you close a task: regular task is
completed and moved to history, subtask is checked (marked as done, but not moved
to history), recurring task is moved forward (due date is updated).
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | The id of the item to close (a number or a temp id). |
Update day orders
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "item_update_day_orders", "uuid": "dbeb40fc-905f-4d8a-8bae-547d3bbd6e91", "args": {"ids_to_orders": {"33548400": 1}}}]'
{
...
"sync_status": {"dbeb40fc-905f-4d8a-8bae-547d3bbd6e91": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.update_day_orders({33548400: 1})
>>> api.commit()
Update the day orders of multiple items at once.
Command arguments
| Argument | Required | Description |
|---|---|---|
| ids_to_orders Object | Yes | A dictionary, where an item id is the key, and the day order its value: item_id: day_order. |
Labels
An example label object
{
"id": 790748,
"name": "Label1",
"color": 30,
"item_order": 0,
"is_deleted": 0,
"is_favorite": 0
}
Properties
| Property | Description |
|---|---|
| id Integer | The id of the label. |
| name String | The name of the label. |
| color Integer | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| item_order Integer | Label’s order in the label list (a number, where the smallest value should place the label at the top). |
| is_deleted Integer | Whether the label is marked as deleted (where 1 is true and 0 is false). |
| is_favorite Integer | Whether the label is favorite (where 1 is true and 0 is false). |
Add a label
An example of adding a label:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "label_add", "temp_id": "f2f182ed-89fa-4bbb-8a42-ec6f7aa47fd0", "uuid": "ba204343-03a4-41ff-b964-95a102d12b35", "args": {"name": "Label1"}}]'
{
...
"sync_status": {"ba204343-03a4-41ff-b964-95a102d12b35": "ok"},
"temp_id_mapping": {"f2f182ed-89fa-4bbb-8a42-ec6f7aa47fd0": 790748},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> label = api.labels.add('Label1')
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| name String | Yes | The name of the label |
| color Integer | No | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| item_order Integer | No | Label’s order in the label list (a number, where the smallest value should place the label at the top). |
| is_favorite Integer | No | Whether the label is favorite (where 1 is true and 0 is false). |
Update a label
An example of updating a label:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "label_update", "uuid": "9c9a6e34-2382-4f43-a217-9ab017a83523", "args": {"id": 790748, "color": 30}}]'
{
...
"sync_status": {"9c9a6e34-2382-4f43-a217-9ab017a83523": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> label = api.labels.get_by_id(790748)
>>> label.update(color=30)
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the label. |
| name String | No | The name of the label. |
| color Integer | No | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| item_order Integer | No | Label’s order in the label list. |
| is_favorite Integer | No | Whether the label is favorite (where 1 is true and 0 is false). |
Delete a label
An example of deleting a label:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "label_delete", "uuid": "aabaa5e0-b91b-439c-aa83-d1b35a5e9fb3", "args": {"id": 790748}}]'
{
...
"sync_status": {"aabaa5e0-b91b-439c-aa83-d1b35a5e9fb3": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> label = api.labels.get_by_id(790748)
>>> label.delete()
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the label. |
Update multiple orders
An example of updating the orders of multiple labels at once:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "label_update_orders", "uuid": "1402a911-5b7a-4beb-bb1f-fb9e1ed798fb", "args": {"id_order_mapping": {"790748": 1, "790749": 2}}}]'
{
...
"sync_status": {
"517560cc-f165-4ff6-947b-3adda8aef744": "ok"},
...
},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.labels.update_orders({790748: 1, 790749: 2})
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id_order_mapping Object | Yes | A dictionary, where a label id is the key, and the order its value: label_id: order. |
Notes
An example task note object
{
"id": 285735024,
"legacy_id": 17299568,
"posted_uid": 1855589,
"project_id": 396936926,
"legacy_project_id": 128501470,
"item_id": 301983856,
"legacy_item_id": 33548400,
"content": "Note",
"file_attachment": {
"file_type": "text/plain",
"file_name": "File1.txt",
"file_size": 1234,
"file_url": "https://example.com/File1.txt",
"upload_state": "completed"
},
"uids_to_notify": null,
"is_deleted": 0,
"posted": "2014-10-01T14:54:55Z",
"reactions": {"❤️": [14781321], "👍": [14781321, 12213313]}
}
Notes are only available for Todoist Premium users.
Properties
| Property | Description |
|---|---|
| id Integer | The id of the note. |
| legacy_id Integer | The legacy id of the note. (only shown for objects created before 1 April 2017) |
| posted_uid Integer | The id of the user that posted the note. |
| item_id Integer | The item which the note is part of. |
| legacy_item_id Integer | The legacy item which the note is part of. (only shown for objects created before 1 April 2017) |
| project_id Integer | The project which the note is part of. |
| legacy_project_id Integer | The legacy project which the note is part of. (only shown for objects created before 1 April 2017) |
| content String | The content of the note. |
| file_attachment Object | A file attached to the note (see more details about attachments later on). |
| uids_to_notify Array of Integer | A list of user ids to notify. |
| is_deleted Integer | Whether the note is marked as deleted (where 1 is true and 0 is false). |
| posted String | The date when the note was posted. |
| reactions Object | List of emoji reactions and corresponding user ids. |
File attachments
A file attachment is represented as a JSON object. The file attachment may point
to a document previously uploaded by the uploads/add API call, or by any
external resource.
Base file properties
| Attribute | Description |
|---|---|
| file_name String | The name of the file. |
| file_size Integer | The size of the file in bytes. |
| file_type String | MIME type (for example text/plain or image/png). |
| file_url String | The URL where the file is located. Note that we don’t cache the remote content on our servers and stream or expose files directly from third party resources. In particular this means that you should avoid providing links to non-encrypted (plain HTTP) resources, as exposing this files in Todoist may issue a browser warning. |
| upload_state String | Upload completion state (for example pending or completed). |
Image file properties
If you upload an image, you may provide thumbnail paths to ensure Todoist
handles them appropriately. Valid thumbnail information is a JSON array with
URL, width in pixels, height in pixels. Ex.:
[“http://example.com/img.jpg”,400,300]. “Canonical” thumbnails (ones we create
by uploads/add API call) have the following sizes: 96x96, 288x288,
528x528.
| Attribute | Description |
|---|---|
| tn_l List | Large thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
| tn_m List | Medium thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
| tn_s List | Small thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
Audio file properties
If you upload an audio file, you may provide an extra attribute file_duration
(duration of the audio file in seconds, which takes an integer value). In the
web interface the file is rendered with a <audio> tag, so you should make sure
it’s supported in current web browsers. See
supported media formats for
the reference.
Add a note
An example of adding a note:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_add", "temp_id": "59fe4461-287b-4b00-bacc-ee771137a732", "uuid": "e1005f08-acd6-4172-bab1-4338f8616e49", "args": {"item_id": 33548400, "content": "Note1"}}]'
# or adding a note with a file attached:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_add", "temp_id": "6149e689-1a54-48d6-a8c2-0ee5425554a9", "uuid": "554a65e9-56d9-478e-b35b-520c419e37d9", "args": {"item_id": 33548400, "content": "Note1", "file_attachment": {"file_type":"image\/gif","file_name":"image.gif","image":"https:\/\/domain\/image.gif","file_url":"https:\/\/domain\/image.gif","image_width":90,"image_height":76,"file_size":7962}}}]'
{
...
"sync_status": {"e1005f08-acd6-4172-bab1-4338f8616e49": "ok"},
"temp_id_mapping": {"59fe4461-287b-4b00-bacc-ee771137a732": 17299568},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> note = api.notes.add(33548400, 'Note1')
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| item_id Integer | Yes | The item which the note is part of (a unique number or temp id). |
| content String | Yes | The content of the note (a string value). |
| file_attachment Object | No | A file attached to the note (see more details about attachments above, and learn how to upload a file in the Uploads section). |
| uids_to_notify Array of Integer | No | A list of user ids to notify. |
Update a note
An example of updating a note:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_update", "uuid": "8a38f9c5-2cd0-4da5-87c1-26d617b354e0", "args": {"id": 17299568, "content": "UpdatedNote1"}}]'
{
...
"sync_status": {"8a38f9c5-2cd0-4da5-87c1-26d617b354e0": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> note = api.notes.get_by_id(17299568)
>>> note.update(content='UpdatedNote1')
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the note. |
| content String | Yes | The content of the note. |
| file_attachment Object | No | A file attached to the note (see more details about attachments above, and learn how to upload a file in the Uploads section). |
Delete a note
An example of deleting a note:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_delete", "uuid": "8d666fda-73c3-4677-8b04-5d223632c24f", "args": {"id": 17299568}}]'
{ ...
"sync_status": {"8d666fda-73c3-4677-8b04-5d223632c24f": "ok"},
... }
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> note = api.notes.get_by_id(17299568)
>>> note.delete()
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the note. |
Project Notes
An example project note object
{
"content": "Hello 2",
"file_attachment": {
"file_type": "text/plain",
"file_name": "File1.txt",
"file_size": 1234,
"file_url": "https://example.com/File1.txt",
"upload_state": "completed"
},
"id": 2310972895,
"is_deleted": 0,
"posted": "2018-08-14T10:56:50Z",
"posted_uid": 16017653,
"project_id": 2191777224,
"reactions": null,
"uids_to_notify": [13432367],
"reactions": {"❤️": [14781321], "👍": [14781321, 12213313]}
}
Project Notes are only available for Todoist Premium users.
Properties
| Property | Description |
|---|---|
| id Integer | The id of the note. |
| posted_uid Integer | The id of the user that posted the note. |
| project_id Integer | The project which the note is part of. |
| content String | The content of the note. |
| file_attachment Object | A file attached to the note (see more details about attachments later on). |
| uids_to_notify Array of Integer | A list of user ids to notify. |
| is_deleted Integer | Whether the note is marked as deleted (where 1 is true and 0 is false). |
| posted String | The date when the note was posted. |
| reactions Object | List of emoji reactions and corresponding user ids. |
File attachments
A file attachment is represented as a JSON object. The file attachment may point
to a document previously uploaded by the uploads/add API call, or by any
external resource.
Base file properties
| Attribute | Description |
|---|---|
| file_name String | The name of the file. |
| file_size Integer | The size of the file in bytes. |
| file_type String | MIME type (for example text/plain or image/png). |
| file_url String | The URL where the file is located. Note that we don’t cache the remote content on our servers and stream or expose files directly from third party resources. In particular this means that you should avoid providing links to non-encrypted (plain HTTP) resources, as exposing this files in Todoist may issue a browser warning. |
| upload_state String | Upload completion state (for example pending or completed). |
Image file properties
If you upload an image, you may provide thumbnail paths to ensure Todoist
handles them appropriately. Valid thumbnail information is a JSON array with
URL, width in pixels, height in pixels. Ex.:
[“http://example.com/img.jpg”,400,300]. “Canonical” thumbnails (ones we create
by uploads/add API call) have the following sizes: 96x96, 288x288,
528x528.
| Attribute | Description |
|---|---|
| tn_l List | Large thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
| tn_m List | Medium thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
| tn_s List | Small thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
Audio file properties
If you upload an audio file, you may provide an extra attribute file_duration
(duration of the audio file in seconds, which takes an integer value). In the
web interface the file is rendered with a <audio> tag, so you should make sure
it’s supported in current web browsers. See
supported media formats for
the reference.
Add a note
An example of adding a project note:
curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_add", "temp_id": "59fe4461-287b-4b00-bacc-ee771137a732", "uuid": "e1005f08-acd6-4172-bab1-4338f8616e49", "args": {"project_id": 2191777224, "content": "Note1"}}]'
# or adding a note with a file attached:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_add", "temp_id": "6149e689-1a54-48d6-a8c2-0ee5425554a9", "uuid": "554a65e9-56d9-478e-b35b-520c419e37d9", "args": {"project_id": 2191777224, "content": "Note1", "file_attachment": {"file_type":"image\/gif","file_name":"image.gif","image":"https:\/\/domain\/image.gif","file_url":"https:\/\/domain\/image.gif","image_width":90,"image_height":76,"file_size":7962}}}]'
{
...
"sync_status": {"e1005f08-acd6-4172-bab1-4338f8616e49": "ok"},
"temp_id_mapping": {"59fe4461-287b-4b00-bacc-ee771137a732": 17299568},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> note = api.project_notes.add(128501682, 'Note1')
>>> api.commit()
| Argument | Required | Description |
|---|---|---|
| project_id Integer or String (temp_id) | Yes | The project which the note is part of. |
| content String | Yes | The content of the note. |
| file_attachment Object | No | A file attached to the note (see more details about attachments above, and learn how to upload a file in the Uploads section). |
Update a note
An example of updating a note:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_update", "uuid": "8a38f9c5-2cd0-4da5-87c1-26d617b354e0", "args": {"id": 17299568, "content": "UpdatedNote1"}}]'
{
...
"sync_status": {"8a38f9c5-2cd0-4da5-87c1-26d617b354e0": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> note = api.project_notes.get_by_id(17299568)
>>> note.update(content='UpdatedNote1')
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the note. |
| content String | Yes | The content of the note. |
| file_attachment Object | No | A file attached to the note (see more details about attachments above, and learn how to upload a file in the Uploads section). |
Delete a note
An example of deleting a note:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "note_delete", "uuid": "8a38f9c5-2cd0-4da5-87c1-26d617b354e0", "args": {"id": 2311081457}}]'
{ ...
"sync_status": {"8d666fda-73c3-4677-8b04-5d223632c24f": "ok"},
... }
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> note = api.project_notes.get_by_id(17299568)
>>> note.delete()
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the note. |
Sections
An example section object
{
"id" : 39982,
"name" : "Section1",
"project_id" : 301946961,
"legacy_project_id": 33511505,
"section_order" : 1,
"collapsed" : false,
"user_id" : 1855589,
"sync_id" : null,
"is_deleted" : false,
"is_archived" : false,
"date_archived" : null,
"date_added" : "2019-10-07T07:09:27Z"
}
Properties
| Property | Description |
|---|---|
| id Integer | The id of the section. |
| name String | The name of the section. |
| project_id Integer | Project that the section resides in |
| legacy_project_id Integer | Legacy project id for the project that the section resides in (only shown for objects created before 1 April 2017) |
| section_order Integer | The order of section. Defines the position of the section among all the sections in the project |
| collapsed Boolean | Whether the section’s tasks are collapsed (a true or false value). |
| sync_id Integer | A special id for shared sections (a number or null if not set). Used internally and can be ignored. |
| is_deleted Boolean | Whether the section is marked as deleted (a true or false value). |
| is_archived Boolean | Whether the section is marked as archived (a true or false value). |
| date_archived String | The date when the section was archived (or null if not archived). |
| date_added String | The date when the section was created. |
Add a section
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_add",
"temp_id": "69ca86df-5ffe-4be4-9c3a-ad14fe98a58a",
"uuid": "97b68ab2-f524-48da-8288-476a42cccf28",
"args": {"name": "Section1", "project_id": 301946961}
}]'
{
...
"sync_status": {"97b68ab2-f524-48da-8288-476a42cccf28": "ok"},
"temp_id_mapping": {"69ca86df-5ffe-4be4-9c3a-ad14fe98a58a": 39982},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> section = api.sections.add('Section1', project_id=39982)
>>> api.commit()
Add a new section to a project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| name String | Yes | The name of the section. |
| project_id Integer | Yes | Project that the section resides in |
| section_order Integer | No | The order of section. Defines the position of the section among all the sections in the project |
Update a section
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_update",
"uuid": "afda2f29-319c-4d09-8162-f2975bed3124",
"args": {"id": 39982, "name": "UpdatedSection1"}
}]'
{
...
"sync_status": {"afda2f29-319c-4d09-8162-f2975bed3124": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> section = api.sections.get_by_id(39982)
>>> section.update(name='UpdatedSection1')
>>> api.commit()
Updates section attributes.
Command arguments
| Argument | Required | Description |
|---|---|---|
| name String | Yes | The name of the section. |
| collapsed Integer | No | Whether the section’s tasks are collapsed (where 1 is true and 0 is false). |
Move a section
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_move",
"uuid": "a8583f66-5885-4729-9e55-462e72d685ff",
"args": {"id": 39982, "project_id": 2217861081}
}]'
{
...
"sync_status": {"a8583f66-5885-4729-9e55-462e72d685ff": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> section = api.sections.get_by_id(33548400)
>>> section.move(project_id=2217861081)
>>> api.commit()
Move section to a different location.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | The id of the section. |
| project_id Integer or String (temp id) | No | Id of the destination project. |
Reorder sections
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_reorder",
"uuid": "109af205-6ff7-47fa-a5f8-1f13e59744ef",
"args": {
"sections": [
{"id": 40103, "section_order": 1},
{"id": 39982, "section_order": 2}
]
}
}]'
{
...
"sync_status": {"109af205-6ff7-47fa-a5f8-1f13e59744ef": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> section1 = api.sections.get_by_id(40103)
>>> section1.reorder(section_order=1)
>>> section2 = api.sections.get_by_id(39982)
>>> section2.reorder(section_order=2)
>>> api.commit()
The command updates section_order properties of sections in bulk.
Command arguments
| Argument | Required | Description |
|---|---|---|
| sections Array of Objects | Yes | An array of objects to update. Each object contains two attributes: id of the section to update and section_order, the new order. |
Delete a section
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_delete",
"uuid": "cebb5267-3e3c-40da-af44-500649281936",
"args": {"id": 39982}
}]'
{
...
"sync_status": {"cebb5267-3e3c-40da-af44-500649281936": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> section = api.sections.get_by_id(39982)
>>> section.delete()
>>> api.commit()
Delete a section and all its descendants items.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer (id) or String (temp id) | Yes | Id of the section to delete. |
Archive a section
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_archive",
"uuid": "2451f267-46ab-4f0e-8db7-82a9cd576f72",
"args": {"id": 39982}
}]'
{
...
"sync_status": {"2451f267-46ab-4f0e-8db7-82a9cd576f72": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.sections.get_by_id(39982)
>>> section.archive()
>>> api.commit()
Archive a section and all its descendants tasks.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | Section id to archive. |
Unarchive a section
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{
"type": "section_unarchive",
"uuid": "cd3a4b4b-182e-4733-b6b5-20a621ba98b8",
"args": {"id": 39982}
}]'
{
...
"sync_status": {"cd3a4b4b-182e-4733-b6b5-20a621ba98b8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.sections.get_by_id(39982)
>>> section.unarchive()
>>> api.commit()
This command is used to unarchive a section.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp id) | Yes | Section id to unarchive |
Uploads
Files can be uploaded to our servers and used as file attachments in Notes.
Upload a file
On success, an HTTP 200 OK with JSON data of file data is returned:
$ curl https://api.todoist.com/sync/v8/uploads/add \
-F token=0123456789abcdef0123456789abcdef01234567 \
-F file_name=example.jpg \
-F file=@/path/to/example.jpg
{
"file_name": "example.jpg",
"file_size": 85665,
"file_type": "image/jpeg",
"file_url": "https://*.cloudfront.net/*/example.jpg",
"tn_l": [
"https://*.cloudfront.net/tn_l_*.jpg",
400, 309
],
"tn_m": [
"https://*.cloudfront.net/tn_m_*.jpg",
288, 222
],
"tn_s": [
"https://*.cloudfront.net/tn_s_*.jpg",
96, 74
]
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.uploads.add('example.jpg')
{
'file_name': 'example.jpg',
'file_size': 85665,
'file_type': 'image/jpeg',
'file_url': 'https://*.cloudfront.net/*/example.jpg',
'tn_l': [
'https://*.cloudfront.net/tn_l_*.jpg',
400, 309
],
'tn_m': [
'https://*.cloudfront.net/tn_m_*.jpg',
288, 222
],
'tn_s': [
'https://*.cloudfront.net/tn_s_*.jpg',
96, 74
]
}
Upload a file suitable to be passed as a file_attachment attribute to the
note_add or note_update calls.
Parameters
| Parameter | Required | Description |
|---|---|---|
| file_name String | Yes | The file name to be uploaded. |
Base file properties
| Attribute | Description |
|---|---|
| file_name String | The name of the file. |
| file_size Integer | The size of the file in bytes. |
| file_type String | MIME type (i.e. text/plain, image/png). |
| file_url String | The URL where the file is located (a string value representing an HTTP URL). Note that we don’t cache the remote content on our servers and stream or expose files directly from third party resources. In particular this means that you should avoid providing links to non-encrypted (plain HTTP) resources, as exposing this files in Todoist may issue a browser warning. |
| upload_state String | Upload completion state (either pending or completed). |
Image file properties
If you upload an image, you may provide thumbnail paths to ensure Todoist
handles them appropriately. Valid thumbnail information is a JSON array with
URL, width in pixels, height in pixels. Ex.:
["http://example.com/img.jpg",400,300]. “Canonical” thumbnails (ones we create
by uploads/add API call) have following sizes: 96x96, 288x288, 528x528.
| Attribute | Description |
|---|---|
| tn_l List | Large thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
| tn_m List | Medium thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
| tn_s List | Small thumbnail (a list that contains the URL, the width and the height of the thumbnail). |
Audio file properties
If you upload an audio file, you may provide an extra attribute file_duration
(duration of the audio file in seconds, which takes an integer value). In the
web interface the file is rendered back with a <audio> tag, so you should make
sure it’s supported in current web
browsers. See
supported media formats for
the reference.
Get uploads
An example of getting the user’s uploads
$ curl https://api.todoist.com/sync/v8/uploads/get \
-d token=0123456789abcdef0123456789abcdef01234567
[
{
"file_size": 86406,
"file_type": "image/jpeg",
"file_url": "https://*.cloudfront.net/*/example.jpg",
"filename": "example.jpg",
"id": 34xx,
"ip": "8.8.8.x",
"item_id": 26166xxxxxx,
"note_id": 6157xxxxxx,
"project_id": 156996xxxxxx,
"uploaded": "2015-12-16T13:18:17Z",
"user_id": 5713xxxxxx
},
{
"file_size": 312,
"file_type": "text/plain",
"file_url": "https://*.cloudfront.net/*/todo.txt",
"filename": "todo.txt",
"id": 34xx,
"ip": "2.86.104.243",
"item_id": 26166xxxxxx,
"note_id": 6157xxxxxx,
"project_id": 156996xxxxxx,
"uploaded": "2015-12-16T12:08:14Z",
"user_id": 5713xxxxxx
}
]
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.uploads.get()
[
{
"file_size": 86406,
"file_type": "image/jpeg",
"file_url": "https://*.cloudfront.net/*/example.jpg",
"filename": "example.jpg",
"id": 34xx,
"ip": "8.8.8.x",
"item_id": 26166xxxxxx,
"note_id": 6157xxxxxx,
"project_id": 156996xxxxxx,
"uploaded": "2015-12-16T13:18:17Z",
"user_id": 5713xxxxxx
},
{
"file_size": 312,
"file_type": "text/plain",
"file_url": "https://*.cloudfront.net/*/todo.txt",
"filename": "todo.txt",
"id": 34xx,
"ip": "2.86.104.243",
"item_id": 26166xxxxxx,
"note_id": 6157xxxxxx,
"project_id": 156996xxxxxx,
"uploaded": "2015-12-16T12:08:14Z",
"user_id": 5713xxxxxx
}
]
Get all user’s uploads.
Parameters
| Parameter | Required | Description |
|---|---|---|
| limit Integer | No | The number of items to return (a number, where the default is 30, and the maximum is 50). |
| last_id Integer | No | Can be used for pagination. This should be the minimum upload id you’ve fetched so far. All results will be listed before that id. |
Delete upload
An example of deleting an upload
$ curl https://api.todoist.com/sync/v8/uploads/delete \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d file_url='https://*.cloudfront.net/*/example.jpg'
"ok"
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.uploads.delete('https://*.cloudfront.net/*/example.jpg')
ok
Delete an uploaded file.
Parameters
| Parameter | Required | Description |
|---|---|---|
| file_url String | Yes | The file URL to delete. |
Filters
Filters are only available for Todoist Premium users.
An example filter object
{
"id": 4638878,
"name": "Priority 1",
"query": "priority 1",
"color": 30,
"item_order": 3,
"is_deleted": 0,
"is_favorite": 0
}
Properties
| Property | Description |
|---|---|
| id Integer | The id of the filter. |
| name String | The name of the filter. |
| query String | The query to search for. Examples of searches can be found in the Todoist help page. |
| color Integer | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| item_order Integer | Filter’s order in the filter list (where the smallest value should place the filter at the top). |
| is_deleted Integer | Whether the filter is marked as deleted (where 1 is true and 0 is false). |
| is_favorite Integer | Whether the filter is favorite (where 1 is true and 0 is false). |
Add a filter
An example of adding a filter:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "filter_add", "temp_id": "9204ca9f-e91c-436b-b408-ea02b3972686", "uuid": "0b8690b8-59e6-4d5b-9c08-6b4f1e8e0eb8", "args": {"name": "Filter1", "query": "no due date"}}]'
{
...
"sync_status": {"0b8690b8-59e6-4d5b-9c08-6b4f1e8e0eb8": "ok"},
"temp_id_mapping": {"9204ca9f-e91c-436b-b408-ea02b3972686": 9},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> filter = api.filters.add('Filter1', 'no due date')
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| name String | Yes | The name of the filter. |
| query String | Yes | The query to search for. Examples of searches can be found in the Todoist help page. |
| color Integer | No | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| item_order Integer | No | Filter’s order in the filter list (the smallest value should place the filter at the top). |
| is_favorite Integer | No | Whether the filter is favorite (where 1 is true and 0 is false). |
Update a filter
An example of updating a filter:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "filter_update", "uuid": "a68b588a-44f7-434c-b3c5-a699949f755c", "args": {"id": 9, "query": "tomorrow"}}]'
{
...
"sync_status": {"a68b588a-44f7-434c-b3c5-a699949f755c": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> filter = api.filters.get_by_id(9)
>>> filter.update(query='tomorrow')
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the filter. |
| name String | No | The name of the filter |
| query String | No | The query to search for. Examples of searches can be found in the Todoist help page. |
| color Integer | No | Color id. It’s a value between 30 and 49, refer to Colors for more info. |
| item_order Integer | No | Filter’s order in the filter list (where the smallest value should place the filter at the top). |
| is_favorite Integer | No | Whether the filter is favorite (where 1 is true and 0 is false). |
Delete a filter
An example of deleting a filter:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "filter_delete", "uuid": "b8186025-66d5-4eae-b0dd-befa541abbed", "args": {"id": 9}}]'
{
...
"sync_status": {"b8186025-66d5-4eae-b0dd-befa541abbed": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> filter = api.filters.get_by_id(9)
>>> filter.delete()
>>> api.commit()
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the filter. |
Update multiple orders
An example of updating the orders of multiple filters at once:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands=[{"type": "filter_update_orders", "uuid": "517560cc-f165-4ff6-947b-3adda8aef744", "args": {"id_order_mapping": {"9": 1, "10": 2}}}]'
{
...
"sync_status": {"517560cc-f165-4ff6-947b-3adda8aef744": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.filters.update_orders({9: 1, 10: 2})
>>> api.commit()
Update the orders of multiple filters at once.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id_order_mapping Object | Yes | A dictionary, where a filter id is the key, and the order its value: filter_id: order. |
Reminders
An example reminder object
{
"id": 12763422,
"notify_uid": 1855589,
"item_id": 33511505,
"service": "email",
"type": "absolute",
"due": {
"date": "2016-08-05T07:00:00Z",
"timezone": null,
"is_recurring": false,
"string": "tomorrow at 10:00",
"lang": "en"
},
"mm_offset": 180,
"is_deleted": 0
}
Reminders are only available for Todoist Premium users.
Properties
| Property | Description |
|---|---|
| id Integer | The id of the reminder. |
| notify_uid Integer | The user id which should be notified of the reminder, typically the current user id creating the reminder. |
| item_id Integer | The item id for which the reminder is about. |
| service String | The way to get notified of the reminder: email for e-mail, mobile for mobile text message, or push for mobile push notification. |
| type String | The type of the reminder: relative for a time-based reminder specified in minutes from now, absolute for a time-based reminder with a specific time and date in the future, and location for a location-based reminder. |
| due Object | The due date of the reminder. See the Due dates section for more details. Note that reminders only support due dates with time, since full-day reminders don’t make sense. |
| mm_offset Integer | The relative time in minutes before the due date of the item, in which the reminder should be triggered. Note that the item should have a due date set in order to add a relative reminder. |
| name String | An alias name for the location. |
| loc_lat String | The location latitude. |
| loc_long String | The location longitude. |
| loc_trigger String | What should trigger the reminder: on_enter for entering the location, or on_leave for leaving the location. |
| radius Integer | The radius around the location that is still considered as part of the location (in meters). |
| is_deleted Integer | Whether the reminder is marked as deleted (where 1 is true and 0 is false). |
Add a reminder
An example of adding a relative reminder:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "reminder_add", "temp_id": "e24ad822-a0df-4b7d-840f-83a5424a484a", "uuid": "41e59a76-3430-4e44-92b9-09d114be0d49", "args": {"item_id": 33511505, "service": "email", "minute_offset": 30}}]'
{
...
"sync_status": {"41e59a76-3430-4e44-92b9-09d114be0d49": "ok"},
"temp_id_mapping": {"e24ad822-a0df-4b7d-840f-83a5424a484a": 12763422},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.reminders.add(33511505, service='email', minute_offset=30)
>>> api.commit()
An example of adding an absolute reminder:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "reminder_add", "temp_id": "952a365e-4965-4113-b4f4-80cdfcada172u", "uuid": "e7c8be2d-f484-4852-9422-a9984c58b1cd", "args": {"item_id": 33511505, "service": "email", "due": {"date": "2014-10-15T11:00:00Z"}}}]'
{
...
"sync_status": {"e7c8be2d-f484-4852-9422-a9984c58b1cd": "ok"},
"temp_id_mapping": {"952a365e-4965-4113-b4f4-80cdfcada172": 12763422},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.reminders.add(33511505, service='email', due={'date': '2014-10-15T11:00:00Z'})
>>> api.commit()
An example of adding a location reminder:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "reminder_add", "temp_id": "7ad9609d-579f-4828-95c5-3600acdb2c81", "uuid": "830cf409-daba-479c-a624-68eb0c07d01c", "args": {"item_id": 33511505, "service": "email", "type": "location", "name": "Aliados", "loc_lat": "41.148581", "loc_long":"-8.610945000000015", "loc_trigger":"on_enter", "radius": 100}}]'
{
...
"sync_status": {"830cf409-daba-479c-a624-68eb0c07d01c": "ok"},
"temp_id_mapping": {"7ad9609d-579f-4828-95c5-3600acdb2c81": 12763422},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.reminders.add(33511505, service='email', type='location', name='Aliados', loc_lat='41.148581', loc_long='-8.610945000000015', loc_trigger='on_enter', radius=100)
>>> api.commit()
Add a new reminder to the user account related to the API credentials.
Command arguments
| Argument | Required | Description |
|---|---|---|
| item_id Integer or String (temp_id) | Yes | The item id for which the reminder is about. |
| type String | Yes | The type of the reminder: relative for a time-based reminder specified in minutes from now, absolute for a time-based reminder with a specific time and date in the future, and location for a location-based reminder. |
| notify_uid Integer | No | The user id which should be notified of the reminder, typically the current user id creating the reminder. |
| service String | No | The way to get notified of the reminder: email for e-mail, mobile for mobile text message, or push for mobile push notification. |
| due Object | The due date of the reminder. See the Due dates section for more details. Note that reminders only support due dates with time, since full-day reminders don’t make sense. | |
| minute_offset Integer | No | The relative time in minutes before the due date of the item, in which the reminder should be triggered. Note, that the item should have a due date set in order to add a relative reminder. |
| name String | No | An alias name for the location. |
| loc_lat String | No | The location latitude. |
| loc_long String | No | The location longitude. |
| loc_trigger String | No | What should trigger the reminder: on_enter for entering the location, or on_leave for leaving the location. |
| radius Integer | No | The radius around the location that is still considered as part of the location (in meters). |
Update a reminder
An example of updating a reminder:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "reminder_update", "uuid": "b0e7562e-ea9f-4c84-87ee-9cbf9c103234", "args": {"id": 12763422, "due": {"date": "2014-10-10T15:00"}}}]'
{
...
"sync_status": {"b0e7562e-ea9f-4c84-87ee-9cbf9c103234": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.reminders.get_by_id(12763422)
>>> reminder.update(due={'date': '2014-10-10T15:00'})
>>> api.commit()
Update a reminder from the user account related to the API credentials.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the reminder. |
| notify_uid Integer | No | The user id which should be notified of the reminder, typically the current user id creating the reminder. |
| service String | No | The way to get notified of the reminder: email for e-mail, mobile for mobile text message, or push for mobile push notification. |
| type String | No | The type of the reminder: relative for a time-based reminder specified in minutes from now, absolute for a time-based reminder with a specific time and date in the future, and location for a location-based reminder. |
| due Object | The due date of the reminder. See the Due dates section for more details. Note that reminders only support due dates with time, since full-day reminders don’t make sense. | |
| minute_offset Integer | No | The relative time in minutes before the due date of the item, in which the reminder should be triggered. Note, that the item should have a due date set in order to add a relative reminder. |
| name String | No | An alias name for the location. |
| loc_lat String | No | The location latitude. |
| loc_long String | No | The location longitude. |
| loc_trigger String | No | What should trigger the reminder: on_enter for entering the location, or on_leave for leaving the location. |
| radius Integer | No | The radius around the location that is still considered as part of the location (in meters). |
Delete a reminder
An example of deleting a reminder:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "reminder_delete", "uuid": "0896d03b-eb90-49f7-9020-5ed3fd09df2d", "args": {"id": 9}}]'
{
...
"sync_status": {"0896d03b-eb90-49f7-9020-5ed3fd09df2d": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.reminders.get_by_id(12763422)
>>> reminder.delete()
>>> api.commit()
Delete a reminder from the user account related to the API credentials.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer or String (temp_id) | Yes | The id of the filter. |
Clear the locations
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "clear_locations", "uuid": "d285ae02-80c6-477c-bfa9-45272d7bddfb", "args": {}}]'
{
...
"sync_status": {"d285ae02-80c6-477c-bfa9-45272d7bddfb": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.locations.clear()
>>> api.commit()
Clears the locations list, which is used for the location reminders.
Due dates
Due dates for tasks and reminders is one of the core concepts of Todoist. It’s very powerful and quite complex, because it has to embrace different use-cases of Todoist users.
Todoist supports three types of due dates.
- Full-day dates (like “1 January 2018” or “tomorrow”)
- Floating due dates with time (like “1 January 2018 at 12:00” or “tomorrow at 10am”)
- Due dates with time and fixed timezone (like “1 January 2018 at 12:00 America/Chicago” or “tomorrow at 10am Asia/Jakarta”)
Unless specified explicitly, dates with time are created as floating.
In addition, any of these due dates can be set to recurring or not, depending on the date string, provided by the client.
- More about the difference between floating due dates and dates with fixed timezones
- More about recurring due dates
Full-day dates
An example of a full-day date
{
"date": "2016-12-01",
"timezone": null,
"string": "every day",
"lang": "en",
"is_recurring": true
}
Properties
| Property | Description |
|---|---|
| date string | Due date in the format of YYYY-MM-DD (RFC 3339). For recurring dates, the date of the current iteration. |
| timezone string | Always set to null. |
| string string | Human-readable representation of due date. String always represents the due object in user’s timezone. Look at our reference to see which formats are supported. |
| lang string | Lang which has to be used to parse the content of the string attribute. Used by clients and on the server side to properly process due dates when date object is not set, and when dealing with recurring tasks. Valid languages are: en, da, pl, zh, ko, de, pt, ja, it, fr, sv, ru, es, nl. |
| is_recurring boolean | Boolean flag which is set to true is due object represents a recurring due date |
Floating due dates with time
An example of a floating due date with time
{
"date": "2016-12-0T12:00:00",
"timezone": null,
"string": "every day at 12",
"lang": "en",
"is_recurring": true
}
| Property | Description |
|---|---|
| date string | Due date in the format of YYYY-MM-DDTHH:MM:SS. For recurring dates, the date of the current iteration. Due date always represent an event in current user’s timezone. Note that it’s not quite compatible with RFC 3339, because the concept of timezone is not applicable to this object. Also note that unlike fixed due dates, the date representation doesn’t end with “Z” |
| timezone string | Always set to null. |
| string string | Human-readable representation of due date. String always represents the due object in user’s timezone. Look at our reference to see which formats are supported. |
| lang string | Lang which has to be used to parse the content of the string attribute. Used by clients and on the server side to properly process due dates when date object is not set, and when dealing with recurring tasks. Valid languages are: en, da, pl, zh, ko, de, pt, ja, it, fr, sv, ru, es, nl. |
| is_recurring boolean | Boolean flag which is set to true is due object represents a recurring due date |
Due dates with time and fixed timezone
An example of a due date with time and fixed timezone
{
"date": "2016-12-06T13:00:00Z",
"timezone": "Europe/Madrid",
"string": "ev day at 2pm",
"lang": "en",
"is_recurring": true
}
Properties
| Property | Description |
|---|---|
| date string | Due date in the format of YYYY-MM-DDTHH:MM:SSZ (RFC 3339). For recurring dates, the date of the current iteration. Due date is stored in UTC. |
| timezone string | Timezone of the due instance. Used to recalculate properly the next iteration for a recurring due date. |
| string string | Human-readable representation of due date. String always represents the due object in user’s timezone. Look at our reference to see which formats are supported. |
| lang string | Lang which has to be used to parse the content of the string attribute. Used by clients and on the server side to properly process due dates when date object is not set, and when dealing with recurring tasks. Valid languages are: en, da, pl, zh, ko, de, pt, ja, it, fr, sv, ru, es, nl. |
| is_recurring boolean | Boolean flag which is set to true is due object represents a recurring due date |
Create or update due dates
Usually you create due dates when you create a new task or a reminder, or
you want to update a due date for an object. In both cases due date is provided
as a due attribute of an object. You may provide all fields of an object in
the constructor, but it’s more convenient to provide only a subset of the
fields and let the server to fill the gaps.
Create or update due date from user-provided string
Input example
"due": {"string": "tomorrow"}
Output example. Full-date instance is created.
"due": {
"date": "2018-11-15",
"timezone": null,
"is_recurring": false,
"string": "tomorrow",
"lang": "en"
}
Input example
"due": {"string": "tomorrow at 12"}
Output example. Floating due date created
"due": {
"date": "2018-11-15T12:00:00",
"timezone": null,
"is_recurring": false,
"string": "tomorrow at 12",
"lang": "en"
}
Input example. Timezone is set explicitly
"due": {"string": "tomorrow at 12", "timezone": "Asia/Jakarta"}
Output example. Due date with fixed timezone created
"due": {
"date": "2018-11-16T05:00:00Z",
"timezone": "Asia/Jakarta",
"is_recurring": false,
"string": "tomorrow at 12",
"lang": "en"
}
You can ask user to provide a due string and to create a new object from that.
You need to provide a timezone if you want to create a fixed due date instead
of the floating one. If you want to create a task without a due date, you
can set due attribute to null.
See the code section to the right for more examples. In all cases you can set
the lang attribute of the date to set the language of the input. If language
is not set, the language from user settings will be used.
Create or update due date from a date object
Input example for a full-day event
"due": {"date": "2018-10-14"}
For a full date event the format of the date attribute is YYYY-MM-DD.
Output example
"due": {
"date": "2018-10-14",
"timezone": null,
"is_recurring": false,
"string": "2018-10-14",
"lang": "en"
}
Input example for a floating due date
"due": {"date": "2018-10-14T10:00:00"}
Output example
"due": {
"date": "2018-10-14T10:00:00",
"timezone": null,
"is_recurring": false,
"string": "2018-10-14 10:00",
"lang": "en"
}
In some cases you have a date object and want to create a due date from it. Usually all you need to do is to chose the format of the due date (floating or fixed) and format the time object properly with strftime or alternative for your programming language. The formatted string goes to a “date” attribute of the constructor.
Note that this approach does not allow you to create recurring due dates.
For a floating due date event the format of the date attribute is
YYYY-MM-DDTHH:MM:SS and the date has to be provided in user’s local
timezone.
Input example for a due date with a fixed timezone
"due": {"date": "2018-10-14T05:00:00Z"}
Output example
"due": {
"date": "2018-10-14T05:00:00Z",
"timezone": "Asia/Jakarta",
"is_recurring": false,
"string": "2018-10-14 12:00",
"lang": "en"
}
For a floating due date event the format of the date attribute is
YYYY-MM-DDTHH:MM:SSZ (mind the “Z” ending) and the date has to be provided
in UTC. Optionally you can provide a timezone name to overwrite the default
timezone of the user.
Miscellaneous
Colors
Some objects (like projects, labels, and filters) may have colors defined by an id. The table below shows the ids for any of these colors.
| Id | Hexadecimal | Id | Hexadecimal | |
|---|---|---|---|---|
| 30 | #b8256f |
40 | #96c3eb |
|
| 31 | #db4035 |
41 | #4073ff |
|
| 32 | #ff9933 |
42 | #884dff |
|
| 33 | #fad000 |
43 | #af38eb |
|
| 34 | #afb83b |
44 | #eb96eb |
|
| 35 | #7ecc49 |
45 | #e05194 |
|
| 36 | #299438 |
46 | #ff8d85 |
|
| 37 | #6accbc |
47 | #808080 |
|
| 38 | #158fad |
48 | #b8b8b8 |
|
| 39 | #14aaf5 |
49 | #ccac93 |
Get productivity stats
An example of getting the user’s productivity stats:
$ curl https://api.todoist.com/sync/v8/completed/get_stats \
-d token=0123456789abcdef0123456789abcdef01234567
{
"karma_last_update": 50,
"karma_trend": "up",
"days_items": [
{ "date": "2014-11-03",
"items": [
{
"completed": 7,
"id": 148483789
},
{
"completed": 5,
"id": 148483788
}
],
"total_completed": 0 },
],
"completed_count": 0,
"karma_update_reasons": [
{ "positive_karma_reasons": [4],
"new_karma": 50,
"negative_karma": 0,
"positive_karma": 50,
"negative_karma_reasons": [],
"time": "Mon 20 Oct 2014 12:06:52"}
],
"karma": 50,
"week_items": [
{ "date": "2014-11-03\/2014-11-09",
"items": [
{
"completed": 7,
"id": 148483789
},
{
"completed": 5,
"id": 148483788
}
],
"total_completed": 0 },
],
"project_colors": {
"2153004888": 7,
"2159009077": 4,
"2155005784": 4,
"2155006874": 9,
"2168008691": 3,
},
"goals": {
"karma_disabled": 0,
"user_id": 4,
"max_weekly_streak": {
"count": 0,
"start": "",
"end": ""
},
"ignore_days": [6, 7],
"vacation_mode": 0,
"current_weekly_streak": {
"count": 0,
"start": "",
"end": ""
},
"current_daily_streak": {
"count": 0,
"start": "",
"end": ""
},
"weekly_goal": 25,
"max_daily_streak": {
"count": 0,
"start": "",
"end": ""
},
"daily_goal": 5
}
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.completed.get_stats()
{
'karma_last_update': 50.0,
'karma_trend': 'up',
'days_items': [
{ 'date': '2014-11-03',
"items": [
{
"completed": 7,
"id": 148483789
},
{
"completed": 5,
"id": 148483788
}
],
'total_completed': 0}
],
'completed_count': 0,
'karma_update_reasons': [
{ 'positive_karma_reasons': [4],
'new_karma': 50.0,
'negative_karma': 0.0,
'positive_karma': 50.0,
'negative_karma_reasons': [],
'time': 'Mon 20 Oct 2014 12:06:52' }
],
'karma': 50.0,
'week_items': [
{ 'date': '2014-11-03/2014-11-09',
"items": [
{
"completed": 7,
"id": 148483789
},
{
"completed": 5,
"id": 148483788
}
],
'total_completed': 0 },
],
'project_colors': {
"2153004888": 7,
"2159009077": 4,
"2155005784": 4,
"2155006874": 9,
"2168008691": 3,
},
'goals': {
'karma_disabled': 0,
'user_id': 4,
'max_weekly_streak': {
'count': 0,
'start': '',
'end': ''
},
'ignore_days': [6, 7],
'vacation_mode': 0,
'current_weekly_streak': {
'count': 0,
'start': '',
'end': ''
},
'current_daily_streak': {
'count': 0,
'start': '',
'end': ''
},
'weekly_goal': 25,
'max_daily_streak': {
'count': 0,
'start': '',
'end': ''
},
'daily_goal': 5
}
}
Get the user’s productivity stats.
Properties
| Property | Description |
|---|---|
| karma_last_update Float | The karma delta on the last update |
| karma_trend String | Karma trend. Possible values: up or down |
| days_items Object | Items completed in the last 7 days. The objects inside items are composed by an id (project_id) and the number of completed tasks for it. |
| completed_count Integer | Total completed tasks count |
| karma_update_reasons | Log of the last karma updates. positive_karma_reasons and negative_karma_reasons are Integer numbers regarding the action done to generate them. Please refer to the Positive and negative karma reasons below. |
| karma Float | Karma score |
| week_items Object | Items completed in the last 4 weeks. The objects inside items are composed by an id (project_id) and the number of completed tasks for it. |
| project_colors Object | Projects color mapping |
| goals Object | Goals definition. The same settings and stats shown in the interface. |
Positive and negative karma reasons
| Number | Description |
|---|---|
| 1 | You added tasks |
| 2 | You completed tasks |
| 3 | Usage of advanced features |
| 4 | You are using Todoist. Thanks! |
| 5 | Signed up for Todoist Beta! |
| 6 | Used Todoist Support section! |
| 7 | For using Todoist Premium - thanks for supporting us! |
| 8 | Getting Started Guide task completed! |
| 9 | Daily Goal reached! |
| 10 | Weekly Goal reached! |
| 50 | You have tasks that are over %s days overdue’ |
| 52 | Inactive for a longer period of time’ |
Get all completed items
An example of getting the user’s completed tasks
$ curl https://api.todoist.com/sync/v8/completed/get_all \
-d token=0123456789abcdef0123456789abcdef01234567
{
"items": [
{ "content": "Item11",
"meta_data": null,
"user_id": 1855589,
"task_id": 33511505,
"note_count": 0,
"project_id": 128501470,
"completed_date": "2015-02-17T15:40:41Z",
"id": 1899066186
}
],
"projects": {
"128501470":
{ "color": 7,
"collapsed": 0,
"parent_id": null,
"is_deleted": 0,
"id": 128501470,
"user_id": 1855589,
"name": "Project1",
"child_order": 36,
"is_archived": 0 }
}
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.completed.get_all()
{
'items': [
{ 'user_id': 1855589,
'task_id': 33511505,
'note_count': 0,
'completed_date': '2015-02-17T15:40:41Z',
'content': 'Item1',
'meta_data': None,
'project_id': 128501470,
'id': 1899066186},
],
'projects': {
'128501470':
{ 'name': 'Inbox',
'user_id': 1855589,
'color': 7,
'is_deleted': 0,
'collapsed': 0,
'inbox_project': True,
'child_order': 36,
'is_archived': 0,
'parent_id': None,
'id': 128501470 }
}
}
Only available for Todoist Premium users.
Get all the user’s completed items (tasks).
Parameters
| Parameter | Required | Description |
|---|---|---|
| project_id Integer | No | Filter the tasks by project id. |
| limit Integer | No | The number of items to return (where the default is 30, and the maximum is 200). |
| offset Integer | No | Can be used for pagination, when more than the limit number of tasks are returned. |
| until String | No | Return items with a completed date same or older than until (a string value formatted as 2007-4-29T10:13). |
| since String | No | Return items with a completed date newer than since (a string value formatted as 2007-4-29T10:13). |
| annotate_notes Boolean | No | Return notes together with the completed items (a true or false value). |
Return values
| Property | Description |
|---|---|
| id Integer | The id of the completed task entry. |
| task_id Integer | The id of the task. |
| user_id Integer | The owner of the task. |
| project_id Integer | Project that the task resides in. |
| content String | The text of the task. |
| completed_date String | The date when the task was completed. |
| note_count Integer | The number of notes of the task. |
| meta_data String | Optional extra details. |
Get archived projects
An example of getting the user’s archived projects
$ curl https://api.todoist.com/sync/v8/projects/get_archived \
-d token=0123456789abcdef0123456789abcdef01234567
[
{
"id" : 150977840,
"name" : "Project1",
"child_order" : 1,
"parent_id" : null,
"color" : 7,
"collapsed" : 0
"is_archived" : 1,
"is_deleted" : 0,
}
]
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.projects.get_archived()
[
{
'id' : 150977840,
'name' : 'Project1',
'child_order' : 1,
'parent_id' : None,
'color' : 7,
'collapsed' : 0
'is_archived' : 1,
'is_deleted' : 0,
}
]
Get the user’s archived projects.
Add item
An example of adding a task:
$ curl https://api.todoist.com/sync/v8/items/add \
-d token=0123456789abcdef0123456789abcdef01234567
-d content=Task1
{
"assigned_by_uid": 1855589,
"labels": [],
"sync_id": null,
"in_history": 0,
"date_added": "2015-02-18T11:09:11Z",
"parent_id" : null,
"children": null,
"content": "Task1",
"is_deleted": 0,
"user_id": 1855589,
"due": null,
"id": 33548400,
"priority": 4,
"child_order": 1,
"responsible_uid": null,
"project_id": 128501411,
"collapsed": 0,
"checked": 0,
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.add_item("Task1")
{
'labels': [],
'sync_id': None,
'in_history': 0,
'checked': 0,
'id': 33548400,
'priority': 4,
'user_id': 1855589,
'date_added': '2015-02-18T11:09:11Z',
'children': None,
'content': 'Task1',
'child_order': 1,
'project_id': 128501411,
'added_by_uid': 1855589,
'assigned_by_uid': 1855589,
'collapsed': 0,
'parent_id': None,
'is_deleted': 0,
'due': None,
'responsible_uid': None
}
Add a new task to a project. Note, that this is provided as a helper
method, a shortcut, to quickly add a task without going through the
Sync workflow described in a previous section.
Parameters
| Parameter | Required | Description |
|---|---|---|
| content String | Yes | The text of the task. |
| project_id Integer | No | The id of the project to add the task to, while the default is the user’s Inbox project. |
| date_string String | No | The date of the task, added in free form text, for example it can be every day @ 10 (or null or an empty string to unset). Look at our reference to see which formats are supported. |
| priority Integer | No | The priority of the task (a number between 1 and 4, 4 for very urgent and 1 for natural). Note: Keep in mind that very urgent is the priority 1 on clients. So, p1 will return 4 in the API. |
| parent_id Integer | The id of the parent task. Set to null for root tasks |
|
| child_order Integer | The order of task. Defines the position of the task among all the tasks with the same parent_id |
|
| labels Array of Integer | No | The task’s labels (a list of label ids such as [2324,2525]). |
| assigned_by_uid Integer | No | The id of the user who assigns the current task. This makes sense for shared projects only. Accepts 0 or any user id from the list of project collaborators. If this value is unset or invalid, it will automatically be set up to your uid. |
| responsible_uid Integer | No | The id of user who is responsible for accomplishing the current task. This makes sense for shared projects only. Accepts 0 or any user id from the list of project collaborators. If this value is unset or invalid, it will automatically be set to null. |
| note String | No | Add a note directly to the task (a string value that will become the content of the note). |
| auto_reminder Boolean | No | When this option is enabled, the default reminder will be added to the new item if it has a due date with time set. See also the auto_reminder user option for more info about the default reminder. |
Get item info
An example of getting an item’s info:
$ curl https://api.todoist.com/sync/v8/items/get \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d item_id=466
{
"project": {
"name": "Inbox",
"color": 7,
"is_deleted": 0,
"collapsed": 0,
"inbox_project": true,
"child_order": 0,
"parent_id" : null,
"id": 1,
"shared": false,
"is_archived": 0
},
"item": {
"assigned_by_uid": 1,
"due": null,
"labels": [],
"sync_id": null,
"in_history": 0,
"date_added": "2016-03-22T16:00:00Z",
"checked": 0,
"id": 466,
"content": "foo",
"parent_id" : null,
"user_id": 1,
"is_deleted": 0,
"priority": 1,
"child_order": 1,
"responsible_uid": null,
"project_id": 1,
"collapsed": 0,
},
"notes": [
{
"is_deleted": 0,
"file_attachment": null,
"content": "1",
"posted_uid": 1,
"uids_to_notify": null,
"item_id": 466,
"project_id": 1,
"id": 36,
"posted": "2016-05-18T16:45:00Z"
},
{
"is_deleted": 0,
"file_attachment": null,
"content": "2",
"posted_uid": 1,
"uids_to_notify": null,
"item_id": 466,
"project_id": 1,
"id": 37,
"posted": "2016-05-18T16:45:00Z"
},
{
"is_deleted": 0,
"file_attachment": null,
"content": "3",
"posted_uid": 1,
"uids_to_notify": null,
"item_id": 466,
"project_id": 1,
"id": 38,
"posted": "2016-05-18T16:45:00Z"
}
]
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.items.get(466)
{
'project': {
'name': 'Inbox',
'color': 7,
'is_deleted': 0,
'collapsed': 0,
'inbox_project': True,
'child_order': 0,
'parent_id': None,
'id': 1,
'shared': False,
'is_archived': 0
},
'item': {
'assigned_by_uid': 1,
'due': None,
'labels': [],
'sync_id': None,
'in_history': 0,
'date_added': '2016-03-22T16:00:00Z',
'checked': 0,
'id': 466,
'content': 'foo',
'parent_id': None,
'user_id': 1,
'is_deleted': 0,
'priority': 1,
'child_order': 1,
'responsible_uid': None,
'project_id': 1,
'collapsed': 0,
},
'notes': [
{
'is_deleted': 0,
'file_attachment': None,
'content': '1',
'posted_uid': 1,
'uids_to_notify': None,
'item_id': 466,
'project_id': 1,
'id': 36,
'posted': '2016-05-18T16:45:00Z'
},
{
'is_deleted': 0,
'file_attachment': None,
'content': '2',
'posted_uid': 1,
'uids_to_notify': None,
'item_id': 466,
'project_id': 1,
'id': 37,
'posted': '2016-05-18T16:45:00Z'
},
{
'is_deleted': 0,
'file_attachment': None,
'content': '3',
'posted_uid': 1,
'uids_to_notify': None,
'item_id': 466,
'project_id': 1,
'id': 38,
'posted': '2016-05-18T16:45:00Z'
}
]
}
This function is used to extract detailed information about the item, including all the notes.
It’s especially important, because on initial load we return back no more than
10 last notes, and if client wants to get more, they can be downloaded with
get_item endpoint.
It returns a JSON object with the item, and optionally the project
and notes attributes.
Parameters
| Parameter | Required | Description |
|---|---|---|
| item_id Integer | Yes | The item’s unique id. |
| all_data Boolean | No | Whether to return the parent project and notes of the item (a true or false value, while the default is true). |
Get project info
An example of getting a project’s info:
$ curl https://api.todoist.com/sync/v8/projects/get \
-d token=0123456789abcdef0123456789abcdef01234567
-d project_id=128501682
{
"project" : {
"id": 128501682,
"name": "Project1",
"color": 1,
"parent_id" : null,
"child_order": 36,
"collapsed": 0,
"shared": false,
"is_deleted": 0,
"is_archived": 0,
},
"notes" : [
{
"is_deleted": 0,
"file_attachment": null,
"content": "Note1",
"posted_uid": 1,
"uids_to_notify": null,
"project_id": 128501682,
"id": 17299568,
"posted": "2016-05-18T16:45:00Z"
},
]
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.projects.get(128501682)
{
"project" : {
'id': 128501682,
'name': 'Project1',
'color': 1,
'parent_id': None,
'child_order': 36,
'collapsed': 0,
'shared': false,
'is_deleted': 0,
'is_archived': 0,
},
"notes" : [
{
'is_deleted': 0,
'file_attachment': null,
'content': 'Note1',
'posted_uid': 1,
'uids_to_notify': null,
'project_id': 128501682,
'id': 17299568,
'posted': '2016-05-18T16:45:00Z'
},
]
}
This function is used to extract detailed information about the project, including all the notes.
It’s especially important, because on initial load we return back no more than
10 last notes, and if client wants to get more, they can be downloaded with
get_project endpoint.
It returns a JSON object with the project, and optionally the notes attributes.
Parameters
| Parameter | Required | Description |
|---|---|---|
| project_id Integer | Yes | The projects’s unique id. |
| all_data Boolean | No | Whether to return the notes of the project (a true or false value, while the default is true). |
Get project data
An example of getting a project’s data:
$ curl https://api.todoist.com/sync/v8/projects/get_data \
-d token=0123456789abcdef0123456789abcdef01234567
-d project_id=128501682
{
"project" : {
"child_order" : 4,
"user_id" : 1855589,
"is_archived" : 0,
"is_deleted" : 0,
"id" : 175655925,
"archived_date" : null,
"collapsed" : 0,
"parent_id" : null,
"archived_timestamp" : 0,
"color" : 7,
"name" : "Project1"
},
"items" : [
{
"is_deleted" : 0,
"date_added" : "2016-07-19T12:50:49Z",
"child_order" : 1,
"responsible_uid" : null,
"content" : "Task1",
"id" : 101964377,
"user_id" : 1855589,
"assigned_by_uid" : 1855589,
"in_history" : 0,
"project_id" : 175655925,
"sync_id" : null,
"collapsed" : 0,
"due" : null,
"parent_id" : null,
"labels" : [],
"checked" : 0,
"priority" : 1
}
]
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.projects.get_data(128501682)
{
'project' : {
'child_order' : 4,
'user_id' : 1855589,
'is_archived' : 0,
'is_deleted' : 0,
'id' : 175655925,
'archived_date' : None,
'collapsed' : 0,
'parent_id': None,
'archived_timestamp' : 0,
'color' : 7,
'name' : 'Project1'
},
'items' : [
{
'is_deleted' : 0,
'date_added' : '2016-07-19T12:50:49Z',
'child_order' : 1,
'responsible_uid' : None,
'content' : 'Task1',
'id' : 101964377,
'user_id' : 1855589,
'assigned_by_uid' : 1855589,
'in_history' : 0,
'project_id' : 175655925,
'sync_id' : None,
'collapsed' : 0,
'due' : None,
'parent_id': None,
'labels' : [],
'checked' : 0,
'priority' : 1
}
]
}
Get a project’s uncompleted items.
Parameters
| Parameter | Required | Description |
|---|---|---|
| project_id Integer | Yes | The projects’s unique id. |
Quick add task
An example of quick add task:
$ curl https://api.todoist.com/sync/v8/quick/add \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d text='Task1 @Label1 #Project1 +ExampleUser'
{
"added_by_uid": 1855589,
"assigned_by_uid": 1855589,
"labels": [
874,
],
"sync_id": null,
"in_history": 0,
"date_added": "2015-02-18T11:09:11Z",
"parent_id": null,
"children": null,
"content": "Task1",
"is_deleted": 0,
"user_id": 1855589,
"due": null,
"id": 33548400,
"priority": 4,
"child_order": 1,
"responsible_uid": 1855589,
"project_id": 128501411,
"collapsed": 0,
"checked": 0,
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.quick.add('Task1 @Label1 #Project1 +ExampleUser')
{
'labels': [
874
],
'sync_id': None,
'in_history': 0,
'checked': 0,
'id': 33548400,
'priority': 4,
'user_id': 1855589,
'date_added': '2015-02-18T11:09:11Z',
'children': None,
'content': 'Task1',
'child_order': 1,
'project_id': 128501411,
'added_by_uid': 1855589,
'assigned_by_uid': 1855589,
'collapsed': 0,
'parent_id': None,
'is_deleted': 0,
'due': None,
'responsible_uid': 1855589,
}
Add a new task using the Quick Add Task implementation available in the official clients.
Parameters
| Parameter | Required | Description |
|---|---|---|
| text String | Yes | The text of the task that is parsed. It can include a due date in free form text, a project name starting with the # character (without spaces), a label starting with the @ character, and an assignee starting with the + character. |
| note String | No | The content of the note. |
| reminder String | No | The date of the reminder, added in free form text. |
| auto_reminder Boolean | No | When this option is enabled, the default reminder will be added to the new item if it has a due date with time set. See also the auto_reminder user option for more info about the default reminder. |
User
An example user object
{
"auto_reminder": 0,
"avatar_big" : "https://*.cloudfront.net/*_big.jpg",
"avatar_medium" : "https://*.cloudfront.net/*_medium.jpg",
"avatar_s640" : "https://*.cloudfront.net/*_s640.jpg",
"avatar_small" : "https://*.cloudfront.net/*_small.jpg",
"business_account_id": 1,
"daily_goal": 15,
"date_format": 0,
"dateist_inline_disabled" : false,
"dateist_lang" : null,
"days_off": [
6,
7
],
"default_reminder": "push",
"email": "me@xample.com",
"features": {
"beta": 1,
"dateist_inline_disabled" : false,
"dateist_lang" : null,
"gold_theme" : true,
"has_push_reminders": true,
"karma_disabled": false,
"karma_vacation": false,
"restriction": 3
},
"full_name": "Example User",
"id": 1855589,
"image_id": "d160009dfd52b991030d55227003450f",
"inbox_project": 128501411,
"is_biz_admin": false,
"is_premium": true,
"join_date": "2015-07-31T18:32:06Z",
"karma": 37504,
"karma_trend": "up",
"lang": "en",
"legacy_inbox_project": 128501411,
"legacy_team_inbox": 2154865775,
"mobile_host": null,
"mobile_number": null,
"next_week": 1,
"premium_until": null,
"share_limit": 51,
"sort_order": 0,
"start_day": 1,
"start_page": "filter:2186297606",
"team_inbox": 2154866775,
"theme": 11,
"time_format": 0,
"token": "8762696c43f6140e111f70e58137749c5f708c24",
"tz_info": {
"gmt_string": "-03:00",
"hours": -3,
"is_dst": 0,
"minutes": 0,
"timezone": "America/Sao_Paulo"
},
}
A user in Todoist is a JSON object. The dates will be in the UTC timezone. Typically a user object will have the following properties:
Properties
| Property | Description |
|---|---|
| auto_reminder Integer | The default time in minutes for the automatic reminders set, whenever a due date has been specified for a task. |
| avatar_big String | The link to a 195x195 pixels image of the user’s avatar. |
| avatar_medium String | The link to a 60x60 pixels image of the user’s avatar. |
| avatar_s640 String | The link to a 640x640 pixels image of the user’s avatar. |
| avatar_small String | The link to a 35x35 pixels image of the user’s avatar. |
| business_account_id Integer | The id of the user’s business account. |
| daily_goal Integer | The daily goal number of completed tasks for karma |
| date_format Integer | Whether to use the DD-MM-YYYY date format (if set to 0), or the MM-DD-YYYY format (if set to 1). |
| dateist_inline_disabled Boolean | Whether smart date recognition has been disabled (a true or false value). |
| dateist_lang String | The language expected for date recognition instead of the user’s lang (null if the user’s lang determines this), one of the following values: da, de, en, es, fi, fr, it, ja, ko, nl, pl, pt_BR, ru, sv, tr, zh_CN, zh_TW. |
| days_off Array | Array of integers representing user’s days off (between 1 and 7, where 1 is Monday and 7 is Sunday). |
| default_reminder String | The default reminder for the user. Reminders are only possible for Premium users. The default reminder can be one of the following: email to send reminders by email, mobile to send reminders to mobile devices via SMS, push to send reminders to smart devices using push notifications (one of the Android or iOS official clients must be installed on the client side to receive these notifications), no_default to turn off sending default reminders. |
| email String | The user’s email. |
| features Object | Used internally for any special features that apply to the user. Current special features include whether the user has enabled beta, whether dateist_inline_disabled that is inline date parsing support is disabled, whether the dateist_lang is set which overrides the date parsing language, whether the gold_theme has been awarded to the user, whether the user has_push_reminders enabled, whether the user has karma_disabled, whether the user has karma_vacation mode enabled, and whether any special restriction applies to the user. |
| full_name String | The user’s real name formatted as Firstname Lastname. |
| id Integer | The user’s id. |
| image_id String | The id of the user’s avatar. |
| inbox_project Integer | The id of the user’s Inbox project. |
| is_biz_admin Boolean | Whether the user is a business account administrator (a true or false value). |
| is_premium Boolean | Whether the user has a Premium subscription (a true or false value). |
| join_date String | The date when the user joined Todoist. |
| karma Integer | The user’s karma score. |
| karma_trend String | The user’s karma trend (for example up). |
| lang String | The user’s language, which can take one of the following values: da, de, en, es, fi, fr, it, ja, ko, nl, pl, pt_BR, ru, sv, tr, zh_CN, zh_TW. |
| legacy_inbox_project Integer | The legacy id of the user’s Inbox project. (only shown for objects created before 1 April 2017) |
| legacy_team_inbox Integer | The legacy id of the Team Inbox project. (only shown for objects created before 1 April 2017) |
| mobile_host String | The user’s mobile host (null if not set). |
| mobile_number String | The user’s mobile number (null if not set). |
| next_week Integer | The day of the next week, that tasks will be postponed to (between 1 and 7, where 1 is Monday and 7 is Sunday). |
| premium_until String | The date when the user’s Premium subscription ends (null if not a Premium user). This should be used for informational purposes only as this does not include the grace period upon expiration. As a result, avoid using this to determine whether someone has premium and use is_premium instead. |
| sort_order Integer | Whether to show projects in an oldest dates first order (if set to 0, or a oldest dates last order (if set to 1). |
| start_day Integer | The first day of the week (between 1 and 7, where 1 is Monday and 7 is Sunday). |
| start_page String | The user’s default view on Todoist. The start page can be one of the following: _info_page for the info page, _blank for a blank page, _project_<PROJECT_ID> for project with id <PROJECT_ID>, and <ANY_QUERY> to query after anything. |
| team_inbox Integer | The id of the Team Inbox project. |
| theme Integer | The currently selected Todoist theme (a number between 0 and 10). |
| time_format Integer | Whether to use a 24h format such as 13:00 (if set to 0) when displaying time, or a 12h format such as 1:00pm (if set to 1). |
| token String | The user’s token that should be used to call the other API methods. |
| tz_info Object | The user’s timezone (a dictionary structure), which includes the following elements: the timezone as a string value, the hours and minutes difference from GMT, whether daylight saving time applies denoted by is_dst, and a string value of the time difference from GMT that is gmt_string. |
| weekly_goal Integer | The target number of tasks to complete per week. |
Register a new user
An example of registering a new user:
$ curl https://api.todoist.com/sync/v8/user/register \
-d email=me@example.com \
-d full_name=Example\ User \
-d password=secret
{
"auto_reminder" : 30,
"avatar_big" : "https://*.cloudfront.net/*_big.jpg",
"avatar_medium" : "https://*.cloudfront.net/*_medium.jpg",
"avatar_s640" : "https://*.cloudfront.net/*_s640.jpg",
"avatar_small" : "https://*.cloudfront.net/*_small.jpg",
"business_account_id": null,
"date_format": 0,
"days_off": [6, 7],
"default_reminder": null,
"email": "me@xample.com",
"features" : {
"beta": 0,
"restriction" : 3,
"has_push_reminders": false
},
"full_name": "Example User",
"id": 1855589,
"image_id": null,
"inbox_project": 128501411,
"is_biz_admin": false,
"is_premium": false,
"join_date": "2014-04-30T13:24:38Z",
"karma": 684.0,
"karma_trend": "-",
"legacy_inbox_project": 128501411,
"legacy_team_inbox": 2154866775,
"mobile_host": null,
"mobile_number": null,
"next_week": 1,
"premium_until": null,
"sort_order": 0,
"start_day": 1,
"start_page": "overdue, 7 days",
"team_inbox": 2154866775,
"theme" : 0,
"time_format": 0,
"token": "0123456789abcdef0123456789abcdef01234567",
"tz_info": {
"timezone": "GMT +1:00",
"gmt_string": "+01:00",
"hours": 1,
"minutes": 0,
"is_dst": 0
}
}
>>> import todoist
>>> api = todoist.TodoistAPI()
>>> api.user.register('me@example.com', 'Example User', 'secret')
{
'auto_reminder' : 30,
'avatar_big' : 'https://*.cloudfront.net/*_big.jpg',
'avatar_medium' : 'https://*.cloudfront.net/*_medium.jpg',
'avatar_s640' : 'https://*.cloudfront.net/*_s640.jpg',
'avatar_small' : 'https://*.cloudfront.net/*_small.jpg',
'business_account_id': None,
'date_format': 0,
'days_off': [6, 7],
'default_reminder': None,
'email': 'me@exampe.com',
'features' : {
'beta': 0,
'restriction' : 3,
'has_push_reminders': false
},
'full_name': 'Example User',
'id': 1855589,
'image_id': None,
'inbox_project': 128501411,
'is_biz_admin': False,
'is_premium': False,
'join_date': '2014-04-30T13:24:38Z',
'karma': 684.0,
'karma_trend': '-',
'legacy_inbox_project': 128501411,
'legacy_team_inbox': 2154866775,
'mobile_host': None,
'mobile_number': None,
'next_week': 1,
'premium_until': None,
'sort_order': 0,
'start_day': 1,
'start_page': 'overdue, 7 days',
'team_inbox': 2154866775,
'theme' : 0,
'time_format': 0,
'token': '0123456789abcdef0123456789abcdef01234567',
'tz_info': {
'timezone': 'GMT +1:00',
'gmt_string': '+01:00',
'hours': 1,
'minutes': 0,
'is_dst': 0
}
}
Parameters
| Parameter | Required | Description |
|---|---|---|
| email String | Yes | The user’s email. |
| full_name String | Yes | The user’s real name formatted as Firstname Lastname. |
| password String | Yes | The user’s password. |
| lang String | No | The user’s language, which can take one of the following values: da, de, en, es, fi, fr, it, ja, ko, nl, pl, pt_BR, ru, sv, tr, zh_CN, zh_TW. |
| timezone String | No | The user’s timezone (a string value such as UTC, Europe/Lisbon, US/Eastern, Asian/Taipei). By default we use the user’s IP address to determine the timezone. |
Delete an existing user
An example of deleting an existing user:
$ curl https://api.todoist.com/sync/v8/user/delete \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d current_password=secret
"ok"
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.user.delete('secret')
ok
Parameters
| Parameter | Required | Description |
|---|---|---|
| current_password String | Yes | The user’s current password. |
Update user’s properties
An example of updating the user’s properties:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "user_update", "uuid": "52f83009-7e27-4b9f-9943-1c5e3d1e6889", "args": {"time_format": 0}}]'
{
...
"sync_status": {"52f83009-7e27-4b9f-9943-1c5e3d1e6889": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.user.update(time_format=0)
Command arguments
| Argument | Required | Description |
|---|---|---|
| email String | No | The user’s email. |
| full_name String | No | The user’s real name formatted as Firstname Lastname. |
| password String | No | The user’s password. |
| timezone String | No | The user’s timezone (a string value such as UTC, Europe/Lisbon, US/Eastern, Asian/Taipei). |
| start_page String | No | The user’s default view on Todoist. The start page can be one of the following: _info_page for the info page, _blank for a blank page, _project_<PROJECT_ID> for project with id <PROJECT_ID>, and <ANY_QUERY> to query after anything. |
| start_day Integer | No | The first day of the week (between 1 and 7, where 1 is Monday and 7 is Sunday). |
| next_week Integer | No | The day of the next week, that tasks will be postponed to (between 1 and 7, where 1 is Monday and 7 is Sunday). |
| time_format Integer | No | Whether to use a 24h format such as 13:00 (if set to 0) when displaying time, or a 12h format such as 1:00pm (if set to 1). |
| date_format Integer | No | Whether to use the DD-MM-YYYY date format (if set to 0), or the MM-DD-YYYY format (if set to 1). |
| sort_order Integer | No | Whether to show projects in an oldest dates first order (if set to 0, or a oldest dates last order (if set to 1). |
| default_reminder String | No | The default reminder for the user. Reminders are only possible for Premium users. The default reminder can be one of the following: email to send reminders by email, mobile to send reminders to mobile devices via SMS, push to send reminders to smart devices using push notifications (one of the Android or iOS official clients must be installed on the client side to receive these notifications), no_default to turn off sending default reminders. |
| auto_reminder Integer | No | The default time in minutes for the automatic reminders set, whenever a due date has been specified for a task. |
| mobile_number String | No | The user’s mobile number (null if not set). |
| mobile_host String | No | The user’s mobile host (or null if not set). |
| theme Integer | No | The currently selected Todoist theme (between 0 and 10). |
Update karma goals
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "update_goals", "uuid": "b9bbeaf8-9db6-452a-a843-a192f1542892", "args": {"vacation_mode": 1}}]'
{
...
"sync_status": {"b9bbeaf8-9db6-452a-a843-a192f1542892": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.user.update_goals(vacation_mode=1)
Update the karma goals of the user.
Command arguments
| Argument | Required | Description |
|---|---|---|
| daily_goal Integer | No | The target number of tasks to complete per day. |
| weekly_goal Integer | No | The target number of tasks to complete per week. |
| ignore_days Integer | No | A list with the days of the week to ignore (1 for Monday and 7 for Sunday). |
| vacation_mode Integer | No | Marks the user as being on vacation (where 1 is true and 0 is false). |
| karma_disabled Integer | No | Whether to disable the karma and goals measuring altogether (where 1 is true and 0 is false). |
Update notification settings
An example of updating the user’s notification settings
$ curl https://api.todoist.com/sync/v8/update_notification_setting \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d notification_type=item_completed \
-d service=email \
-d dont_notify=1
{
"user_left_project": {
"notify_push": true,
"notify_email": true
},
"biz_trial_will_end": {
"notify_push": true,
"notify_email": true
},
"biz_trial_enter_cc": {
"notify_push": true,
"notify_email": true
},
"item_completed": {
"notify_push": true,
"notify_email": false
},
"share_invitation_rejected": {
"notify_push": true,
"notify_email": true
},
"note_added": {
"notify_push": true,
"notify_email": true
},
"biz_account_disabled": {
"notify_push": true,
"notify_email": true
},
"biz_invitation_rejected": {
"notify_push": true,
"notify_email": true
},
"item_uncompleted": {
"notify_push": true,
"notify_email": true
},
"item_assigned": {
"notify_push": true,
"notify_email": true
},
"share_invitation_accepted": {
"notify_push": true,
"notify_email": true
},
"user_removed_from_project": {
"notify_push": true,
"notify_email": true
},
"biz_invitation_accepted": {
"notify_push": true,
"notify_email": true
},
"biz_payment_failed": {
"notify_push": true,
"notify_email": true
}
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.user.update_notification_setting('item_completed', 'email', 1)
{
'biz_invitation_rejected': {
'notify_push': True,
'notify_email': True
},
'user_left_project': {
'notify_push': True,
'notify_email': True
},
'note_added': {
'notify_push': True,
'notify_email': True
},
'biz_trial_enter_cc': {
'notify_push': True,
'notify_email': True
},
'item_completed': {
'notify_push': True,
'notify_email': False
},
'biz_trial_will_end': {
'notify_push': True,
'notify_email': True
},
'biz_account_disabled': {
'notify_push': True,
'notify_email': True
},
'share_invitation_rejected': {
'notify_push': True,
'notify_email': True
},
'item_uncompleted': {
'notify_push': True,
'notify_email': True
},
'item_assigned': {
'notify_push': True,
'notify_email': True
},
'share_invitation_accepted': {
'notify_push': True,
'notify_email': True
},
'user_removed_from_project': {
'notify_push': True,
'notify_email': True
},
'biz_invitation_accepted': {
'notify_push': True,
'notify_email': True
},
'biz_payment_failed': {
'notify_push': True,
'notify_email': True
}
}
Update the user’s notification settings.
Parameters
| Parameter | Required | Description |
|---|---|---|
| notification_type String | Yes | The notification type. For a list of notifications have a look at the Live Notifications section. |
| service String | Yes | The service type, which can take the values: email or push. |
| dont_notify Integer | Yes | Whether notifications of this service should be notified (1 to not notify, and 0 to notify). |
User settings
An example user settings object
{
"reminder_push": true,
"reminder_sms": true,
"reminder_desktop": true,
"reminder_email": true
}
These settings have effect only for Todoist Premium users.
Properties
| Property | Description |
|---|---|
| reminder_push Boolean | Set to true to send reminders as push notifications |
| reminder_sms Boolean | Set to true to send reminders via SMS |
| reminder_desktop Boolean | Set to true to show reminders in desktop applications |
| reminder_email Boolean | Set to true to send reminders by email |
Update user settings
An example of changing user settings:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "user_settings_update", "temp_id": "e24ad822-a0df-4b7d-840f-83a5424a484a", "uuid": "41e59a76-3430-4e44-92b9-09d114be0d49", "args": {"reminder_desktop": false}}]'
{
...
"sync_status": {"41e59a76-3430-4e44-92b9-09d114be0d49": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> reminder = api.user_settings.update(reminder_desktop=False)
>>> api.commit()
Update one or more user settings.
Command arguments
| Argument | Required | Description |
|---|---|---|
| reminder_push Boolean | No | Set to true to send reminders as push notifications |
| reminder_sms Boolean | No | Set to true to send reminders via SMS |
| reminder_desktop Boolean | No | Set to true to show reminders in desktop applications |
| reminder_email Boolean | No | Set to true to send reminders by email |
Sharing
Project can be shared with other users, which are then called collaborators, and this section describes the different commands that are related to sharing.
Collaborators
An example of a collaborator object:
{
"id": 1855589,
"email": "you@example.com",
"full_name": "Example User",
"timezone": "GMT +3:00",
"image_id": null
}
There are two types of objects to get information about a user’s collaborators
and their participation in shared projects: collaborators and
collaborator_states
Every user who shares at least one project with another user, has a collaborators record in the API response. The record contains a restricted subset of user-specific properties.
| Property | Description |
|---|---|
| id Integer | The user id of the collaborator. |
| email String | The email of the collaborator. |
| full_name String | The full name of the collaborator. |
| timezone String | The timezone of the collaborator. |
| image_id Integer | The image id for the collaborator’s avatar, which can be used to get an avatar from a specific URL. Specifically the https://dcff1xvirvpfp.cloudfront.net/<image_id>_big.jpg can be used for a big (195x195 pixels) avatar, https://dcff1xvirvpfp.cloudfront.net/<image_id>_medium.jpg for a medium (60x60 pixels) avatar, and https://dcff1xvirvpfp.cloudfront.net/<image_id>_small.jpg for a small (35x35 pixels) avatar. |
Partial sync returns updated collaborator objects for users that have changed their attributes, such as their name or email.
Collaborator states
An example of a collaborator state:
{
"project_id": 128501470,
"user_id": 1855589,
"state": "active",
"is_deleted": false
}
The list of collaborators doesn’t contain any information on how users are
connected to shared projects. To provide information about these connections,
the collaborator_states field should be used. Every collaborator state record
is a mere “user to shared project” mapping.
| Property | Description |
|---|---|
| project_id Integer | The shared project id of the user. |
| user_id Integer | The user id of the collaborator. |
| state String | The status of the collaborator state, either active or invited. |
| is_deleted Boolean | Set to true when the collaborator leaves the shared project. |
Share a project
An example of sharing a project:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "share_project", "temp_id": "854be9cd-965f-4ddd-a07e-6a1d4a6e6f7a", "uuid": "fe6637e3-03ce-4236-a202-8b28de2c8372", "args": {"project_id": "128501470", "email": "you@example.com"}}]'
{
...
"sync_status": {"fe6637e3-03ce-4236-a202-8b28de2c8372": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.projects.share(128501470, 'you@example.com')
>>> api.commit()
Share a project with another user.
Command arguments
| Argument | Required | Description |
|---|---|---|
| project_id Integer or String (temp_id) | Yes | The project to be shared. |
| email String | Yes | The user email with whom to share the project. |
Delete a collaborator
An example of deleting a person from a shared project:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "delete_collaborator", "uuid": "0ae55ac0-3b8d-4835-b7c3-59ba30e73ae4", "args": {"project_id": 128501470, "email": "you@example.com"}}]'
{
...
"sync_status": {"0ae55ac0-3b8d-4835-b7c3-59ba30e73ae4": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.collaborators.delete(128501470, 'you@example.com')
>>> api.commit()
Remove an user from a shared project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| project_id Integer or String (temp_id) | Yes | The project to be affected. |
| email String | Yes | The user email with whom the project was shared with. |
Accept an invitation
An example of accepting an invitation:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "accept_invitation", "uuid": "4b254da4-fa2b-4a88-9439-b27903a90f7f", "args": {"invitation_id": 1234, "invitation_secret": "abcdefghijklmno"}}]'
{
...
"sync_status": {"4b254da4-fa2b-4a88-9439-b27903a90f7f": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.invitations.accept(1234, 'abcdefghijklmno')
>>> api.commit()
Accept an invitation to join a shared project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| invitation_id Integer | Yes | The invitation id. |
| invitation_secret String | Yes | The secret fetched from the live notification. |
Reject an invitation
An example of rejecting an invitation:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "reject_invitation", "uuid": "284fd900-c36f-44e5-ab92-ee93455e50e0", "args": {"invitation_id": 1234, "invitation_secret": "abcdefghijklmno"}}]'
{
...
"sync_status": {"284fd900-c36f-44e5-ab92-ee93455e50e0": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.invitations.reject(1234, 'abcdefghijklmno')
>>> api.commit()
Reject an invitation to join a shared project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| invitation_id Integer | Yes | The invitation id. |
| invitation_secret String | Yes | The secret fetched from the live notification. |
Delete an invitation
An example of deleting an invitation:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "delete_invitation", "uuid": "399f6a8d-ddea-4146-ae8e-b41fb8ff6945", "args": {"invitation_id": 128501470}}]'
{
...
"sync_status": {"399f6a8d-ddea-4146-ae8e-b41fb8ff6945": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.invitations.delete(128501470)
>>> api.commit()
Delete an invitation to join a shared project.
Command arguments
| Argument | Required | Description |
|---|---|---|
| invitation_id Integer | Yes | The invitation to be deleted. |
Live notifications
Examples of live notifications:
{
"created": 1377639720,
"from_uid": 123,
"id": 1,
"invitation_id": 456,
"invitation_secret": "abcdefghijklmno",
"notification_key": "notification_123",
"notification_type": "share_invitation_sent",
"seq_no": 12345567890,
"state": "accepted"
}
{
"created": 1377639720,
"from_uid": 123,
"id": 2,
"invitation_id": 456,
"notification_key": "notification_123",
"notification_type": "share_invitation_accepted",
"project_id": 789,
"legacy_project_id": 567,
"seq_no": 1234567890
}
{
"created": 1377639720,
"from_uid": 123,
"id": 3,
"invitation_id": 456,
"notification_key": "notification_123",
"notification_type": "share_invitation_rejected",
"project_id": 789,
"legacy_project_id": 567,
"reject_email": "me@example.com",
"seq_no": 1234567890
}
{
"created": 1377639720,
"from_uid": 123,
"id": 4,
"notification_key": "notification_123",
"notification_type": "user_left_project",
"project_id": 456,
"legacy_project_id": 567,
"seq_no": 1234567890
}
{
"created": 1377639720,
"from_uid": 123,
"id": 5,
"notification_key": "notification_123",
"notification_type": "user_removed_from_project",
"project_id": 567,
"legacy_project_id": 456,
"removed_name": "Example User",
"removed_uid": 789,
"seq_no": 1234567890
}
{
"assigned_by_uid": 789,
"created": 1377639720,
"from_uid": 123,
"id": 6,
"item_content": "NewTask",
"item_id": 789,
"legacy_item_id": 456,
"notification_key": "notification_123",
"notification_type": "item_assigned",
"project_id": 567,
"legacy_project_id": 789,
"responsible_uid": 321,
"seq_no": 1234567890
}
{
"assigned_by_uid": 789,
"created": 1377639720,
"from_uid": 123,
"id": 7,
"item_content": "NewTask",
"item_id": 789,
"legacy_item_id": 456,
"notification_key": "notification_123",
"notification_type": "item_completed",
"project_id": 567,
"legacy_project_id": 789,
"responsible_uid": 321,
"seq_no": 1234567890
}
{
"assigned_by_uid": 789,
"created": 1377639720,
"from_uid": 123,
"id": 8,
"item": 456,
"item_content": "NewTask",
"notification_key": "notification_123",
"notification_type": "item_uncompleted",
"project": 789,
"responsible_uid": 321,
"seq_no": 1234567890
}
{
"created": 1377639720,
"from_uid": 123,
"id": 9,
"item_id": 789,
"legacy_item_id": 456,
"note_content": "NewTask",
"note_id": 321,
"legacy_note_id": 789,
"notification_key": "notification_123",
"notification_type": "note_added",
"project_id": 221,
"legacy_project_id": 321,
"seq_no": 1234567890
}
{
"created": 1377639720,
"email": "me@example.com",
"from_uid": 123,
"id": 10,
"notification_key": "notification_123",
"notification_type": "biz_policy_disallowed_invitation",
"project_id": 543,
"legacy_project_id": 456,
"seq_no": 1234567890,
"from_user": {
"email": "you@example.com",
"full_name": "Example User",
"id": "789",
"image_id": "321"
}
}
{
"created": 1377639720,
"from_uid": 123,
"id": 11,
"inviter_id": 456,
"notification_key": "notification_123",
"notification_type": "biz_policy_rejected_invitation",
"seq_no": 1234567890,
"from_user": {
"email": "you@example.com",
"full_name": "Example User",
"id": "789",
"image_id": "321"
}
}
{
"active_until": 1399299727,
"created": 1377639720,
"from_uid": 123,
"id": 12,
"notification_key": "notification_123",
"notification_type": "biz_trial_will_end",
"plan": "business_monthly",
"quantity": 10,
"seq_no": 1234567890
}
{
"active_until": 1399299727,
"amount_due": 600,
"attempt_count": 1,
"created": 1377639720,
"currency": "usd",
"description": "2 x Subscription to Monthly ($3.00/month)",
"from_uid": 123,
"id": 13,
"next_payment_attempt": 1399299735,
"notification_key": "notification_123",
"notification_type": "biz_payment_failed",
"plan": "business_monthly",
"quantity": 10,
"seq_no": 1234567890
}
{
"active_until": 1399299727,
"created": 1377639720,
"from_uid": 123,
"id": 14,
"notification_key": "notification_123",
"notification_type": "biz_account_disabled",
"plan": "business_monthly",
"quantity": 10,
"seq_no": 1234567890
}
{
"account_name": "Example Inc.",
"created": 1377639720,
"from_uid": 123,
"from_user": {
"email": "you@example.com",
"full_name": "Example User",
"id": "456",
"image_id": "789"
},
"id": 15,
"invitation_id": 321,
"invitation_message": "Welcome to our team!",
"invitation_secret": "abcdefghijklmno",
"notification_key": "notification_123",
"notification_type": "biz_invitation_created",
"seq_no": 1234567890,
"state": "accepted"
}
{
"created": 1377639720,
"from_uid": 123,
"from_user": {
"account_name": "Example Inc.",
"email": "you@example.com",
"full_name": "Example User",
"id": "456",
"image_id": "789"
},
"id": 16,
"invitation_id": 321,
"notification_key": "notification_123",
"notification_type": "biz_invitation_accepted",
"seq_no": 1234567890
}
{
"created": 1377639720,
"from_uid": 123,
"from_user": {
"account_name": "Example Inc.",
"email": "you@example.com",
"full_name": "Example User",
"id": "456",
"image_id": "789"
},
"id": 17,
"invitation_id": 321,
"notification_key": "notification_123",
"notification_type": "biz_invitation_rejected",
"seq_no": 1234567890
}
Types
This is the list of notifications which can be issued by the system:
| Type | Description |
|---|---|
| share_invitation_sent | Sent to the sharing invitation receiver. |
| share_invitation_accepted | Sent to the sharing invitation sender, when the receiver accepts the invitation. |
| share_invitation_rejected | Sent to the sharing invitation sender, when the receiver rejects the invitation. |
| user_left_project | Sent to everyone when somebody leaves the project. |
| user_removed_from_project | Sent to everyone, when a person removes somebody from the project. |
| item_assigned | Sent to user who is responsible for the task. Optionally it’s also sent to the user who created the task initially, if the assigner and the task creator is not the same person. |
| item_completed | Sent to the user who assigned the task when the task is completed. Optionally it’s also sent to the user who is responsible for this task, if the responsible user and the user who completed the task is not the same person. |
| item_uncompleted | Sent to the user who assigned the task when the task is uncompleted. Optionally it’s also sent to the user who is responsible for this task, if the responsible user and the user who completed the task is not the same person. |
| note_added | Sent to all members of the shared project, whenever someone adds a note to the task. |
| biz_policy_disallowed_invitation | Sent to you when you try to share a project with someone outside of your business account, but the business account policy disallows this action. |
| biz_policy_rejected_invitation | Sent to you when you try to accept the invitation to a shared project from someone outside of your business account, but the business account policy disallows this action. |
| biz_trial_will_end | Sent to all business account administrators three days before the trial period of a subscription is scheduled to end. |
| biz_payment_failed | Sent to all business account administrators whenever an invoice attempt payment fails. This can occur either due to a declined payment, or because the customer has no active card. A particular case of note is that if a customer with no active card reaches the end of its free trial. |
| biz_account_disabled | Sent to all business account administrators when the account is disabled. |
| biz_invitation_created | Sent to an invitee, when one of business account administrators invites this user to the business account. |
| biz_invitation_accepted | Sent to an inviter, when the invitation is accepted. |
| biz_invitation_rejected | Sent to an inviter, when the invitation is rejected. |
Common properties
Some properties are common for all types of notifications, whereas some others depend on the notification type.
Every live notification has the following properties:
| Property | Description |
|---|---|
| id Integer | The id of the live notification. |
| legacy_id Integer | The legacy id of the live notification. (only shown for objects created before 1 April 2017) |
| created Integer | Live notification creation date. A number representing a timestamp since epoch. |
| from_uid Integer | The id of the user who initiated this live notification. |
| notification_key String | Unique notification key. |
| notification_type String | Type of notification. Different notification type define different extra fields which are described below. |
| seq_no Integer | Notification sequence number. |
| is_unread Integer | Whether the notification is marked as unread (1) or read (0). |
Specific properties
Here are the extra properties for the *_invitation_* types of live
notifications:
| Property | Description |
|---|---|
| from_user Object | User data, useful on share_invitation_sent. |
| project_name String | The project name, useful for share_invitation_* where you may not have the project in the local model. |
| invitation_id Integer | The invitation id. Useful for accepting/rejecting invitations. |
| invitation_secret String | The invitation secret key. Useful for accepting/rejecting invitations. |
Here are the extra properties for the share_invitation_sent type of live notifications:
| Property | Description |
|---|---|
| state String | Invitation state. Initially invited, can change the state to accepted or rejected. |
Here are the extra properties for the user_removed_from_project type of live notifications:
| Property | Description |
|---|---|
| removed_name String | The name of the user removed. |
| removed_uid Integer | The uid of the user removed. |
Here are the extra properties for the biz_trial_will_end type of live notifications:
| Property | Description |
|---|---|
| quantity Integer | The number of users under the control of the business account. |
| plan String | Tariff plan name. Valid values are business_monthly and business_yearly. |
| active_until Integer | The timestamp when the business account will be disabled. The value may not match the business account subscription end date, as we give some extra days (up to two weeks) to pay the invoice. |
Here are the extra properties for the biz_payment_failed type of live notifications:
| Property | Description |
|---|---|
| quantity Integer | The number of users under the control of the business account. |
| plan String | Tariff plan name. Valid values are business_monthly and business_yearly. |
| active_until Integer | The timestamp when the business account will be disabled. The value may not match the business account subscription end date, as we give some extra days (up to two weeks) to pay the invoice. |
| amount_due Integer | Invoice amount. Integer value in 0.01 of currency. |
| attempt_count Integer | Number of automatic payment attempts made for this invoice. |
| currency String | Currency value. Three-letter ISO currency code representing the currency in which the charge was made. |
| description String | Invoice description. |
| next_payment_attempt String | Timestamp value. |
Here are the extra properties for the biz_account_disabled type of live notifications:
| Property | Description |
|---|---|
| quantity Integer | The number of users under the control of the business account. |
| plan String | Tariff plan name. Valid values are business_monthly and business_yearly. |
| active_until Integer | The timestamp when the business account will be disabled. The value may not match the business account subscription end date, as we give some extra days (up to two weeks) to pay the invoice. |
Here are the extra properties for the biz_invitation_created type of live
notifications:
| Property | Description |
|---|---|
| state String | Invitation state. Initially invited, can change the state to accepted or rejected. |
| invitation_secret String | Invitation secret. Should be used to accept or reject invitation. |
| invitation_message String | Invitation message. |
| account_name String | Business account (company) name. |
Set last known
An example of setting the last known notification:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "live_notifications_set_last_read", "uuid": "588b9ccf-29c0-4837-8bbc-fc858c0c6df8", "args": {"id": 1234}}]'
{
...
"sync_status": {"588b9ccf-29c0-4837-8bbc-fc858c0c6df8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.live_notifications.set_last_read(1234)
>>> api.commit()
Set the last known notification.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer | Yes | The id of the last known notification (a number or 0 or null to mark all read). |
Mark as read
An example of marking a notification as read:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "live_notifications_mark_read", "uuid": "588b9ccf-29c0-4837-8bbc-fc858c0c6df8", "args": {"id": 1234}}]'
{
...
"sync_status": {"588b9ccf-29c0-4837-8bbc-fc858c0c6df8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.live_notifications.mark_read(1234)
>>> api.commit()
Mark the notification as read.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer | Yes | The id of the notification. |
Mark all as read
An example of marking all notifications as read:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "live_notifications_mark_read_all", "uuid": "588b9ccf-29c0-4837-8bbc-fc858c0c6df8"}]'
{
...
"sync_status": {"588b9ccf-29c0-4837-8bbc-fc858c0c6df8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.live_notifications.mark_read_all()
>>> api.commit()
Mark all notifications as read.
Mark as unread
An example of marking a notification as unread:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "live_notifications_mark_unread", "uuid": "588b9ccf-29c0-4837-8bbc-fc858c0c6df8", "args": {"id": 1234}}]'
{
...
"sync_status": {"588b9ccf-29c0-4837-8bbc-fc858c0c6df8": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.live_notifications.mark_unread(1234)
>>> api.commit()
Mark the notification as unread.
Command arguments
| Argument | Required | Description |
|---|---|---|
| id Integer | Yes | The id of the notification. |
Business
An example invitation object:
{
"base_url": "http://todoist.com",
"business_account_id": 2,
"email": "z@example.com",
"id": 13,
"inviter_id": 1,
"message": "Welcome to our company business account",
"secret": "0692805f97d9c091debaba52d18f5696",
"user_id": 1
}
The set of functions and Sync API commands to manage Todoist Business accounts. All these functionality is only available for Business account admins.
In order to become a business account admin, you should create a new account from Todoist Business Free Trial, or to ask another business account admin to invite you, and to make you an admin.
User, who is also a business account admin has the attribute is_biz_admin, set
to true.
Send invitation
An example of sending an invitation:
$ curl https://api.todoist.com/sync/v8/business/users/invite \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d email_list='["spam@example.com","egg@example.com"]'
-d message='Welcome'
[
{
"base_url": "http://todoist.com",
"business_account_id": 2,
"email": "spam@example.com",
"id": 15,
"inviter_id": 1,
"message": "Welcome",
"secret": "21d5a7fc4fa7e9d47a6642069d2af6ef",
"user_id": 6
},
{
"base_url": "http://todoist.com",
"business_account_id": 2,
"email": "egg@example.com",
"id": 16,
"inviter_id": 1,
"message": "Welcome",
"secret": "4e20a8b58abe07441c4c30fff34798ed",
"user_id": 15
}
]
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.business_users.invite(['spam@example.com','egg@example.com'])
[
{
'base_url': 'http://todoist.com',
'business_account_id': 2,
'email': 'spam@example.com',
'id': 15,
'inviter_id': 1,
'message': 'Welcome',
'secret': '21d5a7fc4fa7e9d47a6642069d2af6ef',
'user_id': 6
},
{
'base_url': 'http://todoist.com',
'business_account_id': 2,
'email': 'egg@example.com',
'id': 16,
'inviter_id': 1,
'message': 'Welcome',
'secret': '4e20a8b58abe07441c4c30fff34798ed',
'user_id': 15
}
]
This function allows you to send invitation to your business account. Every invitation object has an unique id and secret code. Anyone who knows this information, can activate invitation and join your business account. Invitation is deactivated at the moment it’s accepted or rejected by receiver, or deleted manually by sender.
Invitation objects are not created (quietly skipped), if the invitation recipient is an existing Todoist user and this user already belongs to a business account.
If an invitation for that recipient already exists and hasn’t been activated yet, a new invitation object will not be created. Instead, an existing invitation will be re-sent and the corresponding invitation object will be returned back.
The return value is a list of invitation objects.
Parameters
| Parameter | Required | Description |
|---|---|---|
| email_list Array of Strings | Yes | The emails of users which will be invited |
| message String | No | Additional text which will be included to invitation welcome message |
Accept invitation
An example of accepting a business invitation with a direct call:
$ curl https://api.todoist.com/sync/v8/business/users/accept_invitation \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d id=1234 \
-d secret=abcdefghijklmno
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.business_users.accept_invitation(1234, 'abcdefghijklmno')
An example of accepting a business invitation with a Sync API command:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "biz_accept_invitation", "uuid": "48538e47-7a9f-4f3d-927a-463ea997675e", "args": {"invitation_id": 1234, "invitation_secret": "abcdefghijklmno"}}]'
{
...
"sync_status": {"48538e47-7a9f-4f3d-927a-463ea997675e": "ok"},
...
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.biz_invitations.accept(1234, 'abcdefghijklmno')
>>> api.commit()
There are currently 2 ways to accept an invitation, either with a direct call, or by using a Sync API command, as can be seen from the examples on the side, and the different required parameters below.
The invitation is accepted if it’s still active and user doesn’t belong to any
business account yet. For the direct call, null denotes a successful return
value.
Parameters
For the direct call:
| Parameter | Required | Description |
|---|---|---|
| id Integer | Yes | The invitation id (a number). |
| secret String | Yes | The secret fetched from the live notification (a string value). |
For the Sync API command:
| Command argument | Required | Description |
|---|---|---|
| invitation_id Integer | Yes | The invitation id (a number). |
| invitation_secret String | Yes | The secret fetched from the live notification (a string value). |
Reject invitation
An example of rejecting a business invitation with a direct call:
$ curl https://api.todoist.com/sync/v8/business/users/reject_invitation \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d id=1234 \
-d secret=abcdefghijklmno
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.business_users.reject_invitation(1234, 'abcdefghijklmno')
An example of rejecting a business invitation with a Sync API command:
$ curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[{"type": "biz_reject_invitation", "uuid": "a1b0460a-aab3-4555-9109-779cd0cb0966", "args": {"invitation_id": 1234, "invitation_secret": "abcdefghijklmno"}}]'
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.biz_invitations.reject(1234, 'abcdefghijklmno')
>>> api.commit()
There are currently 2 ways to reject an invitation, either with a direct call, or by using a Sync API command, as can be seen from the examples on the side, and the different required parameters below.
The invitation is rejected and deleted. Note that the client doesn’t have to
provide the user’s token to reject invitation: it’s enough to provide knowledge
of invitation secret business account yet. For the direct call, null denotes
a successful return value.
Parameters
For the direct call:
| Parameter | Required | Description |
|---|---|---|
| id Integer | Yes | The invitation id (a number). |
| secret String | Yes | The secret fetched from the live notification (a string value). |
For the Sync API command:
| Command argument | Required | Description |
|---|---|---|
| invitation_id Integer | Yes | The invitation id (a number). |
| invitation_secret String | Yes | The secret fetched from the live notification (a string value). |
Activity
Activity log is only available for Todoist Premium.
The activity log makes it easy to see everything that is happening across projects, items and notes.
Logged events
Currently the official Todoist clients present only the most important events that most users are interested in, but actually everything that has to do with projects, items and notes, is stored in our DB, and can be accessed by using our API.
The following events are logged for items:
- items added
- items updated (only changes to
content,due_dataandresponsible_uid) - items deleted
- items completed
- items uncompleted
The following events are logged for notes:
- notes added
- notes updated (only changes to
contentorfile_nameif the former is empty) - notes deleted
The following events are logged for projects:
- projects added
- projects updated (only changes to
name) - projects deleted
- projects archived
- projects unarchived
- projects shared
- projects left
Event properties
An example of an activity log event:
{
"id" : 955333384,
"object_type" : "item",
"object_id" : 369593374,
"legacy_object_id" : 101157918,
"event_type" : "added",
"event_date" : "2016-07-01T14:24:59Z",
"parent_project_id" : 442796969,
"legacy_parent_project_id" : 174361513,
"parent_item_id" : null,
"legacy_parent_item_id" : null,
"initiator_id" : null,
"extra_data" : {
"content" : "Task1",
"client" : "Mozilla/5.0; Todoist/830"
}
}
{
'id': 955333384,
'object_type': 'item',
'object_id': 101157918,
'event_type': 'added',
'event_date': '2016-07-01T14:24:59Z',
'parent_project_id': 174361513,
'parent_item_id': None,
'initiator_id': None,
'extra_data': {
'content': 'Task1',
'client' : 'Mozilla/5.0; Todoist/830'
}
}
| Property | Description |
|---|---|
| id Integer | The id of the event. |
| object_type String | The type of object, one of item, note or project. |
| object_id Integer | The id of the object. |
| legacy_object_id Integer | The legacy id of the object. (only shown for objects created before 1 April 2017) |
| event_type String | The type of event, one of added, updated, deleted, completed, uncompleted, archived, unarchived, shared, left. |
| event_date String | The date and time when the event took place. |
| parent_project_id Integer | The id of the item’s or note’s parent project, otherwise null. |
| legacy_parent_project_id Integer | The legacy id of the item’s or note’s parent project, otherwise null. (only shown for objects created before 1 April 2017) |
| parent_item_id Integer | The id of the note’s parent item, otherwise null. |
| legacy_parent_item_id Integer | The legacy id of the note’s parent item, otherwise null. (only shown for objects created before 1 April 2017) |
| initiator_id Integer | The id of the user who is responsible for the event, which only makes sense in shared projects, items and notes, and is null for non-shared objects. |
| extra_data Object | This object contains at least the name of the project, or the content of an item or note, and optionally the last_name if a projects was renamed, the last_content if an item or note was renamed, the due_date and last_due_date if an item’s due date changed, the responsible_uid and last_responsible_uid if an item’s responsible uid changed, and the client that caused the logging of the event. |
Get activity logs
An example of getting the activity logs:
$ curl https://api.todoist.com/sync/v8/activity/get \
-d token=0123456789abcdef0123456789abcdef01234567 \
{
"events": [
{
"id" : 955344370,
"object_type" : "item",
"object_id" : 101157918,
"event_type" : "updated",
"event_date" : "2016-07-01T14:28:37Z",
"parent_project_id" : 174361513,
"parent_item_id" : null,
"initiator_id" : null,
"extra_data" : {
"last_due_date" : null,
"due_date" : "2016-07-02T20:59:59Z",
"content" : "Task1",
"client" : "Mozilla/5.0; Todoist/830"
}
},
{
"id" : 955333751,
"object_type" : "note",
"object_id" : 23685068,
"event_type" : "added",
"event_date" : "2016-07-01T14:25:04Z",
"parent_project_id" : 174361513,
"parent_item_id" : 101157918,
"initiator_id" : null,
"extra_data" : {
"content" : "Note1",
"client": "Todoist/11.2.1"
}
},
{
"id" : 955333384,
"object_type" : "item",
"object_id" : 101157918,
"event_type" : "added",
"event_date" : "2016-07-01T14:24:59Z",
"parent_project_id" : 174361513,
"parent_item_id" : null,
"initiator_id" : null,
"extra_data" : {
"content" : "Task1",
"client": "Todoist 2051"
}
},
{
"id" : 955333239,
"object_type" : "project",
"object_id" : 174361513,
"event_type" : "added",
"event_date" : "2016-07-01T14:24:56Z",
"parent_project_id" : null,
"parent_item_id" : null,
"initiator_id" : null,
"extra_data" : {
"name" : "Project1",
"client": "TodoistForWindows10"
}
}
],
"count": 4
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.activity.get()
{
'events': [
{
'id': 955344370,
'object_type': 'item',
'object_id': 101157918,
'event_type': 'updated',
'event_date': '2016-07-01T14:28:37Z',
'parent_project_id': 174361513,
'parent_item_id': None,
'initiator_id': None,
'extra_data': {
'content': 'Task1',
'due_date': '2016-07-02T20:59:59Z',
'last_due_date': None,
'client' : 'Mozilla/5.0; Todoist/830'
}
},
{
'id': 955333751,
'object_type': 'note',
'object_id': 23685068,
'event_type': 'added',
'event_date': '2016-07-01T14:25:04Z',
'parent_project_id': 174361513,
'parent_item_id': 101157918,
'initiator_id': None,
'extra_data': {
'content': 'Note1',
'client': 'Todoist/11.2.1'
}
},
{
'id': 955333384,
'object_type': 'item',
'object_id': 101157918,
'event_type': 'added',
'event_date': '2016-07-01T14:24:59Z',
'parent_project_id': 174361513,
'parent_item_id': None,
'initiator_id': None,
'extra_data': {
'content': 'Task1',
'client': 'Todoist 2051'
}
},
{
'id': 955333239,
'object_type': 'project',
'object_id': 174361513,
'event_type': 'added',
'event_date': '2016-07-01T14:24:56Z',
'parent_project_id': None,
'parent_item_id': None,
'initiator_id': None,
'extra_data': {
'name': 'Project1',
'client': 'TodoistForWindows10'
}
}
],
'count': 4
}
Get’s activity log events.
Properties
| Parameter | Required | Description |
|---|---|---|
| object_type String | No | Filters events by a specific object type. |
| object_id Integer | No | Filters events by a specific object id, but only if the object_type has been also specified. |
| event_type String | No | Filters events by a specific event type. |
| object_event_types Array of Strings | No | An alternative way to filter by multiple object and event types. This takes a list of strings of the form [object_type]:[event_type] (where either object_type part or the event_type part can be omitted), such as for example ["item:", "note:added"]. When this parameter is specified the object_type, event_type and object_id parameters are ignored. |
| parent_project_id Integer | No | Filters object events by the id of the project they belong to, so this implicitly limits the results to items and notes. |
| parent_item_id Integer | No | Filters object events by the id of the item they belong, so this implicitly limits the results to notes. |
| initiator_id Integer | No | Filters event by the id of the initiator. |
| page Integer | No | The page number, used to iterate over the list of events. Events are split in pages by weeks. Page 0 corresponds to events of the current week. Page 1 is for events of the previous week, etc. Not defining a page parameter means events from the current week plus events from last week (ie. page=0 and page=1). This is useful for the clients in order to always fetch at least a week’s events even on Mondays. |
| limit Integer | No | The number of events to return, where the default is 30, and the maximum is 100. |
| offset Integer | No | The number of events to skip, which can be used for pagination in order to get more events than those returned by the previous call. |
Return value
| Value | Description |
|---|---|
| events Array of Objects | The activity log events. |
| count Integer | The total count of events with the specified parameters, irregardless of the limit and offset parameters. |
Backups
Get backups
The list of recent backup archives can be accessed via the following API endpoint, and upon successful request, a HTTP 200 response will be returned with a list of backup archives in JSON format:
$ curl https://api.todoist.com/sync/v8/backups/get \
-d token=0123456789abcdef0123456789abcdef01234567
[
{
"version": "2018-07-13 02:03",
"url": "https://downloads.todoist.com/12345678901234567890123456789012.zip"
},
...
]
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.backups.get()
[
{
'version': '2018-07-13 02:03',
'url': 'https://downloads.todoist.com/12345678901234567890123456789012.zip'
},
...
]
Todoist creates a backup archive of users’ data on a daily
basis. Backup archives can also be accessed from the web app (Todoist
Settings -> Backups).
Download the backup
$ curl -L -H "Authorization: Bearer 0123456789abcdef0123456789abcdef01234567" \
https://downloads.todoist.com/12345678901234567890123456789012.zip > /tmp/todoist-backup.zip
Get backups will retrieve a list of downloadable files for the user related to the token being used. To download one of the files returned, you have to use the token as a header.
Emails
Get or create
An example creating an email to an object:
$ curl https://api.todoist.com/sync/v8/emails/get_or_create \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d obj_type=project \
-d obj_id=128501411
{
"email": "Inbox <add.task.1855589.128501411.9a3ae36588cf36df@todoist.net>"
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.emails.get_or_create('project', 128501411)
{
'email': 'Inbox <add.task.1855589.128501411.9a3ae36588cf36df@todoist.net>'
}
Creates a new email address for an object, or gets an existing email.
Parameters
| Parameter | Required | Description |
|---|---|---|
| obj_type String | Yes | The object’s type, one of project, project_comments or item. |
| obj_id Integer | Yes | The object’s id. |
Disable
An example disabling an email to an object:
$ curl https://api.todoist.com/sync/v8/emails/disable \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d obj_type=project \
-d obj_id=128501411
{
"status": "ok"
}
>>> import todoist
>>> api = todoist.TodoistAPI('0123456789abcdef0123456789abcdef01234567')
>>> api.emails.disable('project', 128501411)
{
'status': 'ok'
}
Disables an email address for an object.
Parameters
| Parameter | Required | Description |
|---|---|---|
| obj_type String | Yes | The object’s type, one of project, project_comments or item. |
| obj_id Integer | Yes | The object’s id. |
URL schemes
The following URL schemes might also be useful when accessing the Todoist applications (iOS and Android) or when performing certain actions with them, so they are also included here for completeness.
Views
The following schemes are available to open a specific view:
| Scheme | Description |
|---|---|
| todoist:// | Opens Todoist. |
| todoist://today | Opens the today view. |
| todoist://upcoming | Opens the Upcoming view. |
| todoist://profile | Opens the profile view. |
| todoist://inbox | Opens the inbox view. |
| todoist://teaminbox | Opens the team inbox view. If the user doesn’t have a business account (access to team inbox), it will show an alert saying that he/she doesn’t have access to the team inbox because he/she doesn’t have a business account and will be redirected automatically to the inbox view. |
| todoist://notifications | Opens notifications view. |
Tasks
Example of adding a task:
todoist://addtask?content=mytask&date=tomorrow&priority=4
Here’s an example of a content value:
Create document about URL Schemes!
And how it should be supplied using Percent-encoding:
Create&20document%20about%20URL%20Schemes%21
Here’s an example of a date value:
Tomorrow @ 14:00
And how it should be supplied using Percent-encoding:
Tomorrow%20@%2014:00
The following schemes are available for task:
| Scheme | Description |
|---|---|
| todoist://task?id={id} | Opens the task by id |
| todoist://addtask | Opens the add task view to add a new task to Todoist. |
The todoist://addtask scheme accepts the following optional values:
| Value | Description |
|---|---|
| content URL encoding | The content of the task, which should be a string that in Percent-encoding (also known as URL encoding). |
| date URL encoding | The due date of the task, which should be a string that in Percent-encoding (also known as URL encoding). Look at our reference to see which formats are supported. |
| priority Integer | The priority of the task (a number between 1 and 4, 4 for very urgent and 1 for natural). Note: Keep in mind that very urgent is the priority 1 on clients. So, p1 will return 4 in the API. |
If all the values are empty, it will just open the add task view. This URL Scheme will not automatically add the task to Todoist, it will just open the add task view and fill the fields.
Projects
The following scheme is available to show all the projects:
| Scheme | Description |
|---|---|
| todoist://projects | Opens the projects view (shows all projects). |
Example of opening a specific project:
todoist://project?id=128501470
The following scheme is available to open a specific project:
| Scheme | Description |
|---|---|
| todoist://project | Opens a specific project using the id of the project. |
The todoist://project scheme accepts the following required value:
| Value | Description |
|---|---|
| id Integer | The id of the project to view. If the id doesn’t exist, you don’t have access to the project, or the value is empty, an alert will be showed and the user will be redirected to the projects view. |
Labels
The following scheme is available to show all the labels:
| Scheme | Description |
|---|---|
| todoist://labels | Opens the labels view (shows all labels) |
Example of opening a specific label:
todoist://label?name=Urgent
The following scheme is available to open a specific label:
| Scheme | Description |
|---|---|
| todoist://label | Opens a specific label using the name of the label. |
The todoist://label scheme accepts the following required value:
| Value | Description |
|---|---|
| name String | The name of the label to view. If the label doesn’t exist, you don’t have access to the label, or the value is empty, an alert will be shown. |
Filters
The following scheme is available to show all the filters:
| Scheme | Description |
|---|---|
| todoist://filters | Opens the filters view (shows all filters) |
Example of opening a specific filter:
todoist://filter?id=9
The following scheme is available to open a specific filter:
| Scheme | Description |
|---|---|
| todoist://filter | Opens a specific filter using the id of the filter. |
The todoist://filter scheme accepts the following required value:
| Value | Description |
|---|---|
| id Integer | The id of the filter to view. If the id doesn’t exist, you don’t have access to the filter, or the value is empty, an alert will be showed and the user will be redirected to the filters view. |
Search
Example of searching for “Test & Today”:
todoist://search?query=Test%20%26%20Today
The following scheme is available for searching (Android only):
| Scheme | Description |
|---|---|
| todoist://search | Used to search in the Todoist application. |
The todoist://search scheme accepts the following required value:
| Value | Description |
|---|---|
| query URL encoding | The query to search in the Todoist application, which should be a string that is in Percent-encoding (also known as URL encoding). |
Webhooks
The Todoist Webhooks API allows applications to receive real-time notification (in the form of HTTP POST payload) on the subscribed user events. Notice that once you have a webhook setup, you will start receiving webhook events from all your app users immediately.
Important Considerations
Due to the nature of network requests, your application should assume webhook requests could arrive out of order or could even fail to arrive; webhooks should be used only as notifications and not as a primary Todoist data source (make sure your application could still work when webhook is not available).
Configuration
Before you can start receiving webhook event notifications, you must first have your webhook configured at the App Management Console.
Events
Here is a list of events that you could subscribe to, and they are configured at the App Management Console.
| Event Name | Description |
|---|---|
| item:added | An item was added |
| item:updated | An item was updated |
| item:deleted | An item was deleted |
| item:completed | An item was completed |
| item:uncompleted | An item was uncompleted |
| note:added | A note was added |
| note:updated | A note was updated |
| note:deleted | A note was deleted |
| project:added | A project was added |
| project:updated | A project was updated |
| project:deleted | A project was deleted |
| project:archived | A project was archived |
| project:unarchived | A project was unarchived |
| label:added | A label was added |
| label:deleted | A label was deleted |
| label:updated | A label was updated |
| filter:added | A filter was added |
| filter:deleted | A filter was deleted |
| filter:updated | A filter was updated |
| reminder:fired | A reminder has fired |
Request Format
Event JSON Object
Each webhook event notification request contains a JSON object. The event JSON object follows this general structure:
{"event_name": "...", "user_id"=..., "event_data": {...}}
The user_id points to the destination of the event.
The structure of the event_data object varies depending on the type of event
it is. For instance, if it is an “item:added” event notification, The
event_data will represent the newly added item.
Example Delivery
POST /payload HTTP/1.1
Host: your_callback_url_host
Content-Type: application/json
X-Todoist-Hmac-SHA256: UEEq9si3Vf9yRSrLthbpazbb69kP9+CZQ7fXmVyjhPs=
{
"event_name": "item:added",
"user_id": 1234,
"event_data": {
"day_order": -1,
"added_by_uid": 1855589,
"assigned_by_uid": 1855589,
"labels": [],
"sync_id": null,
"in_history": 0,
"has_notifications": 0,
"parent_id": null,
"checked": 0,
"date_added": "2014-09-26T08:25:05Z",
"id": 33511505,
"content": "Task1",
"user_id": 1234,
"due": null,
"children": null,
"priority": 1,
"child_order": 1,
"is_deleted": 0,
"responsible_uid": null,
"project_id": 128501470,
"collapsed": 0,
}
}
...
Request Header
| Header Name | Description |
|---|---|
| User-Agent | Will be set to “Todoist-Webhooks” |
| X-Todoist-Hmac-SHA256 | To verify each webhook request was indeed sent by Todoist, an X-Todoist-Hmac-SHA256 header is included; it is a SHA256 Hmac generated using your client_secret as the encryption key and the whole request payload as the message to be encrypted. The resulting Hmac would be encoded in a base64 string. |
| X-Todoist-Delivery-ID | Each webhook event notification has a unique X-Todoist-Delivery-ID. When a notification request failed to be delivered to your endpoint, the request would be re-delivered with the same X-Todoist-Delivery-ID. |
Failed Delivery
When an event notification failed to be delivered to your webhook callback URL endpoint (i.e. due to server error, network failure, incorrect response, etc), it would be re-delivered after 15 mins, and each notification would be re-delivered for at most three times.
Your callback endpoint must respond with a HTTP 200 when receiving an event notification request.
A response other than HTTP 200 would be considered as failed delivery, and the notification would be delivered again.
Batching commands
Batching multiple commands
When working with the Sync API, changes can be batched into one commit. In our example, we’re batching the creation of a Shopping List project with three different items.
curl https://api.todoist.com/sync/v8/sync \
-d token=0123456789abcdef0123456789abcdef01234567 \
-d commands='[
{
"type": "project_add",
"temp_id": "0a57a3db-2ff1-4d2d-adf6-12490c13c712",
"uuid": "2c0f6e03-c372-46ba-8e85-d94af56abcf3",
"args": { "name": "Shopping List" }
},
{
"type": "item_add",
"temp_id": "ef3d840e-84c9-4433-9a32-86ae9a1e7d42",
"uuid": "49ede211-12f3-42e9-8345-4c0d2b29c08d",
"args": { "content": "Bananas", "project_id": "0a57a3db-2ff1-4d2d-adf6-12490c13c712" }
},
{
"type": "item_add",
"temp_id": "8a23c8cb-1d76-469d-a2c0-80a28b3ea6f6",
"uuid": "46619250-ae02-4ab0-bd31-3c9ab0307e53",
"args": { "content": "Apples", "project_id": "0a57a3db-2ff1-4d2d-adf6-12490c13c712" }
},
{
"type": "item_add",
"temp_id": "bf087eaf-aea9-4cb1-ab57-85188a2d428f",
"uuid": "d0a1666b-d615-4250-aac5-65c7ea89091a",
"args": { "content": "Oranges", "project_id": "0a57a3db-2ff1-4d2d-adf6-12490c13c712" }
}]'
{
"sync_status": {
"2c0f6e03-c372-46ba-8e85-d94af56abcf3": "ok",
"49ede211-12f3-42e9-8345-4c0d2b29c08d": "ok",
"d0a1666b-d615-4250-aac5-65c7ea89091a": "ok",
"46619250-ae02-4ab0-bd31-3c9ab0307e53": "ok"
},
"temp_id_mapping": {
"8a23c8cb-1d76-469d-a2c0-80a28b3ea6f6": 2532257185,
"0a57a3db-2ff1-4d2d-adf6-12490c13c712": 2178698342,
"bf087eaf-aea9-4cb1-ab57-85188a2d428f": 2532257187,
"ef3d840e-84c9-4433-9a32-86ae9a1e7d42": 2532257182
},
"full_sync": true,
"sync_token": "ejXTquzEdPmZb3E82aFs_wp3oassQzhj3xtpVH8-EaRRJfpZPVXhtVRyTvQz-Mjf827kM8rNuT8pXeumPrEE8qjvYTOe-nIWVgog23OOECR4Gj0"
}
from todoist.api import TodoistAPI
api = TodoistAPI('0123456789abcdef0123456789abcdef01234567')
shopping_list = api.projects.add('Shopping List')
item_one = api.items.add('Bananas', project_id=shopping_list['id'])
item_two = api.items.add('Apples', project_id=shopping_list['id'])
item_three = api.items.add('Oranges', project_id=shopping_list['id'])
api.commit()
print(shopping_list, item_one, item_two, item_three)
As we’ve committed the changes all at once, we’re significantly reducing the amount of network calls that have to be made, as well as ensuring we’re not running into any rate limiting issues.
We’re able to batch up to 100 commands per request and when combined with the 50 requests per minute, this gives us a total of 5,000 requests per minute when maximally batched.
Limits
There is currently a 1MiB http request body limit on POST requests. The exception to this rule is any of the upload endpoints which have a limit of 100 MiB.
Upload endpoints are for POST requests pointed at paths such as /upload and /uploads/add.
Sync
The maximum number of commands is 100 per request, and this is done to prevent timeouts and other problems when dealing with big requests.
There’s also a maximum number of 50 sync requests per minute for each user, in order to prevent clients from accidentally overloading our servers.
Processing Timeouts
There are processing timeouts associated with each endpoint and these vary depending on the type of action being performed.
| Type | Limit |
|---|---|
| Uploads | 5 minutes |
| Standard Request | 15 seconds |
Headers
Total size of HTTP headers cannot exceed 65 KiB.
Requests per Minute
You can make a total of 50 requests per minute per user when using the Sync API. This can be further increased when commands are batched where it’s possible to use up to 100 batched commands can per request, giving us 5000 commands in this instance.
Changes
In this section we document all the changes between the two different versions of our API, in order to make it easier to upgrade your client code.
Migration guide
The new v8 Todoist API is still based on the original Todoist Sync API (as was
the case for the v6 and v7 APIs), mainly with some additions and modifications.
Here follows a list of the changes from the previous API version:
- All arguments expecting a date/time must be formatted according to RFC 3339, and all return values are also using the same format.
- All objects will now return unique ids, for this reason, some old objects will have their ids updated. For objects with new ids, we will also have an additional key called
legacy_<key>, which will contain the old id. If you have the data stored and need to find the id and update it, you can rely on these keys for the migration. Here is a breakdown of the available attributes for these old objects:- Item, Project, LiveNotification, and Note objects may have a
legacy_idattribute - Item, LiveNotification, Collaborator, and Note objects may have a
legacy_project_idattribute - LiveNotification and Note objects may have a
legacy_item_idattribute.legacy_note_idmay also be available for LiveNotification. - Item and Project objects may have a
legacy_parent_idattribute - The User object may have the
legacy_inbox_projectandlegacy_team_inboxattributes - Activity object may have the
legacy_object_id,legacy_parent_item_id, andlegacy_parent_project_idattributes
- Item, Project, LiveNotification, and Note objects may have a
- The
item_orderandindentproperties of projects, that denoted a visual hierarchy for the projects (the order of all the projects and the level of indent of each one of them), were replaced byparent_idandchild_order, which denote a real hierarchy (the parent project of a project and the order of all children of a specific parent project). - The
project_addsync command now expects aparent_idandchild_orderparameter, instead of theitem_orderandindentparameters. - The
project_updatesync command doesn’t expect anitem_orderandindentparameters anymore, but it doesn’t accept the newparent_idandchild_orderparameters as well, as the way to change the hierarchy is now different (seeproject_moveandproject_reorder). - The new
project_movesync command must be used to move a project to become the child of another project or become a root project. - The new
project_reordersync command must be used to reorder projects in relation to their siblings with the same parent. - The
project_deletesync command now expects only anidparameter, instead of theidsparameter, and it deletes the project and all the projects’s descendants. - The
project_archivesync command now expects theidparameter, instead of theidsparameter, and it archives the project and all the project’s descendants. - The
project_uncompletesync command now expects anidparameter, instead of theidsparameter, and it restores the project as a root project. - The
project_update_orders_indentssync command was removed. - The
date_string,date_lang,due_date_utcproperties of items were replaced by thedueobject (see the Due dates section for more details). - The
item_orderandindentproperties of items, that denoted a visual hierarchy for the items (the order of all the items and the level of indent of each one of them), were replaced byparent_idandchild_order, which denote a real hierarchy (the parent item of an item and the order of all children of a specific parent item). - The
is_archivedproperty of items and notes was removed as it was a duplicate ofproject.is_archived. Please rely on that property instead. - The
item_addsync command now expects aparent_idandchild_orderparameter, instead of theitem_orderandindentparameters. - The
item_addanditem_updatesync commands now expect adueparameter, instead of thedate_string,date_langand/ordue_date_utcparameters. - The
item_updatesync command doesn’t expect anitem_orderandindentparameters anymore, but it doesn’t accept the newparent_idandchild_orderparameters as well, as the way to change the hierarchy is now different (seeitem_moveanditem_reorder). - The
item_movesync command does not accept theproject_itemsandto_projectparameters, but a new set of parameters specificallyid, and one ofproject_idorparent_id. Another difference stemming from this is that only a single item can be moved at a time, and also that in order to move an item to become the child of another parent (or become a root level item) theitem_movecommand must be used as well. - The
item_update_orders_indentssync command was removed. - The new
item_reordersync command must be used to reorder items in relation to their siblings with the same parent. - The
item_deletesync command now expects only anidparameter, instead of theidsparameter, and it deletes the item and all the item’s descendants. - The
item_completesync command now expects theidparameter, instead of theidsparameter, and it completes the item and all the item’s descendants. In addition the newdate_completedparameter can also be specified. - The
item_uncompletesync command now expects anidparameter, instead of theidsparameter, and it uncompletes all the item’s ancestors. - The new
item_archivesync command can be used to move an item to history. - The new
item_unarchivesync command can be used to move an item out of history. - The
item_update_date_completesync command now expects adueparameter, instead ofnew_date_utc,date_stringand/oris_forwardparameters. - The possible color values of filters changed from
0-12to30-49. - The
date_string,date_lang,due_date_utcproperties of reminders were replaced by thedueobject (see the Due dates section for more details). - The
reminder_addandreminder_updatesync commands now expect adueparameter, instead of thedate_string,date_langand/ordue_date_utcparameters. - The sync command now returns an additional new resource type called
user_settings(see the User settings section for more details). - The user object now includes the
days_offproperty. - The
sinceanduntilparameters of theactivity/getmethod are deprecated, and are replaced by the newpageparameter. - The webhooks
event_dataproperty now returns v8 format for every resource (item, project, etc.). There’s a Webhooks version configuration available in your integration page which says which version your integration is using.v8is the default version for new integrations and will be the only one left after the deprecation date. - The URL changed from https://todoist.com/api/v7/* to https://api.todoist.com/sync/v8/*
Brand usage
Thanks for using Todoist’s API to build an application!
If you plan to utilize Todoist’s logo or branding in the visual design of your application or website, please adhere to Todoist’s brand guidelines.
In addition, please take note of the following:
- “Todoist” cannot be the first word in your application’s name. It can be used in the name of your app, though. For instance “x for Todoist” or “x with Todoist”, etc. This makes it clear that your application is created by you and not by Doist.
- You must clearly state that your application is "not created by, affiliated with, or supported by Doist” in your application description.
By using the Todoist marks you agree to properly follow the above brand guidelines as well as our Terms of Service. For further information about the use of the Todoist brand, please contact press@doist.com.