Skip to content
Niftyhelp 2026.10.1-beta.1 Support

Beta This is the help for Nifty 2026.10.1-beta.1, which isn't released yet. Help for the current release

Projects

Projects, their timeline and their deadlines.

On this page

List projects

GET/projects

Projects, with their members.

Filters combine (AND). Filters are for browsing; sync unfiltered.

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

Query parameters

NameDescription
ordername | created_at | updated_at | id · optionalThe field to sort by; ties are broken by id, so the order is stable.
directionasc | desc · optionalasc (ascending) or desc (descending), for order.
statusstring · optionalComma-separated statuses, e.g. active,on_hold. Anything else is 400.
person_idULID · optionalOnly projects this person is a member of. An unknown or deleted person is an empty page.
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": "Kitchen renovation",
      "status": "planned",
      "status_changed_at": "2026-10-10T09:30:00Z",
      "start_date": "2026-10-10",
      "deadline": "2026-10-10",
      "my_role": "Organiser",
      "external_reference": "JIRA-123",
      "external_url": "https://example.com",
      "description_html": "<p>New units and worktops.</p>",
      "description_text": "New units and worktops.",
      "members": [
        {
          "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
          "role": "string"
        }
      ],
      "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 project

POST/projects

Needs a name. A new project is active unless status says otherwise. Add members with POST /project_members.

curl -X POST "$NIFTY_URL/api/v1/projects" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project":{"name":"Kitchen renovation","status":"active","start_date":"2026-09-01","deadline":"2026-12-18","my_role":"Organiser"}}'

Headers

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

Request body

NameDescription
projectProjectWrite
project.namestring · optionalSpaces are squished. A name another project has, ignoring case, is a 422.
project.statusProjectStatus · optionalplanned, active and on_hold are open; done and cancelled are closed.
project.start_datedate or null · optionalYYYY-MM-DD. One that isn't a date is a 422.
project.deadlinedate or null · optionalYYYY-MM-DD; not before start_date (a 422).
project.my_rolestring or null · optionalSpaces are squished; blank is null.
project.external_referencestring or null · optionalSpaces are squished; blank is null.
project.external_urlstring or null · optionalhttp or https, with a host; without a scheme, https:// is added. Blank is null.
project.description_htmlstring or null · optionalHTML, sanitised as note bodies are. Attachments and images are dropped. A NUL or more than 1 MB is a 422. Null or "" clears it.

Response

201 Created Errors: 400 401 403 409 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Kitchen renovation",
    "status": "planned",
    "status_changed_at": "2026-10-10T09:30:00Z",
    "start_date": "2026-10-10",
    "deadline": "2026-10-10",
    "my_role": "Organiser",
    "external_reference": "JIRA-123",
    "external_url": "https://example.com",
    "description_html": "<p>New units and worktops.</p>",
    "description_text": "New units and worktops.",
    "members": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "role": "string"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Get a project

GET/projects/{id}

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

Path parameters

NameDescription
idULIDA record's ID.

Response

200 OK Errors: 401 404 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Kitchen renovation",
    "status": "planned",
    "status_changed_at": "2026-10-10T09:30:00Z",
    "start_date": "2026-10-10",
    "deadline": "2026-10-10",
    "my_role": "Organiser",
    "external_reference": "JIRA-123",
    "external_url": "https://example.com",
    "description_html": "<p>New units and worktops.</p>",
    "description_text": "New units and worktops.",
    "members": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "role": "string"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Change a project

PATCH/projects/{id}

Also PUT /projects/{id}, the same.

Only the fields sent change. Renaming it gives the notes referencing it a new updated_at (their body_text changes).

curl -X PATCH "$NIFTY_URL/api/v1/projects/01j9zq3k8m5x2v7c4n6b0t1r9e" \
  -H "Authorization: Bearer $NIFTY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"project":{"name":"Kitchen renovation","status":"active","start_date":"2026-09-01","deadline":"2026-12-18","my_role":"Organiser"}}'

