Each API request should be authenticated using HTTP Basic Auth. The user's API key acts as the username, and the password can be left blank.

Example request $ curl \ -u myapikey:

curl uses the -u flag for basic auth credentials. Adding a colon after the API key will prevent it from asking for a password


Along with a normal REST request, there are certain extra parameters you can include which will affect the type of response you receive back.

The modifiers are made distinct from the normal request parameters by beginning with an underscore (e.g. _expand). The available modifiers are described below.

These are one of the most experimental parts of the API, so if you are making use of these, it's probably worth checking back here occasionally to see if anything has changed.

Pretty formatting

By default, the JSON response won't include any excess whitespace (to save bytes), but by passing in the _pretty=true parameter, responses can be neatly formatted (like the examples in this documentation).

Example GET request $ curl "" \ -u myapikey: Example PATCH request $ curl \ -u myapikey: \ -d archived=true \ -d _pretty=true \ -X PATCH

When performing GET requests, extra parameters should be included in the query string. But with POST/PATCH requests, they can be included along with the main data. Parameters beginning with an underscore will be recognised as request modifiers, rather than properties of the object.

Expanding objects

By default, most types of nested objects will simply return the ID of that object. To see the fully serialized version of that object nested in the response, include the key for that object (or array of objects) in the _expand array.

For example, a todo object has a node property, which will normally just be an ID reference to the relevant node, but can be turned into a full object representation by adding node to the _expand array.

As a shortcut, you can pass all as a value to make every type of nested object expand.

Example request $ curl[]=node \ -u myapikey: Example response { "id": 100, "list": "later", "node": { "id": 100, "type": "Step", "name": "Morning run", "status": null, "ordinal": 1024, "streak": 5, "frequency": 2, "nextDue": "2014-01-28T12:40:00+00:00", "overdue": false, "dueAnyTime": false, "hasActions": false, "actions": [ ] } }

Hiding defaults

The _hideDefaults parameter can come in handy if you're finding responses needlessly verbose, or you're working with large datasets and want to cut down on the amount of bytes to be received.

Certain properties of objects which have obvious default values can be hidden from responses by passing _hideDefaults=true along with your request. The default values that you should assume are listed in this reference alongside properties which support this modifier.

Example request $ curl \ -u myapikey: Example response { "id": 100, "list": "next", "node": 100 }

All modifiers

Full reference of available modifiers:

_pretty boolean false See above.
_expand array(string) [] See above.
_hideDefaults boolean false See above.
_depth integer / string 1 The number of nested levels that can be reached in the response before it becomes automatically truncated. Specify an integer value, or all for no limit.
_deepExpand boolean false The _expand options will normally only apply to the highest level object in the response, but with this set to true, it will apply to all objects in the response (up to the specified depth).
_includeArchived boolean false Whether archived nodes should be included in the response.
_includeArchivedChildren boolean false Same as above, except only applies to nodes below the very top-level object of the response.


Nodes represent Steps, Goals or the Inbox -- as seen on the Goal Map. Nodes of type Goal or Step have certain unique fields which only apply to that type of node (the list below is segmented to reflect this). With the Inbox node, the vast majority of these fields are irrelevant and can't be changed, as the Inbox offers very little customisation.

