Skip to content
Niftyhelp 2026.10.2 Support

Tasks

Tasks and task lists, and the counts behind the Tasks sidebar.

On this page

List task lists

GET/task_lists

Task lists, in the owner's order.

curl "$NIFTY_URL/api/v1/task_lists" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Query parameters

NameDescription
orderposition | id | name | updated_at · optionalThe field to sort by; ties are broken by id, so the order is stable.
directionasc | desc · optionalasc (ascending) or desc (descending), for order.
updated_sincedate-time · optionalOnly records updated at or after this time (ISO 8601 with Z or a UTC offset), ordered by updated_at, id.
cursorstring · optionalmeta.next_cursor from the previous page.
limitinteger · optionalItems per page, up to 100; a larger number is taken as 100.
counttrue | false · optionaltrue adds meta.total_count: the size of the filtered set (with updated_since too), ignoring cursor and limit. Anything but true or false is a 400.

Response

200 OK Errors: 400 401 429

{
  "data": [
    {
      "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "name": "Garden",
      "color": "emerald",
      "icon": "leaf",
      "position": 1,
      "created_at": "2026-10-10T09:30:00Z",
      "updated_at": "2026-10-10T09:30:00Z"
    }
  ],
  "meta": {
    "next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
    "limit": 1,
    "total_count": 1
  }
}

Add a task list

POST/task_lists

Needs a name. Goes last unless position is sent. A blank color gets the first one no other list uses (colours and icons are those of GET /category_choices).

curl -X POST "$NIFTY_URL/api/v1/task_lists" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"task_list":{"name":"Garden","color":"emerald","icon":"leaf"}}'

Headers

NameDescription
Idempotency-Keystring · optionalMakes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth).

Request body

NameDescription
task_listobject
task_list.namestring · optionalSpaces are squished. A name another list has, ignoring case, is a 422.
task_list.colorstring or null · optionalA key from GET /category_choices. Blank picks the first one no other list uses.
task_list.iconstring or null · optionalAn icon from GET /category_choices, or null for the default list icon.
task_list.positioninteger · optional1-based; out-of-range values are clamped. Moves the list there.

Response

201 Created Errors: 400 401 403 409 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Garden",
    "color": "emerald",
    "icon": "leaf",
    "position": 1,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Get a task list

GET/task_lists/{id}

curl "$NIFTY_URL/api/v1/task_lists/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

200 OK Errors: 401 404 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Garden",
    "color": "emerald",
    "icon": "leaf",
    "position": 1,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Change or move a task list

PATCH/task_lists/{id}

Only the fields sent change. Sending position moves the list there and renumbers the live lists 1..n; the others whose position changed get a new updated_at, so re-sync with updated_since after a move. Tasks hold only task_list_id, so renaming or recolouring a list changes no task.

curl -X PATCH "$NIFTY_URL/api/v1/task_lists/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"task_list":{"name":"Garden","color":"emerald","icon":"leaf"}}'

Path parameters

NameDescription
idULIDA record's ID.

Request body

NameDescription
task_listobject
task_list.namestring · optionalSpaces are squished. A name another list has, ignoring case, is a 422.
task_list.colorstring or null · optionalA key from GET /category_choices. Blank picks the first one no other list uses.
task_list.iconstring or null · optionalAn icon from GET /category_choices, or null for the default list icon.
task_list.positioninteger · optional1-based; out-of-range values are clamped. Moves the list there.

Response

200 OK Errors: 400 401 403 404 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Garden",
    "color": "emerald",
    "icon": "leaf",
    "position": 1,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Delete a task list

DELETE/task_lists/{id}

Delete a task list and its tasks.

Restorable for 10 seconds (POST /task_lists/{id}/restore), then permanent. The list and its tasks are gone from every endpoint at once, with deletion records for the list and each of its tasks. Its name is free for a new list at once. Deleting again is a 404.

curl -X DELETE "$NIFTY_URL/api/v1/task_lists/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

204 Deleted Errors: 401 403 404 429

Restore a task list

POST/task_lists/{id}/restore

Undo deleting a task list.

