Accent
The accent colour. Iris is the default.
iris | coral | jade | saffron | orchid | steel
AIModel
| Field | Type | Description |
id | ULID | A record's ID. |
ai_provider_id | ULID | A record's ID. |
identifier | string | |
name | string | |
is_default | boolean | At most one model is the default; with none, only tasks with their own model run. |
created_at | date-time | |
updated_at | date-time | |
AIModelResponse
| Field | Type | Description |
data | AIModel | |
AIProvider
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
kind | AIProviderKind | openai_compatible covers OpenAI, Ollama, LM Studio, llama.cpp and vLLM. mock needs no network and isn't available in production. |
base_url | string or null | |
api_key_set | boolean | Whether a key is stored. The key itself is never returned. |
reply_timeout_seconds | integer or null | How long the provider may take to answer each call that writes something (a title, a summary, a
document's, image's or note's reading). Each call waits the longer of this and its own standard limit
(90 seconds, or 5 minutes for a document, image or note). Null: the standard limits. Checks and model
lists keep 90 seconds. |
last_succeeded_at | date-time or null | The last successful check, trial or AI call. |
last_failed_at | date-time or null | |
last_error | string or null | The last failure's message; cleared by a success. |
last_error_reason | string or null | last_error as a sentence fit to show, e.g. “Ollama rejected the API key.” for an HTTP 401 or 403 when a key is stored. Null when last_error is. |
created_at | date-time | |
updated_at | date-time | |
AIProviderKind
openai_compatible covers OpenAI, Ollama, LM Studio, llama.cpp and vLLM. mock needs no network and isn't available in production.
openai_compatible | anthropic | mock
AIProviderResponse
| Field | Type | Description |
data | AIProvider | |
AITask
| Field | Type | Description |
key | string | Stable, e.g. note_titles. |
name | string | |
description | string | |
enabled | boolean | Off until the owner turns it on. |
ai_model_id | ULID or null | The model the task uses; null for the default model. With neither, the task does nothing. |
reasoning | AITaskReasoning | How hard a reasoning model thinks before replying; none answers at once. Sent to OpenAI-compatible
providers as reasoning_effort; null (the default) sends nothing, leaving it to the model. Anthropic and
Mock models ignore it (the value is kept). Anything else is a 422. |
max_output_tokens | integer or null | The most tokens a reply may use (reasoning included); null for default_max_output_tokens. |
default_max_output_tokens | integer | The task's own reply budget, used while max_output_tokens is null (note titles: 2,048). |
backfill_pending | integer or null | How many records POST …/backfill would queue now; null for a task without a backfill. |
updated_at | date-time or null | The last change to its settings; null until first configured. |
AITaskReasoning
How hard a reasoning model thinks before replying; none answers at once. Sent to OpenAI-compatible
providers as reasoning_effort; null (the default) sends nothing, leaving it to the model. Anthropic and
Mock models ignore it (the value is kept). Anything else is a 422.
none | low | medium | high | null
AITaskResponse
| Field | Type | Description |
data | AITask | |
ApiToken
| Field | Type | Description |
id | integer | |
name | string | |
scope | full | read | full may read and change anything a token may; read may only read (GET, HEAD and POST /mcp). |
created_at | date-time | |
expires_at | date-time or null | |
last_used_at | date-time or null | |
Appearance
| Field | Type | Description |
accent | Accent | The accent colour. Iris is the default. |
theme | Theme | system follows the device's light or dark setting. The default. |
code_theme | CodeTheme | Code blocks in notes: match follows the theme (the default); light or dark keeps them in that scheme. |
text_size | TextSize | The interface's text size; medium is the default. |
updated_at | date-time | When the owner record last changed. |
AppearanceResponse
| Field | Type | Description |
data | Appearance | |
Avatar
Absolute URLs that redirect to the image. Anyone with a link can load it (long and unguessable;
owner decision). Thumb is 128 px square and large 256 px square, both WebP.
| Field | Type | Description |
url | uri | |
thumb_url | uri | |
large_url | uri | |
BackupReason
Why it was made; the words are the vocabulary's backup_reasons.
before_update | before_restore | manual | scheduled
CalendarAlert
| Field | Type | Description |
alert_at | date-time | When to alert. |
minutes | integer | Minutes before the event starts: its feed's alert_minutes. |
event | CalendarEvent | One occurrence of a feed's event (a repeating event gives one per instance), or one of the owner's own events
(entry_id set, feed_id null: edit it through /calendar_entries). Otherwise read only. |
CalendarAlertSound
For calendar alerts. music_box is the default; none is silent.
arpeggio | music_box | door_knock | window_knock | none
CalendarAttendee
Someone invited to an event (or its organizer). Matched to a person when the event is read, so never stale: a
live person with this email address (ignoring case), else the one live person whose name is this name
(ignoring case and accents; none when two or more share it).
| Field | Type | Description |
name | string | Their name as the feed gives it, else their email address. |
email | string or null | Their email address, lower case; null when the feed gives none. |
organizer | boolean | The event's organizer (listed first). |
person_id | ULID or null | The person they are; null when none matches. |
CalendarEntry
One of the owner's own events, on My Nifty Calendar: a single day, all day or from a start to an end time.
Synced; deleting one records a calendar_entry deletion. GET /calendar shows it as a CalendarEvent with
entry_id set.
| Field | Type | Description |
type_key | EventTypeKey | A key from event_types, or null for No type. On creation, omission assigns a type once, from the owner's rules (/calendar_type_rules) and then deterministic ones; while it has no type, a rule added or changed later may give it one. Sending it, even null, is the owner's choice, which no rule changes. On update, omission preserves the saved type. |
received_via_api | ReceivedViaAPI or null | How it came: through the Send to Nifty API (GET /send_api), or null. |
id | ULID | A record's ID. |
title | string | |
date | date | The day (in time_zone when timed). |
all_day | boolean | |
start_time | string or null | HH:MM in time_zone; null when all day. |
end_time | string or null | HH:MM in time_zone; null when all day. |
time_zone | string or null | An IANA zone; null when all day. |
starts_at | date-time or null | The start as an instant; null when all day. |
ends_at | date-time or null | The end as an instant; null when all day. |
location | string or null | |
notes | string or null | Plain text. |
created_at | date-time | |
updated_at | date-time | |
CalendarEntryResponse
| Field | Type | Description |
data | CalendarEntry | One of the owner's own events, on My Nifty Calendar: a single day, all day or from a start to an end time.
Synced; deleting one records a calendar_entry deletion. GET /calendar shows it as a CalendarEvent with
entry_id set. |
CalendarEvent
One occurrence of a feed's event (a repeating event gives one per instance), or one of the owner's own events
(entry_id set, feed_id null: edit it through /calendar_entries). Otherwise read only.
| Field | Type | Description |
type_key | EventTypeKey | A key from event_types, or null for No type. On creation, omission assigns a type once, from the owner's rules (/calendar_type_rules) and then deterministic ones; while it has no type, a rule added or changed later may give it one. Sending it, even null, is the owner's choice, which no rule changes. On update, omission preserves the saved type. |
received_via_api | ReceivedViaAPI or null | An own event (entry_id) the Send to Nifty API added; null otherwise. |
key | string | Opaque; the same for this occurrence across syncs. |
link_key | string | Opaque; what notes link to (Note.event.link_key, GET /notes?event=). An own event's is its entry_id.
A feed's is the same across syncs and, for an event that doesn't repeat, even when it moves; for a
repeating one it names this occurrence. |
feed_id | ULID or null | The feed it's from; null for the owner's own events (My Nifty Calendar). |
entry_id | ULID or null | The owner's own event (CalendarEntry.id); null for a feed's. |
title | string | Blank when the event has none. |
all_day | boolean | |
starts_at | date-time or null | Timed events only. |
ends_at | date-time or null | Timed events only; at or after starts_at. |
start_on | date or null | All-day events only. |
end_on | date or null | All-day events only: the last day, inclusive. |
location | string or null | |
description | string or null | Plain text, at most 4,000 characters. |
url | string or null | An http(s) link the event gives. |
meeting | CalendarMeeting or null | The online meeting to join, found in the event's conference properties, URL, location or description; null when none. |
attendee_count | integer | |
attendee_names | string[] | The first 10 attendees' names (else their addresses). |
attendees | CalendarAttendee[] | The first 10 attendees, the organizer first, each matched to a person when one fits. attendee_count counts
every attendee (but not an organizer who isn't one). |
rrule | string or null | The repeat rule (RFC 5545 RRULE value, e.g. FREQ=WEEKLY;BYDAY=MO); null unless it repeats. |
repeats | boolean | One of a repeating event's occurrences: by a rule (rrule) or by dates alone (RDATE, rrule null). False for the owner's own. |
series_key | string or null | Opaque; the same for every occurrence of a repeating event (repeats), moved ones too, and apart from
other feeds' events; null when it doesn't repeat, and for the owner's own events. Groups a week's repeats. |
ignored | event | repeats | null | Ignored (/calendar/ignored_events): this occurrence (event) or every occurrence of its event (repeats,
when both apply); null when not. Only GET /calendar and a note's linked event give an ignored one. |
CalendarFeed
An iCal address whose events the calendar shows, read only. Synced; removing one records a calendar_feed
deletion. Every sync attempt gives it a new updated_at. Its events aren't records: read them with
GET /calendar.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
color | string | A key from the vocabulary's colors. |
address_host | string | The address's host, shown instead of the address (which is secret). |
source | google | outlook | icloud | null | Where the calendar lives, from the host: a key from the vocabulary's calendar_sources; null when unknown. |
sync_every | CalendarSyncFrequency | How often the feed is fetched; the words are the vocabulary's calendar_sync_frequencies. |
alert_minutes | integer or null | Minutes before its timed events start that the desktop app alerts (0: as they start); null when off. See GET /calendar/alerts. |
hidden_from_today | boolean | Its events stay off Today, This week and Next week (and the today tool); Calendar still shows them. |
last_synced_at | date-time or null | The last successful sync (changed or not). |
last_attempt_at | date-time or null | |
sync_error | CalendarFeedSyncError or null | Why the latest syncs failed; null while healthy. The events shown are from last_synced_at. |
created_at | date-time | |
updated_at | date-time | |
CalendarFeedResponse
| Field | Type | Description |
data | CalendarFeed | An iCal address whose events the calendar shows, read only. Synced; removing one records a calendar_feed
deletion. Every sync attempt gives it a new updated_at. Its events aren't records: read them with
GET /calendar. |
CalendarFeedSyncError
| Field | Type | Description |
code | CalendarSyncErrorCode | Why a feed couldn't be read; the words are the vocabulary's calendar_sync_errors. |
http_status | integer or null | The server's HTTP status, when it answered with one. |
failures | integer | Tries that have failed in a row. |
CalendarMeeting
| Field | Type | Description |
provider | CalendarMeetingProvider | The words are the vocabulary's meeting_providers. |
url | uri | An https link to join the meeting. |
CalendarMeetingProvider
The words are the vocabulary's meeting_providers.
google_meet | teams | zoom | webex | whereby | jitsi | goto | other
CalendarProjectDate
| Field | Type | Description |
date | date | |
kind | deadline | start | |
project | Project | Members, role changes and member removals change the project's updated_at, as does a member's person being deleted or restored. |
CalendarRange
| Field | Type | Description |
from | date | |
to | date | |
today | date | Today in the owner's time zone. |
events | CalendarEvent[] | |
tasks | Task[] | |
project_dates | CalendarProjectDate[] | |
key_dates | UpcomingKeyDate[] | |
people | Person[] | Each person an event's attendees name (person_id), once, by name. |
CalendarSyncErrorCode
Why a feed couldn't be read; the words are the vocabulary's calendar_sync_errors.
not_found | denied | server_error | unreachable | timed_out | tls | too_big | not_calendar | too_many_events | refused_address | address_unreadable | not_saved
CalendarSyncFrequency
How often the feed is fetched; the words are the vocabulary's calendar_sync_frequencies.
15_minutes | 30_minutes | hourly | 6_hours | daily
CalendarTypeRule
One of the owner's rules for an event's type.
| Field | Type | Description |
id | ULID | A record's ID. |
type_key | RuleTypeKey | A key from event_types, or null for No type (Nifty's own rules then don't type the event). Null on create unless sent. |
conditions | CalendarTypeRuleCondition[] | All must match, in no particular sense of order. |
position | integer | A sort key: order by position, then id. Gaps are possible after a delete. |
created_at | date-time | |
updated_at | date-time | |
CalendarTypeRuleAttendeeCountCondition
How many take part: the organizer and each guest once, not rooms or resources (so the owner, when on the invite). An event listing nobody, and the owner's own, count 1.
| Field | Type | Description |
kind | attendee_count | |
comparison | at_least | at_most | exactly | |
count | integer | |
CalendarTypeRuleCalendarCondition
The event is on this calendar. At most one per rule.
| Field | Type | Description |
kind | calendar | |
feed_id | ULID or null | A feed's id, or null for My Nifty Calendar. |
CalendarTypeRuleCondition
One test of an event. Text is compared ignoring case, accents and repeated spaces: name_contains,
location_contains and attendee_email_contains match it anywhere, name_equals the whole name.
CalendarTypeRuleTextCondition or CalendarTypeRuleAttendeeCountCondition or CalendarTypeRuleStartsBetweenCondition or CalendarTypeRuleCalendarCondition
CalendarTypeRuleResponse
| Field | Type | Description |
data | CalendarTypeRule | One of the owner's rules for an event's type. |
CalendarTypeRuleSaved
| Field | Type | Description |
data | CalendarTypeRule | One of the owner's rules for an event's type. |
meta | object | |
CalendarTypeRuleStartsBetweenCondition
The event starts at or after from and before to, in the owner's time zone; from after to runs past
midnight (22:00 to 02:00). An all-day event never matches.
| Field | Type | Description |
kind | starts_between | |
from | string | |
to | string | Not the same as from. |
CalendarTypeRuleTextCondition
The event's name, location or an attendee's email address (never their name) has text.
| Field | Type | Description |
kind | name_contains | name_equals | location_contains | attendee_email_contains | |
text | string | Spaces are squished; blank is a 422. |
CalendarView
The view the Calendar opens in: day (the default) or week.
day | week
Category
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
color | string | A palette key from GET /category_choices (e.g. teal). Render it from your own palette. |
icon | string or null | A Lucide icon name, or null for none (show a dot). May be one no longer in the picker. |
position | integer | A sort key: order by position, then id. Gaps are possible after a delete. |
created_at | date-time | |
updated_at | date-time | |
CategoryChoices
| Field | Type | Description |
colors | object[] | |
icons | string[] | |
CategoryNoteCount
| Field | Type | Description |
category_id | ULID | A record's ID. |
note_count | integer | |
CategoryResponse
| Field | Type | Description |
data | Category | |
CodeTheme
Code blocks in notes: match follows the theme (the default); light or dark keeps them in that scheme.
match | light | dark
Company
Where people work. The name keeps its casing; matching ignores case.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
created_at | date-time | |
updated_at | date-time | |
CompanyResponse
| Field | Type | Description |
data | Company | Where people work. The name keeps its casing; matching ignores case. |
Connection
One of a person's links, from their side. person_id is this person's kind.
| Field | Type | Description |
id | ULID | The person link's id. |
person_id | ULID | The other person. |
kind | PersonLinkRole | A role in a person link. Each inverse follows its forward role; the rest are symmetric. |
note | string or null | |
| Field | Type | Description |
suggestions | string[] | |
default | string or null | The label a new one starts with. |
Cover
A record's header: a colour (a cover_colors key in the vocabulary: a gradient or a solid; render each from
your own palette, with a dark-mode version) or a photo the owner uploaded (PUT /projects/{id}/cover_photo),
shown framed position percent down.
| Field | Type | Description |
kind | color | photo | |
color | string or null | A cover_colors key (kind color). |
photo | CoverPhoto or null | |
position | integer | How far down a photo is framed: 0 its top, 100 its foot. |
CoverPhoto
A cover's uploaded photo. Its URLs are public but unguessable, as uploads' are.
| Field | Type | Description |
url | uri | Fitted within 2400×1600 (WebP): for a header. |
preview_url | uri | Fitted within 1024×768 (WebP): for a card. |
thumb_url | uri | A 128px square (WebP): for a tile. |
width | integer | The uploaded image's width. |
height | integer | |
credit | UnsplashCredit or null | Who took a photo from Unsplash, to show with it; null for the owner's own. |
CoverWrite
A cover to set. Every project wears one, so null is a 422 on cover. Kind color needs a color; kind
photo keeps the photo the cover has (upload a new one with PUT /projects/{id}/cover_photo), so it's for
moving position. An unknown colour, a photo when there's none, or a position out of range is a 422 on
cover.<field>. A project created without one gets one of the colours its projects use least, at random. A
photo a colour replaces is deleted.
| Field | Type | Description |
kind | color | photo | |
color optional | string | A cover_colors key (kind color). |
position optional | integer | Default: the cover's own, else 50. |
CreatedSound
Played when a task, person or project is created. blip_blip is the default; none is silent.
blip_blip | pop_drop | shimmer | kalimba_pair | none
DeletedSound
Played when something is deleted, removed, revoked or disconnected. paper_away is the default; none is silent.
knock_away | falling | bloop | paper_away | none
Deletion
| Field | Type | Description |
type | string | The resource type, e.g. "person". |
id | ULID | A record's ID. |
deleted_at | date-time | |
Discovery
| Field | Type | Description |
app | "nifty" | |
version | string | The server's version; dev in an unreleased build. |
min_shell_version | string | The oldest desktop app that can open this server. |
api_versions | object[] | |
Document
A PDF, an image (kind: image: a screenshot or a photo, its text read by OCR), or an email (kind: email,
POST /email_imports) with its PDF attachments inside it. Synced; deleting
one records a document deletion. Embeds no other record's data, only ids, so renaming a folder or a linked
record changes no document. Linking or unlinking it, deleting or restoring a record it's linked to (or a list,
person or project hiding a linked task), and deleting its folder while it's deleted give it a new
updated_at. Notes, projects, tasks and people don't list their documents: filter GET /documents.
| Field | Type | Description |
received_via_api | ReceivedViaAPI or null | How it came: through the Send to Nifty API (GET /send_api), or null. |
id | ULID | A record's ID. |
kind | pdf | email | image | |
name | string | |
dated_on | date | Its date: when it was written, sent or received, as against created_at. The owner's choice when
dated_on_set; else an email's (or an email's attachment's) sent date, else the date the Document summaries
AI task read from it, else the day it was added. A sent or added date is the day in the owner's time zone. |
dated_on_set | boolean | The owner chose dated_on. |
folder_id | ULID or null | An attachment's is its email's. |
email_id | ULID or null | The email this PDF was attached to. It lives inside the email, which moves and deletes it too. |
email | EmailDetails or null | An email's headers and attachments; null for a PDF. |
from_email | EmailOrigin or null | A PDF added from an email that wasn't kept (it had nothing to say), with who sent it and when. |
note_ids | ULID[] | Linked live notes, by id. |
project_ids | ULID[] | |
task_ids | ULID[] | |
person_ids | ULID[] | |
links | object[] | Its links to live records, for DELETE /document_links/{id}. Notes, projects, tasks, then people; each by id. |
file | object | |
analysis | DocumentAnalysisState | Where the document's text and analysis are (GET /documents/{id}/analysis has the rest). Each change gives the
document a new updated_at. |
created_at | date-time | |
updated_at | date-time | |
DocumentAnalysis
A document's analysis: what the PDF says of itself, how much text was read (an image's by OCR), and the
Document summaries AI task's result. facts are the fields every type may have; fields the type's own. Both list every field in
order, with null values for what the document doesn't state. The summary is Markdown written by a model:
render it without HTML, links or images.
| Field | Type | Description |
status | reading | no_text | unreadable | not_analysed | pending | done | failed | |
error | string or null | Why the last try failed (failed only). |
type | string or null | |
type_label | string or null | |
summary | string or null | Markdown. |
facts | DocumentField[] | |
fields | DocumentField[] | |
model | string or null | The name of the model that wrote it. |
analysed_at | date-time or null | |
pages_analysed | integer or null | When the model was given only part of the document (a long one, or a model with a small context): how many
pages, from the first. Null when it read all of it. |
image | DocumentImageProcessing or null | An image's reading by the Image processing AI task; null for anything else, or an image it hasn't read. |
pdf | object | The PDF's own information, where it has it (all null for an image). |
text | object | |
DocumentAnalysisResponse
| Field | Type | Description |
data | DocumentAnalysis | A document's analysis: what the PDF says of itself, how much text was read (an image's by OCR), and the
Document summaries AI task's result. facts are the fields every type may have; fields the type's own. Both list every field in
order, with null values for what the document doesn't state. The summary is Markdown written by a model:
render it without HTML, links or images. |
DocumentAnalysisState
Where the document's text and analysis are (GET /documents/{id}/analysis has the rest). Each change gives the
document a new updated_at.
| Field | Type | Description |
status | reading | no_text | unreadable | not_analysed | pending | done | failed | reading: the text is still to be read, shortly after the upload. no_text: it has no text to read (a
scanned PDF, or an image without words). unreadable: it can't be read (encrypted or broken). not_analysed: it has text but no analysis
(the Document summaries AI task is off, or was when it was read). pending: queued or under way; an
earlier result, if any, stays until it's replaced. done: analysed. failed: the last try failed. |
type | string or null | The document type's key, e.g. energy_bill; null until analysed. |
type_label | string or null | |
DocumentField
One extracted value. value by kind: text and enum a string, date "YYYY-MM-DD", money
{ minor, currency } (an integer in the currency's minor unit, and its ISO code), number a number in
unit, bool a boolean, list an array of objects keyed by columns' keys. Null when not stated.
| Field | Type | Description |
key | string | |
label | string | |
kind | text | date | money | number | enum | bool | list | |
unit | string or null | |
value | any | See kind; null when not stated. |
columns optional | object[] | A list's item fields (list only). |
DocumentImageProcessing
What the Image processing AI task made of an image, while it's on: it reads the picture with a model that can
see it. done: its transcription is the document's text (text), it may have named the image, and description
says what it shows. While pending, the document's analysis is reading. failed: the text OCR read is used.
| Field | Type | Description |
status | pending | done | failed | |
description | string or null | |
model | string or null | The name of the model that read it. |
error | string or null | Why it failed (failed only). |
DocumentLink
A document's link to one note, project, task or person; the other three are null. Not synced (a document lists its own in links).
| Field | Type | Description |
id | ULID | A record's ID. |
document_id | ULID | A record's ID. |
note_id | ULID or null | |
project_id | ULID or null | |
task_id | ULID or null | |
person_id | ULID or null | |
created_at | date-time | |
DocumentLinkResponse
| Field | Type | Description |
data | DocumentLink | A document's link to one note, project, task or person; the other three are null. Not synced (a document lists its own in links). |
DocumentLinkWrite
document_id and exactly one of note_id, project_id, task_id and person_id.
| Field | Type | Description |
document_id | ULID | A record's ID. |
note_id optional | ULID or null | |
project_id optional | ULID or null | |
task_id optional | ULID or null | |
person_id optional | ULID or null | |
DocumentResponse
| Field | Type | Description |
data | Document | A PDF, an image (kind: image: a screenshot or a photo, its text read by OCR), or an email (kind: email,
POST /email_imports) with its PDF attachments inside it. Synced; deleting
one records a document deletion. Embeds no other record's data, only ids, so renaming a folder or a linked
record changes no document. Linking or unlinking it, deleting or restoring a record it's linked to (or a list,
person or project hiding a linked task), and deleting its folder while it's deleted give it a new
updated_at. Notes, projects, tasks and people don't list their documents: filter GET /documents. |
DocumentText
| Field | Type | Description |
text | string | At most 200,000 characters; a PDF's pages each after a --- Page N --- line. |
truncated | boolean | Pages or characters were left out. |
read_by | pdf | ocr | model | email | null | What read it: the PDF's own text, Nifty's OCR, the Image processing task's model, or an email's body. Null until it's read. |
ocr_text | string or null | The text Nifty's OCR read, where the model's reading is text (read_by: model), even when they agree. |
DocumentTextResponse
| Field | Type | Description |
data | DocumentText | |
DocumentWrite
| Field | Type | Description |
name optional | string | Spaces are squished. Needn't be unique. |
folder_id optional | ULID or null | Null: no folder. Not an id, or an unknown folder, is a 422. |
note_ids optional | ULID[] or null | Replaces its links to notes; null or [] removes them. An unknown or deleted id, or one that isn't an id, is a 422 on the field. |
project_ids optional | ULID[] or null | |
task_ids optional | ULID[] or null | A task in a deleted list or project counts as deleted. |
person_ids optional | ULID[] or null | |
dated_on optional | date or null | YYYY-MM-DD: the owner's choice, which nothing else replaces. Null goes back to Nifty's choice. One that isn't a date is a 422. |
EmailAddress
| Field | Type | Description |
id | ULID | A record's ID. |
address | string | |
label | string or null | |
created_at | date-time | |
updated_at | date-time | |
EmailAttachment
| Field | Type | Description |
filename | string | |
content_type | string | |
byte_size | integer | |
status | saved | removed | not_saved | saved: a document inside the email (document_id). removed: it was, and was deleted. not_saved: not a PDF, so not kept. |
document_id | ULID or null | The document it became (saved only). |
EmailDetails
An email's headers, from the original when it was forwarded. Its body is body_url's page; its text is the
document's text (search, summaries and the people it names read it, with its attachments').
| Field | Type | Description |
subject | string or null | |
from | EmailParty or null | |
to | EmailParty[] | |
cc | EmailParty[] | |
sent_at | date-time or null | |
forwarded | boolean | It was forwarded; this is the original it forwards. |
forward_note | string or null | What the forwarder wrote above the forward. |
forwarded_at | date-time or null | When it reached Nifty by email forwarding (GET /email_forwarding); null when it was imported as a file. |
has_html | boolean | Its body is HTML (else plain text). |
remote_images | boolean | Its HTML loads images from elsewhere, which body_url blocks unless asked. |
body_url | uri | GET /documents/{id}/email_body: absolute, and needs the token. |
attachments | EmailAttachment[] | Every attachment, in the email's order. |
EmailForwarding
| Field | Type | Description |
available | boolean | Plus is available (GET /plus): the address accepts email, and it and the senders can be changed. |
unavailable_reason | not_connected | inactive | read_only | null | As GET /plus's. Emails that arrived before the subscription ended are still collected while inactive. |
address | string or null | Where to forward emails; null until Plus first makes it. |
senders | object | |
waiting | integer | Emails waiting to be collected at the last check (at most 30: more are refused). |
error | unreachable | null | unreachable: the forwarding service couldn't be reached at the last check; the rest is as last known. |
checked_at | date-time or null | When the forwarding service last answered. |
collected_at | date-time or null | When an email was last collected. |
lost | integer | Emails let go because they were sealed for another copy of Nifty (before Plus moved here), since last dismissed. |
unreadable | integer | Emails let go because they couldn't be read as emails, since last dismissed. |
EmailForwardingResponse
| Field | Type | Description |
data | EmailForwarding | |
EmailImportResponse
| Field | Type | Description |
data | object | |
EmailOrigin
| Field | Type | Description |
subject | string or null | |
from | EmailParty or null | |
sent_at | date-time or null | |
forwarded_at | date-time or null | When it reached Nifty by email forwarding; null when it was imported as a file. |
EmailParty
| Field | Type | Description |
name | string or null | |
address | string or null | |
person_id | ULID or null | The one live person with this address, matched as it's read (so never stale); else null. |
Error
| Field | Type | Description |
error | object | |
ErrorReportFrame
| Field | Type | Description |
function | string | Blank when unknown. |
file | string | A path or URL; only a URL's path is kept. |
line | integer | 0 when unknown. |
column | integer | 0 when unknown. |
EventTypeKey
A key from event_types, or null for No type. On creation, omission assigns a type once, from the owner's rules (/calendar_type_rules) and then deterministic ones; while it has no type, a rule added or changed later may give it one. Sending it, even null, is the owner's choice, which no rule changes. On update, omission preserves the saved type.
string or null
Fact
What you know about a person under one fact label: at most one fact per person and label. Synced; deleting one, its label or its person records a
fact deletion (undoing the person's delete removes it).
| Field | Type | Description |
id | ULID | A record's ID. |
person_id | ULID | A record's ID. |
label_id | ULID | A record's ID. |
text | string | |
edited_at | date-time | Read-only. The last change to the text or label: when the fact was last updated, to show. |
created_at | date-time | |
updated_at | date-time | For sync. Also changes when the person's delete is undone. |
FactLabel
What a fact is about, shared by every person. Synced; deleting one records a fact_label deletion.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
icon | string or null | A Lucide icon name, or null for none. May be one no longer in the picker. |
position | integer | A sort key: order by position, then id. Gaps are possible after a delete. |
created_at | date-time | |
updated_at | date-time | |
FactLabelCount
| Field | Type | Description |
fact_label_id | ULID | A record's ID. |
fact_count | integer | |
FactLabelResponse
| Field | Type | Description |
data | FactLabel | What a fact is about, shared by every person. Synced; deleting one records a fact_label deletion. |
FactResponse
| Field | Type | Description |
data | Fact | What you know about a person under one fact label: at most one fact per person and label. Synced; deleting one, its label or its person records a
fact deletion (undoing the person's delete removes it). |
Folder
A folder of documents. Synced; deleting one records a folder deletion. No counts or paths (build them from parent_id).
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | Unique among its siblings, ignoring case. |
parent_id | ULID or null | The folder it's in; null at the top level. |
color | string | A key from the vocabulary's colors (e.g. teal). |
icon | string or null | A Lucide icon name, or null for the default folder icon. May be one no longer in the vocabulary's picker_icons. |
created_at | date-time | |
updated_at | date-time | |
FolderCount
| Field | Type | Description |
folder_id | ULID or null | The folder; null for the documents in no folder. |
document_count | integer | |
byte_size | integer | The sum of these documents' and their attachments' file.byte_size. |
FolderResponse
| Field | Type | Description |
data | Folder | A folder of documents. Synced; deleting one records a folder deletion. No counts or paths (build them from parent_id). |
GettingStarted
| Field | Type | Description |
started | object | Whether each area has anything in it yet, deleted things aside. |
hidden | GettingStartedTip[] | The tips the owner has hidden. |
GettingStartedResponse
| Field | Type | Description |
data | GettingStarted | |
GettingStartedTip
A getting-started tip: today, Today's welcome; calendar, Calendar's card.
today | calendar
HiddenCalendars
What the Calendar and Today's Meeting leave out: calendar feeds by id, nifty (My Nifty Calendar) and the kinds of Nifty's own dates (tasks, project_dates, key_dates). Sorted. None by default.
string[]
KeyDate
A date that comes round every year. Synced; destroying one records a key_date deletion.
| Field | Type | Description |
id | ULID | A record's ID. |
kind | KeyDateKind | |
label | string or null | Names an other date ("Sobriety"), or adds to any other kind ("Wedding"). |
day | integer | |
month | integer | |
year | integer or null | Null when unknown. |
created_at | date-time | |
updated_at | date-time | |
KeyDateKind
birthday | anniversary | work_anniversary | first_met | name_day | memorial | other
LibrarySort
How a Library place sorts. By name, A to Z, is the default.
| Field | Type | Description |
by | name | date | size | |
descending | boolean | |
Licence
| Field | Type | Description |
state | licensed | trial | read_only | licensed: a valid key covers this version. trial: the 14-day free trial. read_only: neither, so writes get 403 read_only. |
problem | revoked | not_covered | null | Why the stored key doesn't apply: revoked, or not_covered (this version came out after its updates_until). Null without a key, or when it applies. |
licensee | Licensee or null | The stored key's owner (even with a problem); null without a key. |
key_id | string or null | The stored key's ID, for support. |
order_reference | string or null | The order the key was sold with (the payment provider's reference), when it has one; null otherwise. |
issued_on | date or null | |
updates_until | date or null | The key covers every version released until then; Nifty keeps working after it. |
trial_ends_at | date-time | The end of the free trial, 14 days after first launch (in the past once it's ended). |
trial_days_left | integer | Whole days left in the trial, rounded up; 0 once it's ended. |
released_on | date or null | When this version was released; null in a development build. |
onboarded | boolean | The welcome has been answered (or a key added). |
updated_at | date-time | |
LicenceResponse
| Field | Type | Description |
data | Licence | |
Licences
| Field | Type | Description |
groups | object[] | In display order. |
licences | object[] | |
Licensee
| Field | Type | Description |
name | string | |
email | string | |
Me
| Field | Type | Description |
person_id | ULID or null | The owner's own person (is_me). Change the name and time zone there (PATCH /people/{id}). Null only before setup. |
name | string | The owner's person's name. |
username | string | What the owner signs in with. |
has_password | boolean | Whether the owner has a password. The desktop app's owner starts without one, so can't sign in elsewhere until one is set (PUT /password); a server's has none from setup until the welcome's Signing in step sets one. |
welcomed | boolean | Whether the owner has finished the app's welcome (POST /welcome). Until then the app shows it in place of everything else. |
time_zone | string | The owner's time zone, by its picker name, e.g. "London" or "Eastern Time (US & Canada)", for their person's time_zone. |
time_zone_iana | string | The same zone's IANA identifier, e.g. "Europe/London", for Intl and other time zone libraries. |
today | date | Today's date in the owner's time zone. |
token | ApiToken or null | The token making the request; null under session auth. |
csrf_token | string or null | Under session auth, the session's current CSRF token for X-CSRF-Token (signing in again changes it); null with a bearer token. |
two_factor | boolean | Whether sign-in asks for a code from an authenticator app (any in GET /authenticators). |
password_sign_in | boolean | Whether this server takes a password at sign-in. False on the desktop app's own server, where only the app signs in (so the password, username, authenticators and signing out don't apply). |
MeResponse
| Field | Type | Description |
data | Me | |
NiftyCalendar
The settings of My Nifty Calendar, the built-in calendar of the owner's own events. Not synced.
| Field | Type | Description |
color | string | A key from the vocabulary's colors. |
hidden_from_today | boolean | Its events stay off Today, This week and Next week (and the today tool); Calendar still shows them. |
updated_at | date-time | |
NiftyCalendarResponse
| Field | Type | Description |
data | NiftyCalendar | The settings of My Nifty Calendar, the built-in calendar of the owner's own events. Not synced. |
Note
| Field | Type | Description |
received_via_api | ReceivedViaAPI or null | How it came: through the Send to Nifty API (GET /send_api), or null. |
id | ULID | A record's ID. |
title | string or null | |
name | string | Read-only. What to call it in a list or a link, never blank. The title; without one, the body's first 60 characters (to a word, with mentions as @Name); else "Untitled note". |
title_generated | boolean | Read-only. The title was written by AI (the note_titles task), which keeps it current as the note
changes. Once a write changes or clears title, the title is the owner's and AI leaves it. |
category_id | ULID or null | |
mood | string or null | How the owner felt when writing it, a key from the vocabulary's moods; null when none. |
kind | string or null | Its type, a key from the vocabulary's note_kinds (1-to-1, meeting, journal…); null when it has none.
The owner chooses it, or a linked event gives it (one attendee besides the owner a one_to_one, more a
meeting), or AI does with the title (the note_titles task). Keys are only ever added. |
kind_source | string or null | Read-only. Who set kind: owner (a write; with kind null, the owner chose no type), event (a linked
event) or ai; null when nobody has. The owner's choice is never replaced; an event's replaces AI's. |
tag_ids | ULID[] | Read-only, sorted. The tags in the body. |
person_ids | ULID[] | Read-only, sorted. The people mentioned in the body (their order is in body_html). |
project_ids | ULID[] | Read-only, sorted. The projects referenced in the body, deleted ones excluded. |
body_html | string | See "Note bodies". "" when empty. |
body_text | string | |
pinned | boolean | Read-only; change it with POST/DELETE /notes/{id}/pin. |
pinned_at | date-time or null | Read-only. When it was pinned; null when it isn't. |
event | NoteEvent or null | Read-only (PUT/DELETE /notes/{id}/event, or event on create). The calendar event it's about; null when none. |
edit_version | integer | Read-only. Goes up by one with each edited_at change; send it with an update to detect edits made elsewhere. |
edited_at | date-time | Read-only. The last change to the title, body, category, mood or type through a write. |
created_at | date-time | |
updated_at | date-time | Also changes when a tag in the body is renamed, merged or deleted, a mentioned person or referenced project is renamed, deleted or restored, the category is deleted, AI writes the title or chooses the type, a linked event gives the type (each of which leaves edited_at and edit_version), or the note is pinned or unpinned, or its event linked or unlinked (likewise). |
NoteAnalysis
What the Note insights AI task read from a note. status: off, the task is off (or has no model) and the
note hasn't been read; too_short, the note is too short to read; not_read, it hasn't been read yet;
queued, it waits to be read (run_at: once edits settle, or now); reading, it's being read; read; or
failed, the last reading failed (error). While queued or reading, what was read before stays. stale:
the note changed since it was read. The summary and each insight's text are written by a model: render them
without HTML, links or images.
| Field | Type | Description |
status | off | too_short | not_read | queued | reading | read | failed | |
enabled | boolean | Note insights is on, with a model: the note can be read (again). |
run_at | date-time or null | When a queued reading runs. |
stale | boolean | |
read_at | date-time or null | When the insights were last read. |
model | string or null | The name of the model that read them. |
version | string or null | The version of the reading instructions. |
truncated | boolean | Only the start of a long note was sent. |
error | string or null | Why the last reading failed. |
summary | NoteAnalysisSummary or null | |
summary_removed | boolean | The owner removed the summary (DELETE /notes/{id}/summary): readings don't write one until they ask (POST /notes/{id}/analyze). |
insights | NoteInsight[] | |
NoteAnalysisResponse
| Field | Type | Description |
data | NoteAnalysis | What the Note insights AI task read from a note. status: off, the task is off (or has no model) and the
note hasn't been read; too_short, the note is too short to read; not_read, it hasn't been read yet;
queued, it waits to be read (run_at: once edits settle, or now); reading, it's being read; read; or
failed, the last reading failed (error). While queued or reading, what was read before stays. stale:
the note changed since it was read. The summary and each insight's text are written by a model: render them
without HTML, links or images. |
NoteAnalysisSummary
A long note's summary. skipped: the note is too short for one (markdown null); failed: the last try
failed (error; an earlier summary isn't kept).
| Field | Type | Description |
status | read | failed | skipped | |
markdown | string or null | Markdown bullet points. |
model | string or null | |
read_at | date-time or null | |
error | string or null | |
NoteEvent
The calendar event a note is about: one of the owner's own (entry_id) or one occurrence of a feed's
(feed_id). It stays when the event goes (deleted, gone from its feed, hidden, or its feed removed), naming
what was linked; GET /notes/{id}/event says whether it's still there.
| Field | Type | Description |
link_key | string | The event's CalendarEvent.link_key. |
entry_id | ULID or null | One of the owner's own events; null for a feed's. |
feed_id | ULID or null | The feed of a feed's event (which may have been removed since); null for an own one. |
title | string | The event's title when it was linked; blank when it had none. |
all_day | boolean | As when it was linked. |
starts_at | date-time or null | When it started, as when it was linked; null when all day. |
start_on | date | The day it started in the owner's time zone, as when it was linked. |
linked_at | date-time | |
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.
| Field | Type | Description |
entry_id optional | ULID | A record's ID. |
feed_id optional | ULID | A record's ID. |
key optional | string | The occurrence's CalendarEvent.key. |
date optional | date | |
NoteFields
A note's writable fields (NoteInput).
| Field | Type | Description |
title optional | string or null | 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. |
category_id optional | ULID or null | An unknown id is a 422 on category_id. |
mood optional | string or null | A key from the vocabulary's moods; null clears it. Anything else is a 422 on mood. |
kind optional | string or null | 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. |
body_html optional | string or null | See "Note bodies". Null or "" clears it. |
edit_version optional | integer | 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. |
event optional | NoteEventInput | 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. |
NoteInsight
One thing the note says that's worth remembering, resting on the words in quote (the note holds them).
Dates are the owner's days: when it happens (event_on, to event_until), and when it's worth raising again
(check_on). lifespan: lasting (a fact), until_date (it matters until its dates pass) or fades (current
context). An insight keeps its id and first_seen_at while later readings find it again (the same kind and
quote). The owner's corrections (not_right, their wording, links added or removed) stay with it through
later readings. One marked not_right is wrong: apart from checking insights, nothing should use it.
| Field | Type | Description |
id | integer | Local to this install. |
kind | string | A key from the vocabulary's insight_kinds. |
text | string | One sentence; "you" is the owner. |
quote | string | |
open | boolean | Still to be done |
event_on | date or null | |
event_until | date or null | |
check_on | date or null | |
lifespan | lasting | until_date | fades | |
first_seen_at | date-time | |
not_right | boolean | The owner marked it as not right. |
edited | boolean | text is the owner's wording. |
subjects | NoteInsightSubject[] | |
NoteInsightChoice
A person an unmatched name could be.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
NoteInsightSubject
What an insight is about: a person, project, task or company (id; null once it's gone for good), the note's
event, or a name Nifty couldn't match to anyone. name is the record's current name, else the name it had.
A name that could be several people lists them in choices and isn't matched. A task is either what the
insight is about (about) or the same promise (same). matched_by says how Nifty found the record in the
note, for checking its matching: me, mention, attendee, full_name, email, alias, first_name,
shared_first_name, task, project_mention, name, position, linked, event, or owner for a link the
owner added (more may come).
| Field | Type | Description |
type | person | project | task | company | event | name | |
id | ULID or null | |
name | string | |
deleted | boolean | The record has been deleted. |
task_relation | about | same | null | |
matched_by | string or null | |
choices | NoteInsightChoice[] | |
NoteResponse
| Field | Type | Description |
data | Note | |
NoteSummary
A note in a list (GET /notes?fields=summary). As Note, without body_html, body_text and event.
| Field | Type | Description |
id | ULID | A record's ID. |
title | string or null | |
name | string | As Note's. |
title_generated | boolean | As Note's. |
category_id | ULID or null | |
mood | string or null | As Note's. |
kind | string or null | As Note's. |
kind_source | string or null | As Note's. |
tag_ids | ULID[] | As Note's. |
person_ids | ULID[] | As Note's. |
project_ids | ULID[] | As Note's. |
excerpt | string | The body as one line (mentions "@Name", tags "#name", references "^Name", images left out), at most 240 characters, cut at a word with "...". "" when empty. |
image_count | integer | The images in the body. |
pinned | boolean | As Note's. |
pinned_at | date-time or null | As Note's. |
edit_version | integer | As Note's. |
edited_at | date-time | As Note's. |
created_at | date-time | |
updated_at | date-time | As Note's. |
Now
| Field | Type | Description |
task | Task | Embeds no other record's data (only ids), so renaming a list changes no task. Renaming a person, project or
tag named in the description gives it a new updated_at (description_text changes), as does deleting or
restoring its home (it leaves and rejoins the listings, with a deletion record), the expiry archiving it, another
task's move renumbering it, a document being linked or unlinked, or deleted, restored or purged while linked
(has_documents, document_ids), or a note being attached or detached, or deleted or restored while attached (note_ids). |
since | date-time | |
stops_at | date-time or null | When it will stop by itself, if nothing else stops it first. |
NowResponse
| Field | Type | Description |
data | Now or null | |
NowStopTimes
Times of day (HH:MM, the owner's time zone) at which Now stops by itself, earliest first. No duplicates (a 422).
string[]
| Field | Type | Description |
next_cursor | string or null | Pass as cursor for the next page; null on the last page. |
limit | integer | |
total_count optional | integer | Only with count=true. Every record in the filtered set, on every page. |
PeopleArrange
How People lays out faces: A to Z (az, the default) or under how they relate to you (groups).
az | groups
PeopleShow
Which of People's groups shows: all (the default), a relationship_groups key from the vocabulary, or others, everyone in none.
string
Person
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
aliases | string[] | Other names you call them by ("Mum", "Spud"), in the order given. Search and mentions find them by these too. |
is_me | boolean | Read-only. Whether this is you, the owner. Exactly one person is. |
time_zone | string or null | Their time zone, an IANA zone from the time zone list (Europe/London). Null: yours. Yours is always
set, and is the app's: it decides "today". |
avatar | Avatar or null | |
key_dates | KeyDate[] | |
email_addresses | EmailAddress[] | |
phone_numbers | PhoneNumber[] | |
social_profiles | SocialProfile[] | |
positions | Position[] | Their jobs, in the order added. Change them with the person's PATCH; company_id names a /companies record. |
connections | Connection[] | Read-only. Their links to other people, by link id. Change them through /person_links. |
created_at | date-time | |
updated_at | date-time | Also changes when a key date, a contact detail, a position, the photo or a connection changes. |
PersonFields
A person's writable fields (PersonInput). Each array follows the rules on PATCH. A social
profile's platform equal to the one currently detected for it is no change, so a GET sent back as a
PATCH keeps it detected.
| Field | Type | Description |
name optional | string | |
aliases optional | string[] | Replaces their aliases. Spaces are squished; blank ones, and repeats ignoring case and accents, are dropped.
More than 10 is a 422 on aliases; one over 50 characters, or with a comma, a 422 on aliases[i]. Anything
but an array of strings (null among them) is a 400. |
avatar optional | string or null | The photo, saved with the rest: an upload's signed_id from POST /uploads, or null to remove it. Omitted
keeps it. Only an upload nothing uses yet is accepted; any other signed id (e.g. a note's image, or an
unknown one) is a 422 on avatar, "isn’t a new upload". The photo rules apply (a JPEG, PNG, WebP or GIF
of 10 MB or less). Anything but a string or null is a 400. A replaced or removed photo is deleted. |
time_zone optional | string or null | An IANA zone from the time zone list (Europe/London), or null for none. Anything else is a 422, as is
null for you (is_me). |
key_dates optional | object[] | A new row needs kind, day and month; the year is optional (1900 to this year, not in the future).
label is required for other. A new row with no day, month, year or label is ignored. At most one
birthday: to make another existing row the birthday, change the old birthday to another kind in an
earlier request (in one request it can be refused, depending on the rows' order). |
email_addresses optional | object[] | |
phone_numbers optional | object[] | |
social_profiles optional | object[] | |
positions optional | object[] | A row with id changes it, one without adds, _destroy removes. Each needs a title or a company (a new row
with neither is a 422 on title). The company changes when company_id or company_name is sent: company_id
names a /companies record (an unknown one is a 422), company_name finds a company ignoring case or adds
it, and null or a blank name clears it. Sending both non-null is a 422 on company_name. A company no
position names any more is deleted (it appears in /deletions). An id sent twice in one request is a 422 on
the later row. |
PersonLink
"person_id is related_person_id's kind". Always stored one way: kind is a forward or
symmetric role (parent, never child), and a symmetric link has the lower id in person_id.
Creating, changing or removing a link also changes both people's updated_at.
| Field | Type | Description |
id | ULID | A record's ID. |
person_id | ULID | A record's ID. |
kind | PersonLinkRole | A role in a person link. Each inverse follows its forward role; the rest are symmetric. |
related_person_id | ULID | A record's ID. |
note | string or null | |
created_at | date-time | |
updated_at | date-time | |
PersonLinkResponse
| Field | Type | Description |
data | PersonLink | "person_id is related_person_id's kind". Always stored one way: kind is a forward or
symmetric role (parent, never child), and a symmetric link has the lower id in person_id.
Creating, changing or removing a link also changes both people's updated_at. |
PersonLinkRole
A role in a person link. Each inverse follows its forward role; the rest are symmetric.
spouse | partner | ex_partner | sibling | step_sibling | cousin | sibling_in_law | parent | child | step_parent | step_child | guardian | ward | grandparent | grandchild | aunt_uncle | niece_nephew | parent_in_law | child_in_law | godparent | godchild | friend | acquaintance | housemate | neighbour | introduced | introduced_by | coworker | business_partner | manager | report | mentor | mentee | teacher | student | employer | employee | client | supplier | landlord | tenant
PersonResponse
| Field | Type | Description |
data | Person | |
PersonSummary
A person's name and photo, where a list shows them; GET /people/{id} has the rest.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
avatar | Avatar or null | |
PhoneNumber
| Field | Type | Description |
id | ULID | A record's ID. |
number | string | As typed. |
label | string or null | |
created_at | date-time | |
updated_at | date-time | |
Plus
| Field | Type | Description |
state | not_connected | connected | moved | copied | not_connected: never connected, or disconnected here. connected: linked to a subscription. moved: Plus was moved to another install. copied: this install's data was found in two places, so the account service disconnected both; connect again. |
available | boolean | Plus features can be used now. Connected, the subscription active or past due, and Nifty not read-only. |
unavailable_reason | not_connected | inactive | read_only | null | Why available is false: not_connected (any state but connected), inactive (the subscription isn't active), or read_only (Nifty is read-only; the subscription is still charged). Null when available. |
install_name | string or null | The name this install has on the account (for example “Nifty on Ada's MacBook”); null when not connected. |
account_url | uri | The account page's way to a code: sign in, subscribe, and get a code to connect with. |
account | PlusAccount or null | The account and subscription as last checked; null unless connected. |
error | unreachable | null | The last problem: unreachable (the account service couldn't be reached at the last check; the rest is as last known). Null when none. |
checked_at | date-time or null | When the account service last answered. |
PlusAccount
| Field | Type | Description |
email | string | |
status | active | past_due | inactive | active. past_due: a payment failed and Stripe is retrying; Plus still works. inactive: no current subscription. |
plan | PlusPlan or null | |
period_end | date-time or null | When the current period ends; the subscription renews then unless cancel_at_period_end. |
cancel_at_period_end | boolean | |
PlusPlan
monthly or yearly.
monthly | yearly
PlusResponse
| Field | Type | Description |
data | Plus | |
Position
A job title, a company, or both (never neither). Synced; destroying one records a position deletion.
| Field | Type | Description |
id | ULID | A record's ID. |
title | string or null | |
company_id | ULID or null | A /companies record; its name comes from there. |
created_at | date-time | |
updated_at | date-time | |
Project
Members, role changes and member removals change the project's updated_at, as does a member's person being deleted or restored.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | Unique among projects, ignoring case. |
status | ProjectStatus | planned, active and on_hold are open; done and cancelled are closed. |
status_changed_at | date-time or null | When the status last changed (its latest status event); null if no change is recorded. |
start_date | date or null | |
deadline | date or null | |
external_reference | string or null | |
external_url | uri or null | An http or https link. |
description_html | string | Text-only HTML (no attachments), sanitised as notes are. "" when empty. |
description_text | string | |
cover | Cover or null | The project's header. Every project has one; null only when its photo's upload is missing. |
members | object[] | Read-only, by id. The project's members who aren't deleted people, you (is_me) among them when you're on it, with your role; write them through /project_members. |
pinned | boolean | Pinned for quick access. Set through /projects/{id}/pin. |
pinned_at | date-time or null | When it was pinned (the menu's order); null when it isn't. |
created_at | date-time | |
updated_at | date-time | |
ProjectActivity
One entry of a project's activity. The record named by kind is set; the others are absent.
| Field | Type | Description |
kind | note | task | task_change | document | event | created | |
at | date-time | A note's created_at, a task's completed_at, when a task was added or removed, when a document was linked, an event's created_at, or the project's created_at. |
note optional | NoteSummary | A note in a list (GET /notes?fields=summary). As Note, without body_html, body_text and event. |
task optional | Task | Embeds no other record's data (only ids), so renaming a list changes no task. Renaming a person, project or
tag named in the description gives it a new updated_at (description_text changes), as does deleting or
restoring its home (it leaves and rejoins the listings, with a deletion record), the expiry archiving it, another
task's move renumbering it, a document being linked or unlinked, or deleted, restored or purged while linked
(has_documents, document_ids), or a note being attached or detached, or deleted or restored while attached (note_ids). |
task_change optional | ProjectTaskChange | A task added to the project (made there, moved in, or restored) or removed from it (moved out, or deleted). A
change reversed within 10 minutes (a delete undone, a slip) is dropped instead of recorded. |
document optional | Document | A PDF, an image (kind: image: a screenshot or a photo, its text read by OCR), or an email (kind: email,
POST /email_imports) with its PDF attachments inside it. Synced; deleting
one records a document deletion. Embeds no other record's data, only ids, so renaming a folder or a linked
record changes no document. Linking or unlinking it, deleting or restoring a record it's linked to (or a list,
person or project hiding a linked task), and deleting its folder while it's deleted give it a new
updated_at. Notes, projects, tasks and people don't list their documents: filter GET /documents. |
event optional | ProjectEvent | A change to a project, never edited: updated_at is created_at until restoring its project (or a member event's person) gives it a new one. status: from and to are statuses.
deadline: dates, from null when one was set and to null when it was removed. member_added and
member_removed: person_id, and for member_added the role they were added with; from and to null. |
ProjectEvent
A change to a project, never edited: updated_at is created_at until restoring its project (or a member event's person) gives it a new one. status: from and to are statuses.
deadline: dates, from null when one was set and to null when it was removed. member_added and
member_removed: person_id, and for member_added the role they were added with; from and to null.
| Field | Type | Description |
id | ULID | A record's ID. |
project_id | ULID | A record's ID. |
kind | status | deadline | member_added | member_removed | |
from | string or null | A status key or a date (YYYY-MM-DD). |
to | string or null | A status key or a date (YYYY-MM-DD). |
person_id | ULID or null | |
role | string or null | |
created_at | date-time | |
updated_at | date-time | |
ProjectLastActivity
| Field | Type | Description |
project_id | ULID | A record's ID. |
last_activity_at | date-time | |
ProjectMember
A person on a project, once each. Synced; removing one records a project_member deletion.
| Field | Type | Description |
id | ULID | A record's ID. |
project_id | ULID | A record's ID. |
person_id | ULID | A record's ID. |
role | string or null | |
created_at | date-time | |
updated_at | date-time | |
ProjectMemberResponse
| Field | Type | Description |
data | ProjectMember | A person on a project, once each. Synced; removing one records a project_member deletion. |
ProjectResponse
| Field | Type | Description |
data | Project | Members, role changes and member removals change the project's updated_at, as does a member's person being deleted or restored. |
ProjectsOrder
How Projects orders its sections: by deadline (the default), name, or newest first by when each was created or its latest activity.
deadline | name | created | activity
ProjectStatus
planned, active and on_hold are open; done and cancelled are closed.
planned | active | on_hold | done | cancelled
ProjectTaskChange
A task added to the project (made there, moved in, or restored) or removed from it (moved out, or deleted). A
change reversed within 10 minutes (a delete undone, a slip) is dropped instead of recorded.
| Field | Type | Description |
id | ULID | A record's ID. |
change | added | removed | |
task_id | ULID | A record's ID. |
title | string | The task's title at the time. |
ProjectTaskCount
| Field | Type | Description |
project_id | ULID | A record's ID. |
open | integer | |
completed | integer | |
next_task | object or null | |
ProjectWrite
| Field | Type | Description |
name optional | string | Spaces are squished. A name another project has, ignoring case, is a 422. |
status optional | ProjectStatus | planned, active and on_hold are open; done and cancelled are closed. |
start_date optional | date or null | YYYY-MM-DD. One that isn't a date is a 422. |
deadline optional | date or null | YYYY-MM-DD; not before start_date (a 422). |
external_reference optional | string or null | Spaces are squished; blank is null. |
external_url optional | string or null | http or https, with a host; without a scheme, https:// is added. Blank is null. |
description_html optional | string or null | HTML, sanitised as note bodies are. Attachments and images are dropped. A NUL or more than 1 MB is a 422. Null or "" clears it. |
cover optional | CoverWrite | A cover to set. Every project wears one, so null is a 422 on cover. Kind color needs a color; kind
photo keeps the photo the cover has (upload a new one with PUT /projects/{id}/cover_photo), so it's for
moving position. An unknown colour, a photo when there's none, or a position out of range is a 422 on
cover.<field>. A project created without one gets one of the colours its projects use least, at random. A
photo a colour replaces is deleted. |
ReceivedViaAPI
A record the Send to Nifty API added (GET /send_api), shown in its details as "Received".
| Field | Type | Description |
at | date-time | When it reached Nifty Plus. |
source | string or null | The sender's label for itself, if it gave one. |
RelationshipKey
Deprecated: how someone relates to you is now a person link to you. A role someone can have to you: any person
link role except introduced and introduced_by (an introduction needs a third person), seen from your side
("Ada is your mentee"). The family ones are spouse to godchild.
spouse | partner | ex_partner | sibling | step_sibling | cousin | sibling_in_law | parent | child | step_parent | step_child | guardian | ward | grandparent | grandchild | aunt_uncle | niece_nephew | parent_in_law | child_in_law | godparent | godchild | friend | acquaintance | housemate | neighbour | coworker | business_partner | manager | report | mentor | mentee | teacher | student | employer | employee | client | supplier | landlord | tenant
RelationshipTypes
| Field | Type | Description |
relationships | object[] | |
person_links | object[] | |
key_date_kinds | object[] | A key date's kinds, in display order. |
social_platforms | object[] | A social profile's platforms, in display order. |
RuleTypeKey
A key from event_types, or null for No type (Nifty's own rules then don't type the event). Null on create unless sent.
string or null
SearchGroup
| Field | Type | Description |
type | person | project | note | task | event | document | task_list | folder | company | |
results | SearchResult[] | Best match first. |
has_more | boolean | There are more matches than limit. |
SearchLeadingAvatar
A search result's person photo.
| Field | Type | Description |
type | "avatar" | |
url | uri or null | |
SearchLeadingIcon
A search result's Lucide icon.
| Field | Type | Description |
type | "icon" | |
name | string | |
SearchLeadingSwatch
A search result's colour swatch.
| Field | Type | Description |
type | "swatch" | |
color | string or null | A colour key, e.g. "jade". |
SearchResult
| Field | Type | Description |
id | string | The person's, project's, note's, task's, document's, task list's, folder's or company's id (a ULID); an event's key. |
title | string or null | A person's, project's, document's, task list's or folder's name, a note's title (null for an untitled note), a task's or event's title. |
subtitle | string or null | Null for a person. For a project, its status and, if it's open with a deadline, when it's due in the
owner's time zone ("Active · due today", "Active · due tomorrow", "Active · due 12 Nov", "On hold · overdue",
"Done"). For a note, the start of its text (at most 120 characters). For an open task, its home (a list's,
person's or project's name, or "Inbox") and, with a deadline, when it's due ("Errands · due Friday", "Inbox ·
overdue by 2 days"); for a closed one, how and when it closed in the owner's time zone ("Completed 3 Oct",
"Expired 3 Oct", "Won’t do 3 Oct"). For a document, its folder's path ("Home › Insurance"), "Unsorted" when
it has no folder and no links, or null. For a task list, "List". For a folder, "Folder" at the top level,
else "Folder · " and its parent's path ("Folder · Home › Insurance"). For an event, its day in the owner's
time zone (with the year unless it's this year's), its times or "All day", and its calendar's name ("Tue 7
Oct · 10:00–11:00 · Work"); an event with no title is titled "(No title)". With scope=link, a note's and
document's are as described there. |
event optional | CalendarEvent | An event's occurrence, as GET /calendar gives it; absent for other types. |
leading | SearchLeadingAvatar or SearchLeadingSwatch or SearchLeadingIcon | What the omnibar shows before the title: a person's photo (url is its thumbnail, or null without one), a
colour swatch (a note's category colour, null without a category; a task list's, folder's or event's calendar's colour) or a
Lucide icon by name (projects, tasks, documents). |
SendAPI
| Field | Type | Description |
available | boolean | Plus is available (GET /plus): deposits are accepted, and a token can be made. |
unavailable_reason | not_connected | inactive | read_only | null | As GET /plus's. Items that arrived before the subscription ended are still collected while inactive. |
url | string or null | Where the API is, for the help's examples; null until the service has said. |
tokens | SendAPIToken[] | The tokens, oldest first, without the tokens themselves (shown only when each is made): as the service last listed them. |
waiting | integer | Items waiting to be collected at the last check. |
error | unreachable | null | unreachable: the service couldn't be reached at the last check; the rest is as last known. |
checked_at | date-time or null | When the service last answered. |
collected_at | date-time or null | When an item was last collected. |
skipped | integer | Items Nifty couldn't add (one failing its checks, or failing 3 times over an hour), since last dismissed. |
lost | integer | Items let go because they were sealed for another copy of Nifty (before Plus moved here), since last dismissed. |
expired | integer | Items not collected within 7 days, since last dismissed. |
SendAPIResponse
| Field | Type | Description |
data | SendAPI | |
SendAPIToken
| Field | Type | Description |
id | string | |
name | string | |
ending | string | The token's last four characters. |
created_at | date-time | |
last_used_at | date-time or null | When it was last used, to the hour; null if never. |
SocialProfile
| Field | Type | Description |
id | ULID | A record's ID. |
url | uri | |
platform | website | linkedin | instagram | facebook | x | bluesky | mastodon | threads | github | youtube | tiktok | other | |
platform_detected | boolean | True when platform was worked out from the link rather than chosen. |
label | string or null | |
created_at | date-time | |
updated_at | date-time | |
Sounds
| Field | Type | Description |
on | boolean | Whether any sound plays. On by default. |
volume | SoundVolume | How loud every sound plays, as a percentage. 100, the default, is full volume. |
task_completed | TaskCompletedSound | Played when a task is ticked off. tap_trio is the default; none is silent. |
created | CreatedSound | Played when a task, person or project is created. blip_blip is the default; none is silent. |
deleted | DeletedSound | Played when something is deleted, removed, revoked or disconnected. paper_away is the default; none is silent. |
calendar_alert | CalendarAlertSound | For calendar alerts. music_box is the default; none is silent. |
updated_at | date-time | When the owner record last changed. |
SoundsResponse
| Field | Type | Description |
data | Sounds | |
SoundVolume
How loud every sound plays, as a percentage. 100, the default, is full volume.
integer
SuggestedPerson
| Field | Type | Description |
person_id | ULID | A record's ID. |
person_name | string | The person's name when it was suggested. |
email | string or null | Their email address the text holds; null when it names them instead. |
Suggestion
A person a document names: their full name or an email address of theirs is in its text (found without AI). The
owner accepts it by linking the document to the person (POST /document_links, however it's linked), or
declines it. Synced; one withdrawn (the document read again no longer names them, or the person was deleted) or
purged (its document or person purged) records a suggestion deletion.
| Field | Type | Description |
id | ULID | A record's ID. |
kind | person | |
status | pending | accepted | declined | |
source | SuggestionSource | |
title | string | The person's name when it was suggested. |
person | SuggestedPerson | |
result_id | ULID or null | The document link accepting it made; null until accepted. |
decided_at | date-time or null | When it was accepted or declined. |
created_at | date-time | |
updated_at | date-time | |
SuggestionResponse
| Field | Type | Description |
data | Suggestion | A person a document names: their full name or an email address of theirs is in its text (found without AI). The
owner accepts it by linking the document to the person (POST /document_links, however it's linked), or
declines it. Synced; one withdrawn (the document read again no longer names them, or the person was deleted) or
purged (its document or person purged) records a suggestion deletion. |
SuggestionSource
| Field | Type | Description |
type | document | |
id | ULID | A record's ID. |
title | string or null | The document's name; null once it's gone. |
System
| Field | Type | Description |
version | string | The running version; dev in a development build. |
channel | UpdateChannel | stable (the default) gets stable releases; beta gets betas too, and stable releases newer than them. |
update_checks | boolean | Whether it checks daily (the owner's setting; false when managed). |
update_checks_managed | boolean | Updates come from elsewhere (the desktop app, a package manager: --update-checks=off), so update_checks can't change. |
update_checks_managed_by | desktop | null | Who manages updates: desktop when this is the desktop app's own server (--desktop-secret-stdin), whose updates come with the app; null otherwise. |
error_reports | boolean | Errors and crashes are reported, with no user data (the owner's setting, default false; true on a beta). A development build never sends any, whatever this says. |
error_reports_forced | boolean | This is a beta, which always sends error reports, so error_reports is true and can't change. |
plain_http | boolean | It's reachable beyond this machine over plain http (no TLS). |
update | SystemUpdate | |
SystemResponse
| Field | Type | Description |
data | System | |
SystemUpdate
| Field | Type | Description |
status | up_to_date | available | not_covered | unknown | off | not_covered: a newer release is out but this install's licence doesn't cover it (not_covered_reason), so it isn't offered. |
not_covered_reason | updates_ended | null | With not_covered: updates_ended when the release came out after the licence's updates_until. Null otherwise. Revocation doesn't withhold updates: each release refuses the keys it lists (the licence's problem). |
latest_released_on | date or null | When latest_version was released; null before any check. |
can_check | boolean | This build can check (it has a release signing key and a release version) and checks aren't managed. |
latest_version | string or null | The channel's newest release at the last successful check; null before any check, or when the channel has no release yet (up_to_date). |
notes_url | uri or null | latest_version's What's new page in the public help (a beta's on beta.help.thenifty.app). |
checked_at | date-time or null | The last check's time, successful or not. |
dismissed | boolean | dismissed_version is at least latest_version. |
error | string or null | Why the last check failed; null after a successful one. |
Tag
Shown with a leading #. The name keeps its casing; matching ignores case.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | No whitespace. |
created_at | date-time | |
updated_at | date-time | |
TagResponse
| Field | Type | Description |
data | Tag | Shown with a leading #. The name keeps its casing; matching ignores case. |
Task
Embeds no other record's data (only ids), so renaming a list changes no task. Renaming a person, project or
tag named in the description gives it a new updated_at (description_text changes), as does deleting or
restoring its home (it leaves and rejoins the listings, with a deletion record), the expiry archiving it, another
task's move renumbering it, a document being linked or unlinked, or deleted, restored or purged while linked
(has_documents, document_ids), or a note being attached or detached, or deleted or restored while attached (note_ids).
| Field | Type | Description |
planned_start_on | date or null | The start it was first planned for: its first start_on, settled ten minutes after it was set, then fixed.
Null until it has a start. Tasks made before this was kept have the start they had then. |
delays | integer | How many times it's been put off (GET /tasks/{id}/history): its start moved later or was cleared, or was
first set to a later day while it was due or overdue. Changes within ten minutes of its creation aren't kept; those
within ten minutes of a kept change's first time count once with it, and one that undoes it doesn't count. |
deadline_moves | integer | How many times its deadline has moved later or been cleared, counted as delays is. |
delegated_at | date-time or null | When it was delegated to assignee_id; null when it isn't, or was delegated before this was kept. |
now_since | date-time or null | When the owner started working on it, while it's Now (GET /now); null otherwise. At most one task is Now. |
received_via_api | ReceivedViaAPI or null | How it came: through the Send to Nifty API (GET /send_api), or null. |
id | ULID | A record's ID. |
title | string | |
status | TaskStatus | archived is "Won't do", or expired: archived when its expires_on has passed. |
start_on | date or null | |
deadline_on | date or null | |
expires_on | date or null | |
completed_at | date-time or null | Set while completed. |
archived_at | date-time or null | Set while archived. It expired (rather than "Won't do") when this is the owner's midnight after expires_on. |
task_list_id | ULID or null | The home: at most one of task_list_id and project_id; neither is the Inbox. |
project_id | ULID or null | |
assignee_id | ULID or null | The person it's delegated to (never Me); null: the owner's own. A delegated task stays in its list or
project, but leaves the Inbox and the smart views but delegated and logbook. While the person is deleted
(undo) it's null and the task is the owner's again; their restore puts it back, and their purge clears it,
each with a new updated_at. |
position | integer | Its home's custom order: sort by position, then id. Closed tasks keep theirs. Gaps and ties are possible, and it may be zero or negative. |
description_html | string | See "Note bodies" (no images). "" when empty. |
description_text | string | |
has_documents | boolean | A live document is linked to it (GET /documents?task_id=). |
document_ids | ULID[] | The live documents linked to it, oldest link first (GET /tasks?document_id= lists a document's tasks). |
note_ids | ULID[] | The live notes it's attached to, oldest attachment first (GET /tasks?note_id= lists a note's tasks). |
expired | boolean | Archived by its expiry rather than by hand ("Won't do"), in the owner's time zone. |
created_at | date-time | |
updated_at | date-time | |
TaskCompletedSound
Played when a task is ticked off. tap_trio is the default; none is silent.
pop_in | tap_up | double_pop | tap_trio | sparkle | none
TaskCounts
| Field | Type | Description |
inbox | integer | In the Inbox with no start date (view=inbox). |
today | integer | Started today or earlier, the Inbox too (view=today). |
today_queue | integer | Today's queue: started, or with no start and a deadline (view=today_queue). The Tasks section's Today lists it. |
due_soon | integer | Overdue or due within 14 days (view=due_soon). |
overdue | integer | Due before today |
delegated | integer | Delegated to someone (view=delegated). |
task_lists | object[] | Every live list, by position, with its open tasks (delegated ones too). |
page optional | object | Only when a page is named. Its keys, in the order the page shows them (labels and icons in the vocabulary's
task_count_kinds): inbox, upcoming: open. today: open, completed_today.
logbook: completed, wont_do, expired. One home: open, completed (all-time). |
TaskDateChange
One saved change to a task's start or deadline (GET /tasks/{id}/history). Each date's from and to are null when it had none.
| Field | Type | Description |
id | integer | |
at | date-time | When the change was first made. |
start_changed | boolean | |
start_from | date or null | |
start_to | date or null | |
deadline_changed | boolean | |
deadline_from | date or null | |
deadline_to | date or null | |
delay | boolean | It put the task off: one of delays. |
deadline_moved | boolean | It moved the deadline later or cleared it: one of deadline_moves. |
TaskHistoryResponse
| Field | Type | Description |
data | TaskDateChange[] | |
meta | any | |
TaskList
One of a task's homes. Synced; deleting one records task_list and task deletions.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | Unique among lists, ignoring case. |
color | string | A palette key from GET /category_choices (e.g. amber). |
icon | string or null | A Lucide icon name, or null for the default list icon. May be one no longer in the picker. |
position | integer | A sort key: order by position, then id. Gaps are possible after a delete. |
created_at | date-time | |
updated_at | date-time | |
TaskListResponse
| Field | Type | Description |
data | TaskList | One of a task's homes. Synced; deleting one records task_list and task deletions. |
TaskOrder
How a task page orders its tasks: grouped by deadline (the default) or by start date, or the home's own order (custom).
deadline | start | custom
TaskResponse
| Field | Type | Description |
data | Task | Embeds no other record's data (only ids), so renaming a list changes no task. Renaming a person, project or
tag named in the description gives it a new updated_at (description_text changes), as does deleting or
restoring its home (it leaves and rejoins the listings, with a deletion record), the expiry archiving it, another
task's move renumbering it, a document being linked or unlinked, or deleted, restored or purged while linked
(has_documents, document_ids), or a note being attached or detached, or deleted or restored while attached (note_ids). |
TaskSettings
| Field | Type | Description |
now_stop_times | NowStopTimes | Times of day (HH:MM, the owner's time zone) at which Now stops by itself, earliest first. No duplicates (a 422). |
TaskSettingsResponse
| Field | Type | Description |
data | TaskSettings | |
TaskStatus
archived is "Won't do", or expired: archived when its expires_on has passed.
open | completed | archived
TaskWrite
A 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.
| Field | Type | Description |
title optional | string | Spaces are squished. |
description_html optional | string or null | See "Note bodies": mentions, tags and project references by id. An image (signed-id) is a 422 on description. Null or "" clears it. |
start_on optional | date or null | YYYY-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. |
deadline_on optional | date or null | YYYY-MM-DD. It may be before start_on: the task will be late. A later deadline, or clearing it, counts in deadline_moves. |
expires_on optional | date or null | Not 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. |
status optional | TaskStatus | Any 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_list_id optional | ULID or null | The home. Sending one home id clears the other; both null is the Inbox. |
project_id optional | ULID or null | |
assignee_id optional | ULID or null | Delegates 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. |
position optional | integer | 1-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. |
before_task_id optional | ULID or null | Instead 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. |
document_ids optional | ULID[] or null | The 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. |
document_uploads optional | string[] or null | signed_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. |
note_ids optional | ULID[] or null | The 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. |
TextSize
The interface's text size; medium is the default.
small | medium | large
Theme
system follows the device's light or dark setting. The default.
system | light | dark
Today
| Field | Type | Description |
date | date | Today in the owner's time zone. |
tasks_today | integer | Open, started today or earlier (view=today). |
tasks_due_not_today | integer | Overdue or due within 14 days, not in today's (view=due_not_today). |
tasks_inbox | integer | Open in the Inbox. |
key_dates_in_fortnight | integer | Live people's key dates falling from today to day 14. |
deadlines_in_fortnight | integer | Open projects due from today to day 14. |
overdue_deadlines | integer | Open projects due before today. |
notes_this_week | integer | Notes edited since the start of six days ago. |
pinned_notes | integer | |
ULID
A record's ID.
string
UnsplashCredit
Unsplash's attribution: "Photo by ‹name› on Unsplash", each linked. The links carry Unsplash's referral tags.
| Field | Type | Description |
name | string | The photographer's name. |
profile_url | uri | The photographer's Unsplash page. |
photo_url | uri | The photo's Unsplash page. |
UnsplashPhoto
| Field | Type | Description |
id | string | |
alt | string | Unsplash's description, for alt text; may be blank. |
width | integer | |
height | integer | |
color | string | The photo's main colour, #rrggbb: a placeholder while it loads. |
blur_hash | string or null | |
thumb_url | uri | About 400px wide, on images.unsplash.com. |
preview_url | uri | About 1080px wide, on images.unsplash.com. |
credit | UnsplashCredit | Unsplash's attribution: "Photo by ‹name› on Unsplash", each linked. The links carry Unsplash's referral tags. |
UnsplashPhotosResponse
| Field | Type | Description |
data | UnsplashPhoto[] | |
meta | object | |
UpcomingDeadline
| Field | Type | Description |
date | date | The project's deadline. |
overdue | boolean | The deadline is before today. |
project | Project | Members, role changes and member removals change the project's updated_at, as does a member's person being deleted or restored. |
UpcomingKeyDate
| Field | Type | Description |
date | date | |
years | integer or null | The years it marks (the age a birthday turns). Null without a year, or on the first one. |
key_date | KeyDate | A date that comes round every year. Synced; destroying one records a key_date deletion. |
person | PersonSummary | A person's name and photo, where a list shows them; GET /people/{id} has the rest. |
UpdateChannel
stable (the default) gets stable releases; beta gets betas too, and stable releases newer than them.
stable | beta
Upload
| Field | Type | Description |
signed_id | string | The signed-id to embed in a note body, or send in a task's document_uploads. |
url | uri | Absolute; redirects to the file. Anyone with the link can load it. |
filename | string | |
content_type | image/jpeg | image/png | image/webp | image/gif | application/pdf | |
byte_size | integer | |
width | integer or null | Null for a PDF. |
height | integer or null | |
UploadLimit
| Field | Type | Description |
content_types | string[] | |
max_bytes | integer | |
ViewPlace
One place's choices, each left out while it's the default. The place keys, and what each offers:
| Place |
task_order |
completed_open |
library_sort |
today, delegated |
deadline, start |
|
|
inbox |
|
yes |
|
today_also (Today's Also open) |
|
yes |
|
task_list:<id>, project:<id> |
deadline, start, custom |
yes |
|
person:<id> (their Tasks tab) |
deadline, start |
yes |
|
library, library:unsorted, library:all (All files), folder:<id> |
|
|
yes |
A place's choices stay until it's deleted for good (after its undo window). At most 2,000 places have choices
at once: a change adding places past that is a 422 on places.
| Field | Type | Description |
task_order optional | TaskOrder | How a task page orders its tasks: grouped by deadline (the default) or by start date, or the home's own order (custom). |
completed_open optional | boolean | Whether its folded section (a home's Completed, Today's Also open) is open: only ever true here, as closed is the default. |
library_sort optional | LibrarySort | How a Library place sorts. By name, A to Z, is the default. |
Views
| Field | Type | Description |
wide_text | boolean | View → Wide text: long text wider than its comfortable measure. Off by default. |
projects_order | ProjectsOrder | How Projects orders its sections: by deadline (the default), name, or newest first by when each was created or its latest activity. |
people_arrange | PeopleArrange | How People lays out faces: A to Z (az, the default) or under how they relate to you (groups). |
people_show | PeopleShow | Which of People's groups shows: all (the default), a relationship_groups key from the vocabulary, or others, everyone in none. |
calendar_view | CalendarView | The view the Calendar opens in: day (the default) or week. |
hidden_calendars | HiddenCalendars | What the Calendar and Today's Meeting leave out: calendar feeds by id, nifty (My Nifty Calendar) and the kinds of Nifty's own dates (tasks, project_dates, key_dates). Sorted. None by default. |
places | object | Each place's own choices, by place key; only the places with a choice other than its default. |
ViewsResponse
| Field | Type | Description |
data | Views | |
Vocabulary
relationships, person_links, key_date_kinds and social_platforms are as in RelationshipTypes.
any
Webhook
An address Nifty sends signed events to. This server's own; not synced.
| Field | Type | Description |
id | ULID | A record's ID. |
name | string | |
url | string | |
events | WebhookEvent[] | In the vocabulary's order. |
enabled | boolean | |
last_delivery | WebhookDelivery or null | Its newest delivery, test ones included; null before the first. |
created_at | date-time | |
updated_at | date-time | |
WebhookCreated
any
WebhookCreatedResponse
| Field | Type | Description |
data | WebhookCreated | |
WebhookDelivery
One event sent, or about to be.
| Field | Type | Description |
id | ULID | A record's ID. |
event | task.created | task.completed | task.deadline_changed | task.start_changed | task.expired | document.uploaded | document.summarized | person.created | note.saved | test | |
outcome | pending | succeeded | failed | succeeded is a 2xx reply. The words are the vocabulary's webhook_outcomes. |
http_status | integer or null | The reply's status |
error | string or null | Why it failed, as a sentence ("The address didn't answer within 10 seconds."); null when it succeeded or is pending. |
duration_ms | integer or null | How long the request took. |
payload | WebhookPayload | The JSON body sent. data holds the event's record under its kind (task, document, person or note); it's empty for test. |
response_body | string or null | The start of the reply's body, as text. |
created_at | date-time | When the event happened. |
sent_at | date-time or null | When it was sent; null while pending. |
WebhookDeliveryResponse
| Field | Type | Description |
data | WebhookDelivery | One event sent, or about to be. |
WebhookEvent
An event a webhook can be sent; the words are the vocabulary's webhook_events.
task.created | task.completed | task.deadline_changed | task.start_changed | task.expired | document.uploaded | document.summarized | person.created | note.saved
WebhookPayload
The JSON body sent. data holds the event's record under its kind (task, document, person or note); it's empty for test.
| Field | Type | Description |
id | ULID | A record's ID. |
type | task.created | task.completed | task.deadline_changed | task.start_changed | task.expired | document.uploaded | document.summarized | person.created | note.saved | test | |
created_at | date-time | When the event happened. |
data | object | |
WebhookResponse
| Field | Type | Description |
data | Webhook | An address Nifty sends signed events to. This server's own; not synced. |
A whole number, or one written as a string ("5"); null or "" is none.
integer or null or string