Notes
Notes, with their mentions, tags, project references, images and checklists.
On this page
- List or search notes
- Write a note
- Get a note
- Change a note
- Delete a note
- Download a note as a PDF
- Restore a note
- Get a note's insights
- Read a note again
- Mark an insight as not right
- Unmark an insight
- Correct an insight
- Remove a note's summary
- Pin a note
- Unpin a note
- Get a note's event
- Link a note to an event
- Unlink a note's event
- Attach a task to a note
- Detach a task from a note
- Tick a checklist item
- Note bodies
List or search notes
GET/notes
Notes, by when they were written (add direction=desc for the newest first), or searched with q.
Filters combine (AND). A filter id that doesn't exist gives an empty page; one that isn't an ID is 400.
Search. A non-blank q lists only matching notes, best match first (title, then tag and mentioned
names, then text; ties newest first), as GET /search finds them. When more than 2,000 notes
match in their title or labels, those are newest first instead of ranked; text-only matches are
newest first and capped at the newest 1,000. It combines with the
filters, but not with order, direction or updated_since (400). Its cursor belongs to that q and
those filters (400 otherwise) and holds a position, so notes edited between pages may shift: don't
sync with it. A blank q is ignored.
curl "$NIFTY_URL/api/v1/notes" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Query parameters
| Name | Description |
|---|---|
qstring · optional | Words to search for; each matches a word's start. Case and accents don't matter. More than 100 characters, or a NUL, is 400. |
orderedited_at | created_at | updated_at | id · optional | edited_at is the owner's last edit; side effects such as a tag rename don't change it. |
directionasc | desc · optional | asc (ascending) or desc (descending), for order. |
category_idULID · optional | A record's ID. |
tag_idULID · optional | A record's ID. |
person_idULID · optional | Only notes that mention this person (person_ids includes it), as the web person page lists them. An unknown or deleted person is an empty page. |
project_idULID · optional | Only notes that reference this project (project_ids includes it). An unknown or deleted project is an empty page. |
pinnedboolean · optional | true: only pinned notes; false: only unpinned ones. Anything else is 400. |
eventstring · optional | Only notes linked to this event (its CalendarEvent.link_key). One that no note links to is an empty page. |
kindstring · optional | Only notes of this type (kind), a key from the vocabulary's note_kinds. One no note has is an empty page. |
fieldssummary · optional | summary: each note as a NoteSummary, without body_html and body_text but with an excerpt and image_count, for lists (much faster for long notes). Anything else is 400. |
updated_sincedate-time · optional | Only records updated at or after this time (ISO 8601 with Z or a UTC offset), ordered by updated_at, id. |
cursorstring · optional | meta.next_cursor from the previous page. |
limitinteger · optional | Items per page, up to 100; a larger number is taken as 100. |
counttrue | false · optional | true 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": [
{
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
],
"meta": {
"next_cursor": "eyJrIjpbIjIwMjYtMTAtMDlUMDg6MzA6MDBaIl19",
"limit": 1,
"total_count": 1
}
}
Write a note
POST/notes
Needs a title or a body. See "Note bodies" for body_html.
curl -X POST "$NIFTY_URL/api/v1/notes" \
-H "Authorization: Bearer $NIFTY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"note":{"title":"Coffee with Alice","category_id":"01j9zq3c5d7e9f1g3h5j7k9m1n","body_html":"<p>Talked about the move with <nifty-mention person-id=\"01j9zq3k8m5x2v7c4n6b0t1r9e\"></nifty-mention>. <nifty-tag tag-name=\"moving\"></nifty-tag></p>"}}'
Headers
| Name | Description |
|---|---|
Idempotency-Keystring · optional | Makes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth). |
Request body
| Name | Description |
|---|---|
noteNoteFields | A note's writable fields (NoteInput). |
note.titlestring or null · optional | Spaces are squished; blank is null. Send it only when the owner changed it: any change makes the
title the owner's (title_generated false), and AI no longer touches it.
|
note.category_idULID or null · optional | An unknown id is a 422 on category_id. |
note.moodstring or null · optional | A key from the vocabulary's moods; null clears it. Anything else is a 422 on mood. |
note.kindstring or null · optional | A key from the vocabulary's note_kinds; null is no type. Anything else is a 422 on kind. Send it
only when the owner chose it: it's theirs from then on (kind_source owner), even null, so neither an
event nor AI types the note again. Left out, the type stays as it is.
|
note.body_htmlstring or null · optional | See "Note bodies". Null or "" clears it. |
note.edit_versioninteger · optional | Updates only (ignored on create). The note's edit_version these changes are based on; if it has moved on, the update is 409 conflict. |
note.eventNoteEventInput · optional | Create only (an update with it is a 422 on event; use PUT /notes/{id}/event). Links the new note to this calendar event, in the same save. |
Response
201 Created Errors: 400 401 403 409 415 422 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Get a note
GET/notes/{id}
curl "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 OK Errors: 401 404 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Change a note
PATCH/notes/{id}
Only the fields sent change. An omitted body_html is kept; "" clears it.
Send the edit_version your changes are based on to avoid overwriting an edit made elsewhere: if the
note has been edited since, it's 409 conflict and nothing is saved. Without it, the last write wins.
curl -X PATCH "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e" \
-H "Authorization: Bearer $NIFTY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"note":{"title":"Coffee with Alice","category_id":"01j9zq3c5d7e9f1g3h5j7k9m1n","body_html":"<p>Talked about the move with <nifty-mention person-id=\"01j9zq3k8m5x2v7c4n6b0t1r9e\"></nifty-mention>. <nifty-tag tag-name=\"moving\"></nifty-tag></p>"}}'
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Request body
| Name | Description |
|---|---|
noteNoteFields | A note's writable fields (NoteInput). |
note.titlestring or null · optional | Spaces are squished; blank is null. Send it only when the owner changed it: any change makes the
title the owner's (title_generated false), and AI no longer touches it.
|
note.category_idULID or null · optional | An unknown id is a 422 on category_id. |
note.moodstring or null · optional | A key from the vocabulary's moods; null clears it. Anything else is a 422 on mood. |
note.kindstring or null · optional | A key from the vocabulary's note_kinds; null is no type. Anything else is a 422 on kind. Send it
only when the owner chose it: it's theirs from then on (kind_source owner), even null, so neither an
event nor AI types the note again. Left out, the type stays as it is.
|
note.body_htmlstring or null · optional | See "Note bodies". Null or "" clears it. |
note.edit_versioninteger · optional | Updates only (ignored on create). The note's edit_version these changes are based on; if it has moved on, the update is 409 conflict. |
note.eventNoteEventInput · optional | Create only (an update with it is a 422 on event; use PUT /notes/{id}/event). Links the new note to this calendar event, in the same save. |
Response
200 OK Errors: 400 401 403 404 409 415 422 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Delete a note
DELETE/notes/{id}
Restorable for 10 seconds (POST /notes/{id}/restore), then permanent. The note is gone from every
endpoint at once, with a note deletion record. Once the 10 seconds have passed, any tag no other note
uses is deleted too (with a tag deletion record). Deleting again is a 404.
curl -X DELETE "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
204 Deleted Errors: 401 403 404 429
Download a note as a PDF
GET/notes/{id}/pdf
The note as a PDF to print or share: A4, set as the app's reader sets it, with its category and the date it was last edited (in the owner's time zone) above the title, then its body with images, checklists, code and links. Mentions, tags and project references show by their current names.
A download (Content-Disposition: attachment) named after the note plus .pdf, with
X-Content-Type-Options: nosniff. Made on each request, so it's never cached. It shows the note's first 100
images (in the order they were uploaded).
Two are made at a time: another meanwhile is a 503 busy with Retry-After. A note that takes too long to set
(a very long one, on a slow machine) is a 503 timeout.
curl "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/pdf" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 The PDF. Errors: 401 404 429 503
"@file.pdf"
Restore a note
POST/notes/{id}/restore
Undo deleting a note.
Within 10 seconds of DELETE /notes/{id}: brings the note back as it was. Its deletion record is removed and
it gets a new updated_at (not edited_at). No body. Restoring a note 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.
curl -X POST "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/restore" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Headers
| Name | Description |
|---|---|
Idempotency-Keystring · optional | Makes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth). |
Response
200 Restored. The note, as GET /notes/{id} returns it. Errors: 400 401 403 404 409 415 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Get a note's insights
GET/notes/{id}/analysis
This endpoint is in beta, so it can change in any release (Versions).
What the Note insights AI task read from the note: its summary (only a long note has one), its insights, and how the reading went. What was read before stays while the note waits to be read again, and while the task is off. A deleted or unknown note is a 404.
curl "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/analysis" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 The note's analysis. Errors: 401 404 429
{
"data": {
"status": "off",
"enabled": true,
"run_at": "2026-10-10T09:30:00Z",
"stale": true,
"read_at": "2026-10-10T09:30:00Z",
"model": "string",
"version": "insights-1",
"truncated": true,
"error": "The provider didn't answer within 5 minutes.",
"summary": {
"status": "read",
"markdown": "string",
"model": "string",
"read_at": "2026-10-10T09:30:00Z",
"error": "string"
},
"summary_removed": true,
"insights": [
{
"id": 1,
"kind": "you_owe",
"text": "string",
"quote": "string",
"open": true,
"event_on": "2026-10-10",
"event_until": "2026-10-10",
"check_on": "2026-10-10",
"lifespan": "lasting",
"first_seen_at": "2026-10-10T09:30:00Z",
"not_right": true,
"edited": true,
"subjects": [
{
"type": "person",
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string",
"deleted": true,
"task_relation": "about",
"matched_by": "mention",
"choices": [
{
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string"
}
]
}
]
}
]
}
}
Read a note again
POST/notes/{id}/analyze
This endpoint is in beta, so it can change in any release (Versions).
Queues the Note insights AI task to read the note now, even if it hasn't changed, replacing its analysis once
done (the earlier one stays meanwhile), and returns it as queued. A long note gets a summary again, even one
the owner removed. 422 (details.base) when the task is off
or has no model, or the note is too short to read. A deleted or unknown note is a 404. Limited with document
analysis runs: 20 a minute per IP address.
curl -X POST "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/analyze" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Headers
| Name | Description |
|---|---|
Idempotency-Keystring · optional | Makes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth). |
Response
202 Queued. Errors: 401 403 404 409 422 429
{
"data": {
"status": "off",
"enabled": true,
"run_at": "2026-10-10T09:30:00Z",
"stale": true,
"read_at": "2026-10-10T09:30:00Z",
"model": "string",
"version": "insights-1",
"truncated": true,
"error": "The provider didn't answer within 5 minutes.",
"summary": {
"status": "read",
"markdown": "string",
"model": "string",
"read_at": "2026-10-10T09:30:00Z",
"error": "string"
},
"summary_removed": true,
"insights": [
{
"id": 1,
"kind": "you_owe",
"text": "string",
"quote": "string",
"open": true,
"event_on": "2026-10-10",
"event_until": "2026-10-10",
"check_on": "2026-10-10",
"lifespan": "lasting",
"first_seen_at": "2026-10-10T09:30:00Z",
"not_right": true,
"edited": true,
"subjects": [
{
"type": "person",
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string",
"deleted": true,
"task_relation": "about",
"matched_by": "mention",
"choices": [
{
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string"
}
]
}
]
}
]
}
}
Mark an insight as not right
PUT/notes/{id}/insights/{insight_id}/not_right
This endpoint is in beta, so it can change in any release (Versions).
Records that the insight is wrong, so nothing but checking insights uses it, with a copy of it and of the note's text as read, so it can become a test case. It stays marked while later readings find it again. Marking one already marked changes nothing. No body. A deleted or unknown note, or an insight it doesn't have, is a 404.
curl -X PUT "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/insights/1/not_right" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
insight_idinteger | The insight's id (local to this install). |
Response
200 Marked. The note's analysis. Errors: 401 403 404 429
{
"data": {
"status": "off",
"enabled": true,
"run_at": "2026-10-10T09:30:00Z",
"stale": true,
"read_at": "2026-10-10T09:30:00Z",
"model": "string",
"version": "insights-1",
"truncated": true,
"error": "The provider didn't answer within 5 minutes.",
"summary": {
"status": "read",
"markdown": "string",
"model": "string",
"read_at": "2026-10-10T09:30:00Z",
"error": "string"
},
"summary_removed": true,
"insights": [
{
"id": 1,
"kind": "you_owe",
"text": "string",
"quote": "string",
"open": true,
"event_on": "2026-10-10",
"event_until": "2026-10-10",
"check_on": "2026-10-10",
"lifespan": "lasting",
"first_seen_at": "2026-10-10T09:30:00Z",
"not_right": true,
"edited": true,
"subjects": [
{
"type": "person",
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string",
"deleted": true,
"task_relation": "about",
"matched_by": "mention",
"choices": [
{
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string"
}
]
}
]
}
]
}
}
Unmark an insight
DELETE/notes/{id}/insights/{insight_id}/not_right
This endpoint is in beta, so it can change in any release (Versions).
Removes the insight's Not right, and its copy. One not marked changes nothing. A deleted or unknown note, or an insight it doesn't have, is a 404.
curl -X DELETE "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/insights/1/not_right" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
insight_idinteger | The insight's id (local to this install). |
Response
200 Unmarked. The note's analysis. Errors: 401 403 404 429
{
"data": {
"status": "off",
"enabled": true,
"run_at": "2026-10-10T09:30:00Z",
"stale": true,
"read_at": "2026-10-10T09:30:00Z",
"model": "string",
"version": "insights-1",
"truncated": true,
"error": "The provider didn't answer within 5 minutes.",
"summary": {
"status": "read",
"markdown": "string",
"model": "string",
"read_at": "2026-10-10T09:30:00Z",
"error": "string"
},
"summary_removed": true,
"insights": [
{
"id": 1,
"kind": "you_owe",
"text": "string",
"quote": "string",
"open": true,
"event_on": "2026-10-10",
"event_until": "2026-10-10",
"check_on": "2026-10-10",
"lifespan": "lasting",
"first_seen_at": "2026-10-10T09:30:00Z",
"not_right": true,
"edited": true,
"subjects": [
{
"type": "person",
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string",
"deleted": true,
"task_relation": "about",
"matched_by": "mention",
"choices": [
{
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string"
}
]
}
]
}
]
}
}
Correct an insight
PATCH/notes/{id}/insights/{insight_id}
This endpoint is in beta, so it can change in any release (Versions).
Changes the fields sent. text is the owner's wording, kept when later readings find the insight again.
subjects are what it's about, in order: a record by type and id (one gone for good, by type and name),
event for the note's event, or a name it already has by name. Those it has but aren't sent are removed, and later readings leave them off; a record
it doesn't have is added (matched_by owner), and also replaces an unmatched name that could be them. An
unknown or deleted record, one sent twice, or more than 8, is a 422. A deleted or unknown note, or an insight it
doesn't have, is a 404.
curl -X PATCH "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/insights/1" \
-H "Authorization: Bearer $NIFTY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"insight":{"text":"Simon'\''s dad wants him to have more to show for 25 years of owning Krystal.","subjects":[{"type":"person","id":"01j9zq3a9b8c7d6e5f4g3h2j1k"}]}}'
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
insight_idinteger | The insight's id (local to this install). |
Request body
| Name | Description |
|---|---|
insightobject | |
insight.textstring · optional | One sentence. Spaces are squished. |
insight.subjectsobject[] · optional | |
insight.subjects[].typeperson | project | task | company | event | name | |
insight.subjects[].idULID · optional | A record's ID. |
insight.subjects[].namestring · optional | A name subject's name, or a record's gone for good, as the insight has it. |
Response
200 Corrected. The note's analysis. Errors: 400 401 403 404 415 422 429
{
"data": {
"status": "off",
"enabled": true,
"run_at": "2026-10-10T09:30:00Z",
"stale": true,
"read_at": "2026-10-10T09:30:00Z",
"model": "string",
"version": "insights-1",
"truncated": true,
"error": "The provider didn't answer within 5 minutes.",
"summary": {
"status": "read",
"markdown": "string",
"model": "string",
"read_at": "2026-10-10T09:30:00Z",
"error": "string"
},
"summary_removed": true,
"insights": [
{
"id": 1,
"kind": "you_owe",
"text": "string",
"quote": "string",
"open": true,
"event_on": "2026-10-10",
"event_until": "2026-10-10",
"check_on": "2026-10-10",
"lifespan": "lasting",
"first_seen_at": "2026-10-10T09:30:00Z",
"not_right": true,
"edited": true,
"subjects": [
{
"type": "person",
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string",
"deleted": true,
"task_relation": "about",
"matched_by": "mention",
"choices": [
{
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string"
}
]
}
]
}
]
}
}
Remove a note's summary
DELETE/notes/{id}/summary
This endpoint is in beta, so it can change in any release (Versions).
Deletes the note's summary, and later readings don't write one (summary_removed) until the owner asks for
one (POST /notes/{id}/analyze). A note without one changes nothing. A deleted or unknown note is a 404.
curl -X DELETE "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/summary" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 Removed. The note's analysis. Errors: 401 403 404 429
{
"data": {
"status": "off",
"enabled": true,
"run_at": "2026-10-10T09:30:00Z",
"stale": true,
"read_at": "2026-10-10T09:30:00Z",
"model": "string",
"version": "insights-1",
"truncated": true,
"error": "The provider didn't answer within 5 minutes.",
"summary": {
"status": "read",
"markdown": "string",
"model": "string",
"read_at": "2026-10-10T09:30:00Z",
"error": "string"
},
"summary_removed": true,
"insights": [
{
"id": 1,
"kind": "you_owe",
"text": "string",
"quote": "string",
"open": true,
"event_on": "2026-10-10",
"event_until": "2026-10-10",
"check_on": "2026-10-10",
"lifespan": "lasting",
"first_seen_at": "2026-10-10T09:30:00Z",
"not_right": true,
"edited": true,
"subjects": [
{
"type": "person",
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string",
"deleted": true,
"task_relation": "about",
"matched_by": "mention",
"choices": [
{
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"name": "string"
}
]
}
]
}
]
}
}
Pin a note
PUT/notes/{id}/pin
Sets pinned and pinned_at. Not an edit: the note gets a new updated_at, but edited_at and
edit_version stay, so an update based on the earlier edit_version still succeeds. No body. Pinning a
pinned note changes nothing and returns it. A deleted or unknown note is a 404.
curl -X PUT "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/pin" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 Pinned. The note, as GET /notes/{id} returns it. Errors: 401 403 404 415 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Unpin a note
DELETE/notes/{id}/pin
Clears pinned and pinned_at, as pinning sets them: a new updated_at, not an edit. Unpinning a note
that isn't pinned changes nothing and returns it. A deleted or unknown note is a 404.
curl -X DELETE "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/pin" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 Unpinned. The note, as GET /notes/{id} returns it. Errors: 401 403 404 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Get a note's event
GET/notes/{id}/event
The note's event (event) as the calendar shows it now, with its current title and times. A 404 when the
note has none, or its event is no longer in the calendar (deleted, gone from its feed, hidden, or its feed
removed).
curl "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/event" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 OK Errors: 401 404 429
{
"data": {
"type_key": "string",
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"key": "string",
"link_key": "string",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Team stand-up",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"ends_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"end_on": "2026-10-10",
"location": "Room 2",
"description": "Weekly check-in.",
"url": "string",
"meeting": {
"provider": "google_meet",
"url": "https://example.com"
},
"attendee_count": 0,
"attendee_names": [
"string"
],
"attendees": [
{
"name": "Maya Okafor",
"email": "[email protected]",
"organizer": true,
"person_id": "01j9zq3k8m5x2v7c4n6b0t1r9e"
}
],
"rrule": "FREQ=WEEKLY;BYDAY=MO,WE",
"repeats": true,
"series_key": "string",
"ignored": "event"
}
}
Link a note to an event
PUT/notes/{id}/event
Sets the note's event, replacing any it had. Not an edit, as pinning: the note gets a new updated_at,
but edited_at and edit_version stay. Linking the event it's already linked to changes nothing. A
deleted or unknown note is a 404.
curl -X PUT "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/event" \
-H "Authorization: Bearer $NIFTY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"event":{"feed_id":"01j9zq3c5d7e9f1g3h5j7k9m1n","key":"q0Zb1kV6mVt2Xw3yZ4aB","date":"2026-10-09"}}'
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Headers
| Name | Description |
|---|---|
Idempotency-Keystring · optional | Makes a POST safe to retry for 24 hours. Needs a bearer token (400 under session auth). |
Request body
| Name | Description |
|---|---|
eventNoteEventInput | A calendar event to link a note to, as GET /calendar gives it: an own event's entry_id, or a feed's
occurrence by its feed_id, key and date (the day it starts in the owner's time zone). A repeating
event links that one occurrence. One that isn't an event (an unknown or deleted entry, or no such
occurrence that day), or one naming both kinds, is a 422 on event.
|
event.entry_idULID · optional | A record's ID. |
event.feed_idULID · optional | A record's ID. |
event.keystring · optional | The occurrence's CalendarEvent.key. |
event.datedate · optional |
Response
200 Linked. The note, as GET /notes/{id} returns it. Errors: 400 401 403 404 409 415 422 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Unlink a note's event
DELETE/notes/{id}/event
Clears the note's event, as linking sets it: a new updated_at, not an edit. A note with none changes
nothing and is returned. A deleted or unknown note is a 404.
curl -X DELETE "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/event" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
Response
200 Unlinked. The note, as GET /notes/{id} returns it. Errors: 401 403 404 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Attach a task to a note
PUT/notes/{id}/tasks/{task_id}
Adds the note to the task's note_ids, as a task save with it would (the web linker on a note). The task gets
a new updated_at; the note doesn't change. One attached already changes nothing. A deleted or unknown note
or task (a task in a deleted list or project counts as deleted) is a 404. No body.
curl -X PUT "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
task_idULID | A record's ID. |
Response
204 Attached. Errors: 401 403 404 429
Detach a task from a note
DELETE/notes/{id}/tasks/{task_id}
Removes the note from the task's note_ids, as attaching adds it. One not attached changes nothing. A
deleted or unknown note or task is a 404.
curl -X DELETE "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/tasks/01j9zq3k8m5x2v7c4n6b0t1r9e" \
-H "Authorization: Bearer $NIFTY_TOKEN"
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
task_idULID | A record's ID. |
Response
204 Detached. Errors: 401 403 404 429
Tick a checklist item
PATCH/notes/{id}/checklist_items/{position}
Tick or untick a checklist item in a note.
An edit, like PATCH /notes/{id}: edit_version, edited_at and updated_at move. edit_version is
required: if the note has been edited since, it's 409 conflict and nothing is saved, as the position may
name another item by then. An item already in that state saves nothing and returns the note. A position
with no item, or an unknown or deleted note, is a 404.
curl -X PATCH "$NIFTY_URL/api/v1/notes/01j9zq3k8m5x2v7c4n6b0t1r9e/checklist_items/0" \
-H "Authorization: Bearer $NIFTY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"checklist_item":{"checked":true,"edit_version":3}}'
Path parameters
| Name | Description |
|---|---|
idULID | A record's ID. |
positioninteger | The item's position among the body's checklist items (<li role="checkbox">), 0-based, in document order. |
Request body
| Name | Description |
|---|---|
checklist_itemobject | |
checklist_item.checkedboolean | true ticks it, false unticks it. Anything else is 400. |
checklist_item.edit_versioninteger | The note's edit_version the position was read at. Missing or not a positive integer is 400. |
Response
200 Ticked or unticked, or already so (nothing saved). The note, as GET /notes/{id} returns it. Errors: 400 401 403 404 409 415 422 429
{
"data": {
"received_via_api": {
"at": "2026-10-10T09:30:00Z",
"source": "Zapier"
},
"id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Coffee with Maya",
"name": "Coffee with Maya",
"title_generated": true,
"category_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"mood": "anxious",
"kind": "meeting",
"kind_source": "owner",
"tag_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"person_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"project_ids": [
"01j9zq3k8m5x2v7c4n6b0t1r9e"
],
"body_html": "<p>Talked about the move.</p>",
"body_text": "Talked about the move.",
"pinned": true,
"pinned_at": "2026-10-10T09:30:00Z",
"event": {
"link_key": "string",
"entry_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"feed_id": "01j9zq3k8m5x2v7c4n6b0t1r9e",
"title": "Planning",
"all_day": true,
"starts_at": "2026-10-10T09:30:00Z",
"start_on": "2026-10-10",
"linked_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"
}
}
Note bodies
body_html is HTML. Mentions, tags, project references and images are empty elements
carrying ids:
| Attachment | Element |
|---|---|
| Mention | <nifty-mention person-id="…">, and an optional alias="Mum": one of theirs, shown instead of their name |
| Tag | <nifty-tag tag-id="…">, or <nifty-tag tag-name="Work trip"> to find or make one |
| Project | <nifty-project project-id="…"> |
| Image | <nifty-image signed-id="…"> (signed-id from POST /uploads), and an optional caption |
- What you send is cleaned with the same rules used for display: scripts,
on*attributes,javascript:links and raw<img>are removed. - The body's mentions, tags and project references set the note's
person_ids,tag_idsandproject_ids(read-only). A tag no note uses any more is deleted. - Checklists are
<ul class="checklist">lists of<li role="checkbox" aria-checked="true|false">items; tick one withPATCH /notes/{id}/checklist_items/{position}. body_textis the plain text: mentions as "@Name" (or "@Alias"), tags as "#name", projects as "^Name".- Renaming, merging or deleting a tag, a person or a project gives the notes that use it a new
updated_at. - A body over 1 MB, or with a NUL, an unknown
tag-idorproject-id, or a badsigned-id, is a422.