id integer
type string Either Goal, Step, or Inbox.
name string
active boolean False if the node, or any of its parent nodes, are archived or paused. For example, if this node is a step, and the user archived the parent goal, then active=false, and the step shouldn't appear on to-do lists etc. read-only
status string? completed, failed, or null if the step/goal is still on-going. For steps, this value is read-only, but for goals, you can complete or fail a goal by submitting one of the listed codes (this is just a shortcut for setting completedAt or failedAt manually).
ordinal double A number which represents the position of a non-archived node amongst its list of neighbours. This is a double-precision floating point, so can be a decimal with many digits of precision. The method we use to calculate these on the client-side when creating new nodes is: if it's the last node in the list, add 2^14 to the ordinal value of the node above. Or, if it's being placed before another node, give it an ordinal half way between ordinal value appearing above and below it. (Note: we've switched to this from the previous method of using a 0-indexed list of integers as it means we can insert a node into a list without having to inefficiently change the ordinal of every single node below).
privacy string? null null for private (default), or public to make a goal publicly accessible at{user.username}/{} (currently only for goals).
archived boolean Whether the user has marked this node as archived, meaning they want it and its children to disappear from their goal map.
coverPhoto string? null ID of the attachment image which is set as the cover photo, or null for no cover photo. Note that the attachment must belong to a note which belongs to this node. This can be set for any type of node, but we recommend only allowing it for Goals for consistency with the web-app.
coverPhotoPath string? null If the node has a cover photo, full path to the cover photo image file. read-only
parent integer? null The ID of the parent node, or null if this node is top-level. You can change a node's parent by giving this a new value. Note that it's more usual to traverse downwards through the children, than upwards through the parents, so this field should be used only in special cases. Also note that there's currently a _parentId field in the API response holding the same information - please ignore that field as it will soon be removed.
fileCount integer Number of file attachments contained within notes. Will currently always show 0 as non-image file attachments aren't yet supported. read-only
imageCount integer Number of image attachments contained within notes. read-only
children array(integer / object) [] Child nodes in the node hierarchy. Only a property of Goal and Inbox type nodes. Step nodes can't have children. read-only expandable
notes array(integer / object) []
read-only expandable
Goal only  
paused boolean false Whether the user has marked this goal as paused in the Goal Map.
due date? null
completedAt date? null If the goal has been completed (as reflected by the status), the date when it was completed.
failedAt date? null If the goal has been failed (as reflected by the status), the date when it was failed.
trackers array []
category integer? null ID of the assigned category, or null. Categories cannot be expanded - you should just fetch the list of all categories. This field should be ignored if the current goal isn't at the top-level.
Step only  
streak integer? If the step is repeating, number of consecutive completed actions. read-only
habit boolean false Is this step a habit?
dailyScore integer? If the step is a habit, the current positive or negative score for today read-only
frequency integer? null If the step is "repeat every X days", what is X? A frequency of 0 can be used to signify "sporadic" repeating.
skipWeekends boolean false If the step is "repeat every X days", should weekends be ignored as a potential due date?
weeklySchedule integer? null If the step repeats on a weekly schedule, which days are selected? Represented with a bit mask from Monday-Sunday. E.g. 0b0100100 (36 in decimal) is Tuesday and Friday.
pushWhenMissed boolean false If the step repeats and a scheduled day is missed, should the due date automatically be pushed back to the next due date (carried out by the server)?
nextDue datetime? null
overdue boolean
dueAnyTime boolean? null If true, the time segment of the step's due date will be ignored, and will just represent the day which the step is due. Set to null when the step has no nextDue value.
reminderNotice integer? null If non-null, specifies the number of minutes before the due time which an email reminder will be sent by the server. Set to null when the step has no nextDue value.
smsReminderNotice integer? null If non-null, specifies the number of minutes before the due time which an SMS reminder will be sent by the server. Set to null when the step has no nextDue value.
hiddenActionButton string? null For habits, which of the action buttons should be hidden? completed for the +, failed for the -, or null for neither.
actionCount integer
actions array(integer / object) [] The history of actions for the step (which show past completions/misses/failures etc). read-only expandable
Example step object { "id": 108, "type": "Step", "name": "Go to the gym", "active": true, "status": null, "ordinal": 1024, "privacy": null, "archived": false, "coverPhoto": null, "coverPhotoPath": null, "streak": 2, "dailyScore": null, "habit": false, "frequency": 2, "skipWeekends": false, "weeklySchedule": null, "pushWhenMissed": false, "nextDue": "2014-07-05T23:59:59+01:00", "overdue": false, "dueAnyTime": true, "reminderNotice": null, "smsReminderNotice": null, "hiddenActionButton": null, "hasActions": true, "actionCount": 2, "actions": [ { "id": 1147, "result": "completed", "performedAt": "2014-07-01T00:00:00+00:00" }, { "id": 1164, "result": "completed", "performedAt": "2014-07-03T00:00:00+00:00" } ], "fileCount": 0, "imageCount": 0, "notes": [ { "id": 710, "content": "Had to start taking a break due to wrist pain", "updatedAt": "2014-07-03T21:49:36+01:00", "recordedAt": "2014-06-17T21:50:41+01:00" } ] }

Create a top-level node

By not specifying a parent node ID, a new node can be added at the top-level of the goal map.

Required parameters:

Definition POST{USERNAME}/nodes Example request $ curl \ -u myapikey: \ -d type=Goal \ -d "name=Learn to read Chinese" \ -d ordinal=1024

Create a child node

Supply a parent node ID along with the POST data to set this node as a child to another.

Required parameters:

Definition POST{USERNAME}/nodes Example request $ curl \ -u myapikey: \ -d type=Step \ -d "name=Buy some new shoes" \ -d parent=1050

Retrieve a node

This is a good way to request everything needed for the detailed standalone view of a node (remember to expand the properties you're interested in).

Definition GET{NODE_ID} Example request $ curl \ -u myapikey:

Update a node

Currently works with either PATCH or POST, but PATCH is more semantically correct when only updating a subset of properties.

Definition PATCH{NODE_ID} Example request $ curl \ -u myapikey: \ -d "nextDue=2014-07-06T17:15:00+00:00" \ -x PATCH

List all nodes

Retrieves all active top-level nodes. This is a good way to fetch the entire of the Goal Map when an app is first loaded.

Definition GET{USERNAME}/nodes Example request $ curl \ -u myapikey:

Delete a node

Be careful with this as it's irreversible, and deletes all child nodes, and attached notes, trackers, etc.

Definition DELETE{NODE_ID} Example request $ curl \ -u myapikey: \ -X DELETE Example response []


To-dos are managed automatically by the server, and have a 1:1 relationship with steps that should appear on the to-do list (are active, etc.). So you'll never need to create a to-do object, but marking to-dos as completed is most easily done through this object interface (which manages the Action objects behind the scenes).

The node property is expandable, if you want the full node object instead of just the object ID.

id integer Same as the node's ID read-only
list string? Which section of the to-do list should it appear on - habit, overdue, later (later this week), or next (next steps). Note that steps which have a due date that doesn't fall within the next week don't feature on any sublists so will have a value of null. read-only
status string? Current status of the to-do, calculated based on whether an action exists for today. Either null, completed, or failed. Actions for today can be controlled by updating this value (read next sections).
node integer / object The step which corresponds to the to-do. read-only expandable
Example object { "id": 100, "list": "today", "node": 100 }

Complete a to-do

By passing in the status parameter as completed, the to-do will be marked as completed, and a completion action for today will be created by the server. The failed status can also be used for marking to-dos as failed.

Definition PATCH{TODO_ID} Example request $ curl \ -u myapikey: \ -d status=completed \ -X PATCH Example response { "id": 100, "list": "today", "status": "completed", "node": 100 }

Uncomplete a to-do

Send a status of null to mark a to-do as uncompleted, and remove today's action.

Definition PATCH{TODO_ID} Example request $ curl \ -u myapikey: \ -d status=null \ -X PATCH Example response { "id": 100, "list": "today", "node": 100 }

List all to-dos

This list is in the correct order in which the to-dos should be presented to the user. This is worth doing to fetch a fresh to-do list after any changes are made to due dates / activity states etc (unless you're managing the order yourself), as the order of the todos in the list may well have changed.

Definition GET{USERNAME}/todos Example request $ curl Example response [ { "id": 100, "list": "today", "status": "completed", "node": 100 }, { "id": 82, "list": "later", "node": 82 }, ]


Notes can either belong to a node object (in which case they appear on the node's detail page), or to a user object (in which case they appear in the History section under a certain date).

id integer
content string Plaintext representation of the user's note content. Whitespace should be preserved, along with linebreaks (\n). See here for a full list of formatting options that the web-app supports.
archived boolean false
pinned boolean false Only notes associated with a node should be pinned.
recordedAt datetime Where on the timeline this should appear.
updatedAt datetime
attachments array(object) []
read-only expandable
Example object { "id": 10, "content": "Go live checklist:\n\n- [x] Push changes\n- [ ] Run tests\n- [ ] Mailing list", "archived": false, "pinned": false, "recordedAt": "2014-09-01T16:57:00+01:00", "updatedAt": "2013-09-02T17:30:25+01:00", "attachments": [ ] }

Create a node note

If no recordedAt value is provided, defaults to the current date/time

Required parameters:

Definition POST{NODE_ID}/notes Example request $ curl \ -u myapikey: \ -d $'content=This is a new note.\nWith a linebreak'

Create a user note

If no recordedAt value is provided, defaults to the current date/time

Required parameters:

Definition POST{USERNAME}/notes Example request $ curl \ -u myapikey: \ -d $'content=This is a new note.\nWith a linebreak' \ -d "recordedAt=2014-09-01T17:15:00+00:00"

Retrieve a note

Definition GET{NOTE_ID} Example request $ curl \ -u myapikey:


id integer
name string
archived boolean false
limitedDaily boolean Should the tracker be limited to one reading per day? Recommended to use true when possible.
current decimal? Current value (based on most recent Measure). read-only
unit string? null Identifier of the unit type being used (if it's one of the predefined types). Current types: CurrencyGBP, CurrencyUSD, Second. The point of these types is to provide smarter formatting than a simple suffix string.
customUnit string? null User specific custom unit which can be appended to their tracker readings when they need to be displayed neatly. E.g. kg.
cumulative boolean false
targets array(integer / object) []
read-only expandable
measureToday boolean Do any of the tracker's readings have a date of today? read-only
measures array(integer / object) []
read-only expandable
Example object { "id": 20, "name": "Bodyweight", "archived": false, "limitedDaily": true, "current": 78.5, "unit": null, "customUnit": "kg", "cumulative": false, "targets": [ 10, 340 ], "measureToday": true, "measures": [ 3240, 3241, 4080, 4100, ] }


A measure is a reading for a tracker.

id integer
value decimal Values are always stored as decimals. The type of unit is stored in the tracker object, which may give a clue on how it should be formatted. E.g. a tracker with a unit of "Time (seconds)" (Second) should display the reading value 100 as 1:40.
recordedAt datetime The timestamp of when the user performed this action. You can set this as something different from the current date/time, e.g. if the user is filling in past data.
Example object { "id": 2200, "value": 68.5, "recordedAt": "2014-05-20T14:34:04+00:00" }

Create a new measure

If no recordedAt value is provided, defaults to the current date/time

Required parameters:

Definition POST{TRACKER_ID}/measures Example request $ curl \ -u myapikey: \ -d value=68 Example response { "id": 5210, "value": 68, "recordedAt": "2014-09-01T14:34:04+00:00" }

Update a measure

Definition PATCH{MEASURE_ID} Example request $ curl \ -u myapikey: \ -d value=70 \ -X PATCH Example response { "id": 2200, "value": 70, "recordedAt": "2014-05-20T14:34:04+00:00" }

Delete a measure

Definition DELETE{MEASURE_ID} Example request $ curl \ -u myapikey: \ -X DELETE Example response []