Authentication
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 https://nachapp.com/api/users/JohnDoe \
-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
Modifiers
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 "https://nachapp.com/api/nodes/100?_pretty=true" \
-u myapikey:
Example PATCH request
$ curl https://nachapp.com/api/nodes/100 \
-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 https://nachapp.com/api/todos/100?_expand[]=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 https://nachapp.com/api/todos/100?_hideDefaults=true \
-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
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
read-only
|
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 http://nach.me/u/{user.username}/{node.id} (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 []
read-only
|
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
read-only
|
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
read-only
|
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 https://nachapp.com/api/users/{USERNAME}/nodes
Example request
$ curl https://nachapp.com/api/users/JohnDoe/nodes \
-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 https://nachapp.com/api/users/{USERNAME}/nodes
Example request
$ curl https://nachapp.com/api/users/JohnDoe/nodes \
-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 https://nachapp.com/api/nodes/{NODE_ID}
Example request
$ curl https://nachapp.com/api/nodes/100 \
-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 https://nachapp.com/api/nodes/{NODE_ID}
Example request
$ curl https://nachapp.com/api/nodes/1050 \
-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 https://nachapp.com/api/users/{USERNAME}/nodes
Example request
$ curl https://nachapp.com/api/users/JohnDoe/nodes \
-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 https://nachapp.com/api/nodes/{NODE_ID}
Example request
$ curl https://nachapp.com/api/nodes/1050 \
-u myapikey: \
-X DELETE
Example response
[]
To-dos
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 https://nachapp.com/api/todos/{TODO_ID}
Example request
$ curl https://nachapp.com/api/todos/100 \
-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 https://nachapp.com/api/todos/{TODO_ID}
Example request
$ curl https://nachapp.com/api/todos/100 \
-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 https://nachapp.com/api/users/{USERNAME}/todos
Example request
$ curl https://nachapp.com/api/users/JohnDoe/todos
Example response
[
{
"id": 100,
"list": "today",
"status": "completed",
"node": 100
},
{
"id": 82,
"list": "later",
"node": 82
},
]
Notes
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
read-only
|
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
read-only
|
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 https://nachapp.com/api/nodes/{NODE_ID}/notes
Example request
$ curl https://nachapp.com/api/nodes/100/notes \
-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 https://nachapp.com/api/users/{USERNAME}/notes
Example request
$ curl https://nachapp.com/api/users/JohnDoe/notes \
-u myapikey: \
-d $'content=This is a new note.\nWith a linebreak' \
-d "recordedAt=2014-09-01T17:15:00+00:00"
Definition
GET https://nachapp.com/api/notes/{NOTE_ID}
Example request
$ curl https://nachapp.com/api/notes/100 \
-u myapikey:
Trackers
id |
integer
read-only
|
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,
]
}
Measures
A measure is a reading for a tracker.
id |
integer
read-only
|
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 https://nachapp.com/api/trackers/{TRACKER_ID}/measures
Example request
$ curl https://nachapp.com/api/trackers/100/measures \
-u myapikey: \
-d value=68
Example response
{
"id": 5210,
"value": 68,
"recordedAt": "2014-09-01T14:34:04+00:00"
}
Definition
PATCH https://nachapp.com/api/measures/{MEASURE_ID}
Example request
$ curl https://nachapp.com/api/measures/2200 \
-u myapikey: \
-d value=70 \
-X PATCH
Example response
{
"id": 2200,
"value": 70,
"recordedAt": "2014-05-20T14:34:04+00:00"
}
Definition
DELETE https://nachapp.com/api/measures/{MEASURE_ID}
Example request
$ curl https://nachapp.com/api/measures/2200 \
-u myapikey: \
-X DELETE
Example response
[]