Path parameters

NameDescription
idULIDA record's ID.

Request body

NameDescription
projectProjectWrite
project.namestring · optionalSpaces are squished. A name another project has, ignoring case, is a 422.
project.statusProjectStatus · optionalplanned, active and on_hold are open; done and cancelled are closed.
project.start_datedate or null · optionalYYYY-MM-DD. One that isn't a date is a 422.
project.deadlinedate or null · optionalYYYY-MM-DD; not before start_date (a 422).
project.my_rolestring or null · optionalSpaces are squished; blank is null.
project.external_referencestring or null · optionalSpaces are squished; blank is null.
project.external_urlstring or null · optionalhttp or https, with a host; without a scheme, https:// is added. Blank is null.
project.description_htmlstring or null · optionalHTML, sanitised as note bodies are. Attachments and images are dropped. A NUL or more than 1 MB is a 422. Null or "" clears it.

Response

200 OK Errors: 400 401 403 404 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Kitchen renovation",
    "status": "planned",
    "status_changed_at": "2026-10-10T09:30:00Z",
    "start_date": "2026-10-10",
    "deadline": "2026-10-10",
    "my_role": "Organiser",
    "external_reference": "JIRA-123",
    "external_url": "https://example.com",
    "description_html": "<p>New units and worktops.</p>",
    "description_text": "New units and worktops.",
    "members": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "role": "string"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

Delete a project

DELETE/projects/{id}

Delete a project and its members.

Restorable for 20 seconds (POST /projects/{id}/restoration), then permanent. The project is gone from every endpoint at once, with deletion records for the project and each member who isn't a deleted person. Notes referencing it get a new updated_at (they drop it from project_ids). Once the 20 seconds have passed, each reference becomes plain text "^Name" and those notes get a new updated_at (but not edited_at). Its name is free for a new project at once. Deleting again is a 404.

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

Path parameters

NameDescription
idULIDA record's ID.

Response

204 Deleted Errors: 401 403 404 429

Restore a project

POST/projects/{project_id}/restoration

Undo deleting a project.

Within 20 seconds of DELETE /projects/{id}: brings the project back with its description, members and references. Its deletion records are removed, and it, its members and the notes referencing it get a new updated_at. If another project took its name meanwhile, it comes back renamed "Name (2)" (the first free number), so check name. No body. Restoring a project that isn't deleted changes nothing and returns it, so a retry is safe. Once the 20 seconds have passed, or for an unknown id, it's a 404. If other projects take the name it picks twice in a row, it's a 422 on name and the project stays deleted; try again.

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

Path parameters

NameDescription
project_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 project, as GET /projects/{id} returns it. Errors: 400 401 403 404 409 415 422 429

{
  "data": {
    "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
    "name": "Kitchen renovation",
    "status": "planned",
    "status_changed_at": "2026-10-10T09:30:00Z",
    "start_date": "2026-10-10",
    "deadline": "2026-10-10",
    "my_role": "Organiser",
    "external_reference": "JIRA-123",
    "external_url": "https://example.com",
    "description_html": "<p>New units and worktops.</p>",
    "description_text": "New units and worktops.",
    "members": [
      {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "role": "string"
      }
    ],
    "created_at": "2026-10-10T09:30:00Z",
    "updated_at": "2026-10-10T09:30:00Z"
  }
}

List a project's activity

GET/projects/{project_id}/activity

What happened on a project, newest first.

One feed of the project's notes (live ones referencing it, at their created_at), completed tasks (live ones homed in it, at completed_at; reopening one removes it), linked documents (live ones, at the link's created_at; unlinking removes it), events (/project_events; a deleted person's member events are left out until they're restored) and, last, its creation. Newest first; entries at the same time go events, tasks, documents, notes, then created. Not a record: there's nothing to sync here (sync the records themselves). An unknown or deleted project is a 404.

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

Path parameters