Within 10 seconds of DELETE /task_lists/{id}: brings the list back with its tasks. Their deletion records are removed, and they get a new updated_at. A task deleted on its own before the list stays deleted. If another list took its name meanwhile, it comes back renamed "Name (2)", so check name. No body. Restoring a list that isn't deleted changes nothing and returns it, so a retry is safe. Once the 10 seconds have passed, or for an unknown id, it's a 404. If other lists take the name it picks twice in a row, it's a 422 on name; try again.

curl -X POST "$NIFTY_URL/api/v1/task_lists/01j9zq3k8m5x2v7c4n6b0t1r9e/restore" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Headers

NameDescription
Idempotency-Keystring · optionalMakes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth).

Response

200 Restored. The list, as GET /task_lists/{id} returns it. Errors: 400 401 403 404 409 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Garden",
    "color": "emerald",
    "icon": "leaf",
    "position": 1,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

List tasks

GET/tasks

Live tasks: not deleted, and not in a deleted list or project. Filters combine (AND); they're for browsing, so sync unfiltered. Without view or status, every status is listed. Before answering, open tasks whose expires_on has passed are archived (as every task endpoint does), so none is listed as open.

curl "$NIFTY_URL/api/v1/tasks" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Query parameters

NameDescription
statusstring · optionalComma-separated statuses, e.g. open,completed. Anything else, or with view, is 400.
viewinbox | today | upcoming | due_soon | due_not_today | today_queue | delegated | logbook · optionalA smart list, with today in the owner's time zone. Each lists only open tasks, except logbook. Combines with one home filter (inbox, task_list_id or project_id). Every view but delegated and logbook leaves delegated tasks (assignee_id set) out; inbox=true leaves them out of every view, so view=delegated&inbox=true is always empty. - inbox: in the Inbox with no start date. - today: started today or earlier (start_on ≤ today), from every home, the Inbox too. - upcoming: starting after today, from every home, the Inbox too. Ordered by start_on by default. - due_soon: overdue, or due within 14 days, from every home. Ordered by deadline_on by default. - due_not_today: due_soon without today's (no start date, or starting after today). Ordered by deadline_on by default. - today_queue: Today's queue: started (start_on ≤ today), or with no start and a deadline, however far off; one that starts after today isn't in it, even overdue. Ordered by deadline (none last) by default; Today groups them itself. - delegated: delegated to someone, from every home, the Inbox too. - logbook: completed and archived tasks, by when they closed (completed_at or archived_at, whichever is set; ordered as closed_at), newest first by default.
inboxtrue · optionaltrue: only the Inbox (tasks with no home), without its delegated tasks. Anything else is 400.
assignee_idULID · optionalOnly the tasks delegated to this person. Not a home filter, so it combines with one. An unknown or deleted person is an empty page.
task_list_idULID · optionalOnly this list's tasks. An unknown or deleted list is an empty page. At most one home filter (inbox, task_list_id, project_id); two is 400. A home filter combines with view (e.g. view=logbook&task_list_id=…, one list's Logbook).
person_idULID · optionalPeople aren't homes any more, so this is always an empty page. Counts as a home filter.
project_idULID · optionalOnly the tasks whose home is this project.
note_idULID · optionalOnly the tasks attached to this note (its inspector's Tasks). Not a home filter, so it combines with one. An unknown or deleted note is an empty page. With document_id is 400.
document_idULID · optionalOnly the tasks this document is linked to (its inspector's Tasks). Not a home filter. An unknown or deleted document is an empty page. With note_id is 400.
orderposition | created_at | updated_at | id | start_on | deadline_on | closed_at | completed_at · optionalposition (the default: the home's manual order; ties, e.g. across homes, by id), created_at, updated_at or id. view=upcoming adds start_on (its default), view=due_soon, view=due_not_today and view=today_queue deadline_on (their default; today_queue puts tasks with none last) and view=logbook closed_at (its default: completed_at or archived_at, whichever is set; not a field of its own). status=completed (alone) adds completed_at, e.g. the latest completed with direction=desc. Anything else is 400.
directionasc | desc · optionalasc by default; desc for view=logbook.
updated_sincedate-time · optionalOnly records updated at or after this time (ISO 8601 with Z or a UTC offset), ordered by updated_at, id.
cursorstring · optionalmeta.next_cursor from the previous page.
limitinteger · optionalItems per page, up to 100; a larger number is taken as 100.
counttrue | false · optionaltrue adds meta.total_count: the size of the filtered set (with updated_since too), ignoring cursor and limit. Anything but true or false is a 400.

Response

200 OK Errors: 400 401 429

{
  "data": [
    {
      "planned_start_on": "2026-10-10",
      "delays": 0,
      "deadline_moves": 0,
      "delegated_at": "2026-10-10T09:30:00Z",
      "now_since": "2026-10-10T09:30:00Z",
      "received_via_api": {
        "at": "2026-10-10T09:30:00Z",
        "source": "Zapier"
      },
      "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "title": "Book the plumber",
      "status": "open",
      "start_on": "2026-10-10",
      "deadline_on": "2026-10-10",
      "expires_on": "2026-10-10",
      "completed_at": "2026-10-10T09:30:00Z",
      "archived_at": "2026-10-10T09:30:00Z",
      "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "position": 1,
      "description_html": "<p>Ask about the boiler too.</p>",
      "description_text": "Ask about the boiler too.",
      "has_documents": true,
      "document_ids": [
        "01j9zq3k8m5x2v7c4n6b0t1r9e"
      ],
      "note_ids": [
        "01j9zq3k8m5x2v7c4n6b0t1r9e"
      ],
      "expired": true,
      "created_at": "2026-10-10T09:30:00Z",
      "updated_at": "2026-10-10T09:30:00Z"
    }
  ],
  "meta": {
    "next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
    "limit": 1,
    "total_count": 1
  }
}

Add a task

POST/tasks

Needs a title. A new task is open unless status is sent, in the Inbox unless a home id is sent, and goes to the top of its home's open tasks unless position is sent (a closed one, to the bottom). Going to the top changes no other task: its position is one less than the first's, so it may be zero or negative.

curl -X POST "$NIFTY_URL/api/v1/tasks" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"task":{"title":"Book the plumber","deadline_on":"2026-10-16","project_id":"01j9zq3p4q6r8s0t2v5w7x9y1z"}}'

Headers

NameDescription
Idempotency-Keystring · optionalMakes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth).

Request body

NameDescription
taskTaskWriteA home id that isn't an id, an unknown or deleted home, or two home ids at once (a 422 on base), are 422s. People aren't homes: person_id is ignored.
task.titlestring · optionalSpaces are squished.
task.description_htmlstring or null · optionalSee "Note bodies": mentions, tags and project references by id. An image (signed-id) is a 422 on description. Null or "" clears it.
task.start_ondate or null · optionalYYYY-MM-DD. Today (owner's zone) or earlier puts it in view=today. One that isn't a date is a 422. A later start, or clearing it, counts in delays.
task.deadline_ondate or null · optionalYYYY-MM-DD. It may be before start_on: the task will be late. A later deadline, or clearing it, counts in deadline_moves.
task.expires_ondate or null · optionalNot before start_on or deadline_on, nor, on an open task, before today (each a 422). The task stays open through that day and is archived from the next, with archived_at that midnight in the owner's zone.
task.statusTaskStatus · optionalAny status can change to any other. completed sets completed_at, archived sets archived_at, open clears both, and reopening a task whose expires_on has passed clears it. Sending the current status changes nothing.
task.task_list_idULID or null · optionalThe home. Sending one home id clears the other; both null is the Inbox.
task.project_idULID or null · optionalA record's ID.
task.assignee_idULID or null · optionalDelegates it to this person, or null to take it back. Its home stays as it is. Me, or an unknown or deleted person, is a 422 on assignee_id; one that isn't an id is a 422 too.
task.positioninteger · optional1-based among the (new) home's open tasks, its custom order; out-of-range values are clamped. Without one, a new open task goes to the top of its home, and a task moved to another home to the bottom.
task.before_task_idULID or null · optionalInstead of position (both is a 422): just before this open task in its (new) home, or null for the bottom, among every open task the home orders. One that isn't an open task there (or the task itself) is a 422.
task.document_idsULID[] or null · optionalThe task's documents after the save: the full set, linked and unlinked in the save's transaction. Omitted leaves them as they are; null or [] unlinks them all. An unknown or deleted one is a 422 on documents, and nothing saves. Not an array of ids is a 400.
task.document_uploadsstring[] or null · optionalsigned_ids of PDFs or images from POST /uploads, each becoming a document (named from its filename) linked to the task, in the save. One that isn't an unused PDF upload or PNG, JPEG or WebP image upload, or an image under POST /documents' minimum size, is a 422 on documents, and nothing saves.
task.note_idsULID[] or null · optionalThe notes it's attached to after the save: the full set, attached and detached in the save's transaction. Omitted leaves them as they are; null or [] detaches them all (a deleted note's link stays, for its undo). An unknown or deleted one is a 422 on notes, and nothing saves. Not an array of ids is a 400.

Response

201 Created Errors: 400 401 403 409 415 422 429

{
  "data": {
    "planned_start_on": "2026-10-10",
    "delays": 0,
    "deadline_moves": 0,
    "delegated_at": "2026-10-10T09:30:00Z",
    "now_since": "2026-10-10T09:30:00Z",
    "received_via_api": {
      "at": "2026-10-10T09:30:00Z",
      "source": "Zapier"
    },
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "title": "Book the plumber",
    "status": "open",
    "start_on": "2026-10-10",
    "deadline_on": "2026-10-10",
    "expires_on": "2026-10-10",
    "completed_at": "2026-10-10T09:30:00Z",
    "archived_at": "2026-10-10T09:30:00Z",
    "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "position": 1,
    "description_html": "<p>Ask about the boiler too.</p>",
    "description_text": "Ask about the boiler too.",
    "has_documents": true,
    "document_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "note_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "expired": true,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Get a task

GET/tasks/{id}

A deleted task, or one in a deleted list or project, is a 404.

curl "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

200 OK Errors: 401 404 429

{
  "data": {
    "planned_start_on": "2026-10-10",
    "delays": 0,
    "deadline_moves": 0,
    "delegated_at": "2026-10-10T09:30:00Z",
    "now_since": "2026-10-10T09:30:00Z",
    "received_via_api": {
      "at": "2026-10-10T09:30:00Z",
      "source": "Zapier"
    },
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "title": "Book the plumber",
    "status": "open",
    "start_on": "2026-10-10",
    "deadline_on": "2026-10-10",
    "expires_on": "2026-10-10",
    "completed_at": "2026-10-10T09:30:00Z",
    "archived_at": "2026-10-10T09:30:00Z",
    "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "position": 1,
    "description_html": "<p>Ask about the boiler too.</p>",
    "description_text": "Ask about the boiler too.",
    "has_documents": true,
    "document_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "note_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "expired": true,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Change a task

PATCH/tasks/{id}

Change, move, complete or reopen a task.

Only the fields sent change. Moving it to another home puts it at the bottom there unless position is sent too. Sending position moves it among its home's open tasks and renumbers them 1..n; the others whose position changed get a new updated_at, so re-sync with updated_since after a move.

curl -X PATCH "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"task":{"title":"Book the plumber","deadline_on":"2026-10-16","project_id":"01j9zq3p4q6r8s0t2v5w7x9y1z"}}'

Path parameters

NameDescription
idULIDA record's ID.

Request body

NameDescription
taskTaskWriteA home id that isn't an id, an unknown or deleted home, or two home ids at once (a 422 on base), are 422s. People aren't homes: person_id is ignored.
task.titlestring · optionalSpaces are squished.
task.description_htmlstring or null · optionalSee "Note bodies": mentions, tags and project references by id. An image (signed-id) is a 422 on description. Null or "" clears it.
task.start_ondate or null · optionalYYYY-MM-DD. Today (owner's zone) or earlier puts it in view=today. One that isn't a date is a 422. A later start, or clearing it, counts in delays.
task.deadline_ondate or null · optionalYYYY-MM-DD. It may be before start_on: the task will be late. A later deadline, or clearing it, counts in deadline_moves.
task.expires_ondate or null · optionalNot before start_on or deadline_on, nor, on an open task, before today (each a 422). The task stays open through that day and is archived from the next, with archived_at that midnight in the owner's zone.
task.statusTaskStatus · optionalAny status can change to any other. completed sets completed_at, archived sets archived_at, open clears both, and reopening a task whose expires_on has passed clears it. Sending the current status changes nothing.
task.task_list_idULID or null · optionalThe home. Sending one home id clears the other; both null is the Inbox.
task.project_idULID or null · optionalA record's ID.
task.assignee_idULID or null · optionalDelegates it to this person, or null to take it back. Its home stays as it is. Me, or an unknown or deleted person, is a 422 on assignee_id; one that isn't an id is a 422 too.
task.positioninteger · optional1-based among the (new) home's open tasks, its custom order; out-of-range values are clamped. Without one, a new open task goes to the top of its home, and a task moved to another home to the bottom.
task.before_task_idULID or null · optionalInstead of position (both is a 422): just before this open task in its (new) home, or null for the bottom, among every open task the home orders. One that isn't an open task there (or the task itself) is a 422.
task.document_idsULID[] or null · optionalThe task's documents after the save: the full set, linked and unlinked in the save's transaction. Omitted leaves them as they are; null or [] unlinks them all. An unknown or deleted one is a 422 on documents, and nothing saves. Not an array of ids is a 400.
task.document_uploadsstring[] or null · optionalsigned_ids of PDFs or images from POST /uploads, each becoming a document (named from its filename) linked to the task, in the save. One that isn't an unused PDF upload or PNG, JPEG or WebP image upload, or an image under POST /documents' minimum size, is a 422 on documents, and nothing saves.
task.note_idsULID[] or null · optionalThe notes it's attached to after the save: the full set, attached and detached in the save's transaction. Omitted leaves them as they are; null or [] detaches them all (a deleted note's link stays, for its undo). An unknown or deleted one is a 422 on notes, and nothing saves. Not an array of ids is a 400.

Response

200 OK Errors: 400 401 403 404 415 422 429

{
  "data": {
    "planned_start_on": "2026-10-10",
    "delays": 0,
    "deadline_moves": 0,
    "delegated_at": "2026-10-10T09:30:00Z",
    "now_since": "2026-10-10T09:30:00Z",
    "received_via_api": {
      "at": "2026-10-10T09:30:00Z",
      "source": "Zapier"
    },
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "title": "Book the plumber",
    "status": "open",
    "start_on": "2026-10-10",
    "deadline_on": "2026-10-10",
    "expires_on": "2026-10-10",
    "completed_at": "2026-10-10T09:30:00Z",
    "archived_at": "2026-10-10T09:30:00Z",
    "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "position": 1,
    "description_html": "<p>Ask about the boiler too.</p>",
    "description_text": "Ask about the boiler too.",
    "has_documents": true,
    "document_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "note_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "expired": true,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Delete a task

DELETE/tasks/{id}

Restorable for 10 seconds (POST /tasks/{id}/restore), then permanent. Writes a task deletion record at once. Deleting again is a 404.

curl -X DELETE "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

204 Deleted Errors: 401 403 404 429

Restore a task

POST/tasks/{id}/restore

Undo deleting a task.

Within 10 seconds of DELETE /tasks/{id}: brings the task back, removes its deletion record and gives it a new updated_at. No body. Restoring a task that isn't deleted changes nothing and returns it, so a retry is safe. Once the 10 seconds have passed, for an unknown id, or while its list, person or project is deleted (restore that instead), it's a 404. If its expiry passed meanwhile, it comes back archived.

curl -X POST "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e/restore" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Headers

NameDescription
Idempotency-Keystring · optionalMakes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth).

Response

200 Restored. The task, as GET /tasks/{id} returns it. Errors: 400 401 403 404 409 415 429

{
  "data": {
    "planned_start_on": "2026-10-10",
    "delays": 0,
    "deadline_moves": 0,
    "delegated_at": "2026-10-10T09:30:00Z",
    "now_since": "2026-10-10T09:30:00Z",
    "received_via_api": {
      "at": "2026-10-10T09:30:00Z",
      "source": "Zapier"
    },
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "title": "Book the plumber",
    "status": "open",
    "start_on": "2026-10-10",
    "deadline_on": "2026-10-10",
    "expires_on": "2026-10-10",
    "completed_at": "2026-10-10T09:30:00Z",
    "archived_at": "2026-10-10T09:30:00Z",
    "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "position": 1,
    "description_html": "<p>Ask about the boiler too.</p>",
    "description_text": "Ask about the boiler too.",
    "has_documents": true,
    "document_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "note_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "expired": true,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Get a task's date history

GET/tasks/{id}/history

The changes to a task's start and deadline, newest first, and how often it's been worked on as Now.

A change within ten minutes of the task's creation isn't kept. One within ten minutes of an entry's first time merges into that entry, which keeps its from; one that undoes it removes it. Not synced: read it when it's shown. A deleted task is a 404.

curl "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e/history" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Query parameters

NameDescription
cursorstring · optionalmeta.next_cursor from the previous page.
limitinteger · optionalItems per page, up to 100; a larger number is taken as 100.

Response

200 OK Errors: 400 401 404 429

{
  "data": [
    {
      "id": 1,
      "at": "2026-10-10T09:30:00Z",
      "start_changed": true,
      "start_from": "2026-10-10",
      "start_to": "2026-10-10",
      "deadline_changed": true,
      "deadline_from": "2026-10-10",
      "deadline_to": "2026-10-10",
      "delay": true,
      "deadline_moved": true
    }
  ],
  "meta": {
    "next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
    "limit": 1,
    "total_count": 1,
    "sessions": 0,
    "first_session_at": "2026-10-10T09:30:00Z"
  }
}

Work on a task now

PUT/tasks/{id}/now

Makes the task Now, ending any other task's session; both get a new updated_at. A task that starts after today has its start_on moved to today (an earlier start, so not a delay; task.start_changed fires). No body. Starting the task that's already Now changes nothing and returns it. A closed or delegated task is a 422 on base; a deleted one is a 404.

curl -X PUT "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e/now" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

200 Started. The task, as GET /tasks/{id} returns it. Errors: 401 403 404 415 422 429

{
  "data": {
    "planned_start_on": "2026-10-10",
    "delays": 0,
    "deadline_moves": 0,
    "delegated_at": "2026-10-10T09:30:00Z",
    "now_since": "2026-10-10T09:30:00Z",
    "received_via_api": {
      "at": "2026-10-10T09:30:00Z",
      "source": "Zapier"
    },
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "title": "Book the plumber",
    "status": "open",
    "start_on": "2026-10-10",
    "deadline_on": "2026-10-10",
    "expires_on": "2026-10-10",
    "completed_at": "2026-10-10T09:30:00Z",
    "archived_at": "2026-10-10T09:30:00Z",
    "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "position": 1,
    "description_html": "<p>Ask about the boiler too.</p>",
    "description_text": "Ask about the boiler too.",
    "has_documents": true,
    "document_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "note_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "expired": true,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Stop working on a task

DELETE/tasks/{id}/now

Ends the task's session, so nothing is Now; it gets a new updated_at. Stopping a task that isn't Now changes nothing and returns it. Completing, closing, deleting, delegating or delaying the task, deleting its home, its expiry and the stop times (GET /task_settings) end it too. A deleted task is a 404.

curl -X DELETE "$NIFTY_URL/api/v1/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e/now" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Path parameters

NameDescription
idULIDA record's ID.

Response

200 Stopped. The task, as GET /tasks/{id} returns it. Errors: 401 403 404 429

{
  "data": {
    "planned_start_on": "2026-10-10",
    "delays": 0,
    "deadline_moves": 0,
    "delegated_at": "2026-10-10T09:30:00Z",
    "now_since": "2026-10-10T09:30:00Z",
    "received_via_api": {
      "at": "2026-10-10T09:30:00Z",
      "source": "Zapier"
    },
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "title": "Book the plumber",
    "status": "open",
    "start_on": "2026-10-10",
    "deadline_on": "2026-10-10",
    "expires_on": "2026-10-10",
    "completed_at": "2026-10-10T09:30:00Z",
    "archived_at": "2026-10-10T09:30:00Z",
    "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "position": 1,
    "description_html": "<p>Ask about the boiler too.</p>",
    "description_text": "Ask about the boiler too.",
    "has_documents": true,
    "document_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "note_ids": [
      "01j9zq3k8m5x2v7c4n6b0t1r9e"
    ],
    "expired": true,
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Get the task that's Now

GET/now

The task the owner is working on (PUT /tasks/{id}/now), or null. A session still running at a stop time (GET /task_settings) ends at that time, when this or any task read next runs. stops_at is when it will stop by itself: the next stop time or the end of its expiry day, whichever comes first; read it again then.

curl "$NIFTY_URL/api/v1/now" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Response

200 OK Errors: 401 429

{
  "data": {
    "task": {
      "planned_start_on": "2026-10-10",
      "delays": 0,
      "deadline_moves": 0,
      "delegated_at": "2026-10-10T09:30:00Z",
      "now_since": "2026-10-10T09:30:00Z",
      "received_via_api": {
        "at": "2026-10-10T09:30:00Z",
        "source": "Zapier"
      },
      "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "title": "Book the plumber",
      "status": "open",
      "start_on": "2026-10-10",
      "deadline_on": "2026-10-10",
      "expires_on": "2026-10-10",
      "completed_at": "2026-10-10T09:30:00Z",
      "archived_at": "2026-10-10T09:30:00Z",
      "task_list_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "assignee_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "position": 1,
      "description_html": "<p>Ask about the boiler too.</p>",
      "description_text": "Ask about the boiler too.",
      "has_documents": true,
      "document_ids": [
        "01j9zq3k8m5x2v7c4n6b0t1r9e"
      ],
      "note_ids": [
        "01j9zq3k8m5x2v7c4n6b0t1r9e"
      ],
      "expired": true,
      "created_at": "2026-10-10T09:30:00Z",
      "updated_at": "2026-10-10T09:30:00Z"
    },
    "since": "2026-10-10T09:30:00Z",
    "stops_at": "2026-10-10T09:30:00Z"
  }
}

Get the task settings

GET/task_settings

The times of day at which Now stops by itself. One resource; there's no collection.

curl "$NIFTY_URL/api/v1/task_settings" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Response

200 OK Errors: 401 429

{
  "data": {
    "now_stop_times": [
      "18:00"
    ]
  }
}

Change the task settings

PATCH/task_settings

Only the fields sent change. now_stop_times replaces the list: a time that's added applies from now, so it never ends a session at a moment before it was added.

curl -X PATCH "$NIFTY_URL/api/v1/task_settings" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"task_settings":{"now_stop_times":["08:00","18:00"]}}'

Request body

NameDescription
task_settingsobject
task_settings.now_stop_timesNowStopTimes · optionalTimes of day (HH:MM, the owner's time zone) at which Now stops by itself, earliest first. No duplicates (a 422).

Response

200 OK Errors: 400 401 403 415 422 429

{
  "data": {
    "now_stop_times": [
      "18:00"
    ]
  }
}

Task counts per list

GET/task_counts

How many open tasks are in the Inbox, Today, due soon, overdue and each list; and one page's counts.

Live, open tasks, with today in the owner's time zone; each count except overdue matches its GET /tasks listing. Expired tasks are archived first. Not a record: there's nothing to sync, so ask again when tasks change.

Name a page with view, or one home (inbox, task_list_id or project_id), to get its counts in page. view=logbook may also name one home. An unknown or hidden home counts zeros.

curl "$NIFTY_URL/api/v1/task_counts" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Query parameters

NameDescription
viewinbox | today | upcoming | logbook · optionalA Tasks page. Anything else, or any but logbook with a home, is 400.
inboxtrue · optionaltrue: the Inbox's page. Anything else is 400. At most one home; two is 400.
task_list_idULID · optionalA list's page. Not an id is 400.
person_idULID · optionalPeople aren't homes any more, so this counts zeros.
project_idULID · optionalA project's Tasks.

Response

200 OK Errors: 400 401 429

{
  "data": {
    "inbox": 1,
    "today": 1,
    "today_queue": 1,
    "due_soon": 1,
    "overdue": 1,
    "delegated": 1,
    "task_lists": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "open": 1
      }
    ],
    "page": {
      "open": 1,
      "completed": 1,
      "completed_today": 1,
      "overdue": 1,
      "wont_do": 1,
      "expired": 1
    }
  }
}

Task counts per project

GET/project_task_counts

Each project's open and completed tasks, and its next task.

Live tasks of live projects, by project_id; a project with none is left out (archived tasks aren't counted). next_task is the open task to do next: started ones (no start_on, or today or earlier in the owner's time zone) first, then by deadline_on (none last), position and id; null when none is open. Expired tasks are archived first. Not paginated, and not a record: ask again when tasks change.

curl "$NIFTY_URL/api/v1/project_task_counts" \
  -H "Authorization: Bearer $NIFTY_TOKEN"

Response

200 OK Errors: 401 429

{
  "data": [
    {
      "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "open": 1,
      "completed": 1,
      "next_task": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "string",
        "start_on": "2026-10-10",
        "deadline_on": "2026-10-10"
      }
    }
  ]
}

Menu

2026.10.2Contact support