NameDescription
project_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": [
    {
      "kind": "note",
      "at": "2026-10-10T09:30:00Z",
      "note": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "title": "Coffee with Maya",
        "name": "Coffee with Maya",
        "title_generated": true,
        "category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "tag_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "person_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "project_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "excerpt": "Talked about the move.",
        "image_count": 0,
        "pinned": true,
        "pinned_at": "2026-10-10T09:30:00Z",
        "edit_version": 1,
        "edited_at": "2026-10-10T09:30:00Z",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      },
      "task": {
        "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",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "position": 1,
        "description_html": "<p>Ask about the boiler too.</p>",
        "description_text": "Ask about the boiler too.",
        "has_documents": true,
        "expired": true,
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      },
      "document": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "name": "Boiler warranty",
        "folder_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "note_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "project_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "task_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "person_ids": [
          "01j9zq3k8m5x2v7c4n6b0t1r9e"
        ],
        "links": [
          {
            "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
            "note_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
            "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
            "task_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
            "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e"
          }
        ],
        "file": {
          "filename": "string",
          "byte_size": 1,
          "content_type": "application/pdf",
          "url": "https://example.com",
          "download_url": "https://example.com",
          "thumbnail_url": "https://example.com"
        },
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      },
      "event": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "kind": "status",
        "from": "string",
        "to": "string",
        "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "role": "Builder",
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    }
  ],
  "meta": {
    "next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
    "limit": 1,
    "total_count": 1
  }
}

List project changes

GET/project_events

Changes to projects' status, deadline and members.

Recorded as a project's status or deadline changes and as members are added or removed; never written through the API, and never edited. A status or deadline change within 10 minutes of the project's last of the same kind replaces it: that event is deleted (with a deletion record) and the new one runs from its from, or neither stays if it ends where that one began. Events of live projects, without a deleted person's member events. Deleting a project records a project_event deletion record for each of its events, and deleting a person for each of their member events; undoing the delete removes them and gives the events a new updated_at. For sync; GET /projects/{id}/activity shows them with the rest.

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

Query parameters

NameDescription
project_idULID · optionalA record's ID.
orderid | created_at | 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",
      "project_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "kind": "status",
      "from": "string",
      "to": "string",
      "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
      "role": "Builder",
      "created_at": "2026-10-10T09:30:00Z",
      "updated_at": "2026-10-10T09:30:00Z"
    }
  ],
  "meta": {
    "next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
    "limit": 1,
    "total_count": 1
  }
}

List upcoming deadlines

GET/upcoming_deadlines

Upcoming project deadlines.

Open projects (planned, active, on_hold) due from today to days from today, inclusive, and every overdue one, ordered by deadline, then name, then id; with limit alone, the nearest limit open deadlines with no window. Today is in the owner's time zone. Not paginated.

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

Query parameters

NameDescription
daysinteger · optionalThe window in days. Without days or limit, 30 (as /upcoming_key_dates); with limit alone, no window.
limitinteger · optionalAt most this many. With limit and no days: the nearest limit open deadlines, whatever the date, overdue first. With both, both apply.

Response

200 OK Errors: 400 401 429

{
  "data": [
    {
      "date": "2026-10-10",
      "overdue": true,
      "project": {
        "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
        "name": "Kitchen renovation",
        "status": "planned",
        "status_changed_at": "2026-10-10T09:30:00Z",
        "start_date": "2026-10-10",
        "deadline": "2026-10-10",
        "my_role": "Organiser",
        "external_reference": "JIRA-123",
        "external_url": "https://example.com",
        "description_html": "<p>New units and worktops.</p>",
        "description_text": "New units and worktops.",
        "members": [
          {
            "id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
            "person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
            "role": "string"
          }
        ],
        "created_at": "2026-10-10T09:30:00Z",
        "updated_at": "2026-10-10T09:30:00Z"
      }
    }
  ]
}

Menu

2026.10.1-beta.1Contact support