{"openapi":"3.1.0","info":{"title":"Hjarni REST API","version":"1.0.0","description":"Hjarni is a Markdown knowledge base that AI assistants and people share; this API reads and writes the same notes, folders (called containers) and tags that its MCP server exposes. Requests go to https://hjarni.com/api/v1 with a bearer token in the Authorization header, send and receive JSON, and list endpoints page with `page` and `per_page` and report totals in the `X-Total-Count`, `X-Page` and `X-Per-Page` headers. Requests are limited to 100 a minute per account across all of its tokens, and going over answers 429 with a `Retry-After` header.","termsOfService":"https://hjarni.com/terms","contact":{"name":"Hjarni","email":"evert@hjarni.com","url":"https://hjarni.com/docs/api"}},"externalDocs":{"url":"https://hjarni.com/docs/api"},"servers":[{"url":"https://hjarni.com/api/v1"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Me","description":"The account and the token making the request."},{"name":"Dashboard","description":"Counts and recent notes, in one call."},{"name":"Search","description":"Full-text search over notes."},{"name":"Notes","description":"Markdown notes, their links, revision history and Trash."},{"name":"Files","description":"Attaching files to notes."},{"name":"Containers","description":"Folders (containers) that hold notes and other folders, and their AI instructions."},{"name":"Tags","description":"Tags that label notes across folders."}],"paths":{"/me":{"get":{"operationId":"getMe","summary":"Get the account and token","description":"Returns the account behind the token (`user`, with `plan`) and a `token` block describing the token itself. A full-access token also gets `onboarding`, `teams`, `limits` and `suggestions`; an agent token gets only `user` and `token`, and its `token` block adds the `grants` it holds, the `instructions` written for that agent, and `follows_brain_instructions`. Call it first to learn what the token can reach.","tags":["Me"],"responses":{"200":{"description":"The account and the token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/dashboard":{"get":{"operationId":"getDashboard","summary":"Get counts and recent notes","description":"Returns note, folder and tag counts plus the five most recently created active notes, with bodies. A full-access token counts the person's personal notes and folders; an agent token counts what its grants reach, across spaces (`inbox_count` stays personal-only). Not paginated.","tags":["Dashboard"],"responses":{"200":{"description":"Counts and recent notes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dashboard"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/search":{"get":{"operationId":"searchNotes","summary":"Search notes","description":"Full-text search over active notes (archived and trashed notes are left out), ranked by relevance when `q` is given. With a full-access token `search_scope` chooses personal notes, one team's notes, or both (`all`, the default); an agent token searches what its grants reach and is refused with 403 when it names a team it reaches nothing in. Paginated.","tags":["Search"],"parameters":[{"name":"q","in":"query","description":"Search terms. Omitted, blank, or punctuation only, the scope is returned unfiltered and in no particular order.","schema":{"type":"string"}},{"name":"search_scope","in":"query","description":"`personal` for personal notes only, `team:\u003cid\u003e` for one team's notes, or `all` for personal notes plus every team the person belongs to. Any other value is treated as `all`. A `team:\u003cid\u003e` the person is not a member of answers 404.","schema":{"type":"string","pattern":"^(personal|all|team:[0-9]+)$","default":"all"},"example":"personal"},{"$ref":"#/components/parameters/ExcludeBody"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of matching notes.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes":{"get":{"operationId":"listNotes","summary":"List notes","description":"Lists active notes (not archived, not trashed) by position, then newest first; notes with no position come after positioned ones. A full-access token lists the person's personal notes; an agent token lists every note its grants reach, team notes included. Filter with `scope`, `container_id`, `tag` and `q`. Paginated.","tags":["Notes"],"parameters":[{"name":"scope","in":"query","description":"`archived` for archived notes, `inbox` for notes in no folder, `favorited` for favorited notes (with a full-access token this includes favorited notes in the person's teams). Omit for active notes. Trashed notes are listed by GET /notes/trash.","schema":{"type":"string","enum":["archived","inbox","favorited"]}},{"name":"container_id","in":"query","description":"Only notes filed directly in this folder.","schema":{"type":"integer"}},{"name":"tag","in":"query","description":"Only notes carrying a tag with exactly this name.","schema":{"type":"string"}},{"name":"q","in":"query","description":"Full-text search within the listed notes; results are then ordered by relevance. With `q`, only the person's own personal notes match, also for an agent token.","schema":{"type":"string"}},{"$ref":"#/components/parameters/ExcludeBody"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of notes.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"createNote","summary":"Create a note","description":"Creates a note and returns it with 201. Without `container_id` it lands in the inbox. A full-access token always creates a personal note; an agent token creates in the space of the folder it names (or its one writable inbox) and needs write access there. Refused with 403 and an `upgrade_url` when the Free plan's note limit is reached. Search first and update an existing note on the same topic rather than creating a duplicate.","tags":["Notes"],"requestBody":{"$ref":"#/components/requestBodies/NoteCreate"},"responses":{"201":{"description":"The created note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/inbox":{"get":{"operationId":"listInboxNotes","summary":"List inbox notes","description":"Lists active personal notes that sit in no folder, in the same shape and order as GET /notes. Personal notes only, for agent tokens too. Supports `exclude_body`. Paginated.","tags":["Notes"],"parameters":[{"$ref":"#/components/parameters/ExcludeBody"},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of inbox notes.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/trash":{"get":{"operationId":"listTrashedNotes","summary":"List notes in the Trash","description":"Lists notes deleted one at a time, most recently deleted first, each with `deleted_at`, `purge_after` and `deleted_by`. Notes deleted along with their folder are not listed here; they come back when the folder is restored. Paginated.","tags":["Notes"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of trashed notes.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TrashedNote"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"get":{"operationId":"getNote","summary":"Get a note","description":"Returns one note with its full body, tags, folder, attachments (each with a download URL that expires 15 minutes after the response) and `linked_note_ids`. A full-access token reaches the person's personal notes here and gets 404 for a team note; an agent token reaches every note its grants cover. Trashed notes answer 404.","tags":["Notes"],"responses":{"200":{"description":"The note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"operationId":"updateNote","summary":"Update a note","description":"Changes only the fields sent. Replace the body with `body`, or edit it in place with exactly one surgical mode (`append_body`, `insert_body`, `replace_find`, `replace_section`, `append_to_section`, `rename_heading`, `check_item`, `uncheck_item`), which is safer on long notes. Pass `expected_lock_version` (the `lock_version` you read) to get 409 instead of overwriting someone else's edit. Unknown or misplaced keys are refused with 422 and nothing is changed. An agent token needs write access to the note.","tags":["Notes"],"requestBody":{"$ref":"#/components/requestBodies/NoteUpdate"},"responses":{"200":{"description":"The updated note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/LockConflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"operationId":"updateNoteWithPut","summary":"Update a note (PUT)","description":"The same action as PATCH /notes/{id}: a partial update that changes only the fields sent, not a replacement of the whole note. Prefer PATCH.","tags":["Notes"],"requestBody":{"$ref":"#/components/requestBodies/NoteUpdate"},"responses":{"200":{"description":"The updated note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/LockConflict"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"operationId":"deleteNote","summary":"Move a note to the Trash","description":"Moves the note to the Trash and answers 204. It stays restorable with POST /notes/{id}/restore for 30 days, then is purged. Allowed even while the account is read-only over its note limit. An agent token needs write access to the note.","tags":["Notes"],"responses":{"204":{"description":"The note is in the Trash."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/archive":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"patch":{"operationId":"archiveNote","summary":"Archive a note","description":"Sets `archived` to true and returns the note. Archived notes leave the default lists and search but stay readable (GET /notes?scope=archived). An agent token needs write access.","tags":["Notes"],"responses":{"200":{"description":"The archived note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/unarchive":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"patch":{"operationId":"unarchiveNote","summary":"Unarchive a note","description":"Sets `archived` to false and returns the note. An agent token needs write access.","tags":["Notes"],"responses":{"200":{"description":"The unarchived note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/move":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"patch":{"operationId":"moveNote","summary":"Move a note to another folder","description":"Files the note in the folder named by `container_id`, or in the inbox when it is null or omitted, and returns the note. The folder must be a kept folder in the note's own space; one elsewhere or in the Trash is refused (422, or 403 when the token or a team role is what stands in the way). An agent token needs write access to the note and to the destination.","tags":["Notes"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"container_id":{"type":["integer","null"],"description":"The destination folder. Null or omitted moves the note to the inbox."}}},"example":{"container_id":5}}}},"responses":{"200":{"description":"The moved note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/favorite":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"patch":{"operationId":"favoriteNote","summary":"Favorite a note","description":"Sets `favorited` to true and returns the note. Unlike the other note actions, a full-access token can also favorite notes in the person's teams. An agent token needs write access.","tags":["Notes"],"responses":{"200":{"description":"The favorited note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/unfavorite":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"patch":{"operationId":"unfavoriteNote","summary":"Unfavorite a note","description":"Sets `favorited` to false and returns the note. A full-access token can also unfavorite notes in the person's teams. An agent token needs write access.","tags":["Notes"],"responses":{"200":{"description":"The note, no longer favorited.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/link":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"operationId":"linkNote","summary":"Link two notes","description":"Links this note and `target_note_id` (links have no direction) and returns this note, whose `linked_note_ids` then includes the target. Linking an already linked pair is a no-op. Both notes must be reachable by the token (404 otherwise), and an agent token needs write access to both.","tags":["Notes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_note_id"],"properties":{"target_note_id":{"type":"integer","description":"The note to link to. Missing or unknown answers 404."}}},"example":{"target_note_id":42}}}},"responses":{"200":{"description":"This note, with the new link in `linked_note_ids`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/unlink":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"delete":{"operationId":"unlinkNote","summary":"Remove the link between two notes","description":"Removes the link between this note and `target_note_id`, in either direction, and answers 204. The parameter is read from the query string or a JSON body. Allowed while the account is read-only. An agent token needs write access to both notes.","tags":["Notes"],"parameters":[{"name":"target_note_id","in":"query","required":true,"description":"The other note. Also accepted as `{\"target_note_id\": 42}` in a JSON body. Missing or unknown answers 404.","schema":{"type":"integer"}}],"responses":{"204":{"description":"The link is gone."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/linked":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"get":{"operationId":"listLinkedNotes","summary":"List linked notes","description":"Returns every note linked to this one that the token can read, with bodies, as one array. Not paginated.","tags":["Notes"],"responses":{"200":{"description":"The linked notes.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/history":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"get":{"operationId":"getNoteHistory","summary":"List a note's revisions","description":"Without `seq`, lists revisions newest first with who made each one and what changed; page back with `before_seq` and `limit` (this endpoint does not use `page`). With `seq`, returns that one revision with its body as it stood then. Use it before POST /notes/{id}/revert.","tags":["Notes"],"parameters":[{"name":"seq","in":"query","description":"Return only this revision, with its reconstructed `body`, instead of the listing. An unknown seq answers 404; one whose stored history fails verification answers 422.","schema":{"type":"integer"}},{"name":"limit","in":"query","description":"Revisions per listing. Values outside 1-100 are clamped.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"before_seq","in":"query","description":"Cursor. Lists only revisions with a seq lower than this one.","schema":{"type":"integer"}},{"name":"include_body","in":"query","description":"`true` adds each listed revision's reconstructed `body`. A row that cannot be reconstructed gets `body: null` and a `body_error` instead of failing the request.","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"The listing, or with `seq` the one revision.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/NoteHistory"},{"$ref":"#/components/schemas/Revision"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"description":"The revision named by `seq` exists but its stored history does not verify.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevisionUnreadable"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/revert":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"operationId":"revertNote","summary":"Revert a note to an earlier revision","description":"Restores the body of revision `seq` as a new revision (history is never rewritten) and returns the note. Pass `expected_lock_version` to get 409 if the note changed since you read it. Find seq values with GET /notes/{id}/history. An agent token needs write access.","tags":["Notes"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["seq"],"properties":{"seq":{"type":"integer","description":"The revision to bring back. Missing or unknown answers 404."},"expected_lock_version":{"type":"integer","description":"The note's `lock_version` when you read it. A mismatch answers 409."}}},"example":{"seq":3,"expected_lock_version":7}}}},"responses":{"200":{"description":"The note with the earlier body.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/LockConflict"},"422":{"description":"The revision exists but its stored history does not verify (a body with `seq`), or the save failed validation (the generic error body).","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RevisionUnreadable"},{"$ref":"#/components/schemas/Error"}]}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{id}/restore":{"parameters":[{"$ref":"#/components/parameters/NoteId"}],"post":{"operationId":"restoreNote","summary":"Restore a note from the Trash","description":"Brings a note deleted on its own back from the Trash and returns it. A note deleted along with its folder answers 404 here; restore the folder with PATCH /containers/{id}/restore instead. Refused with 403 and an `upgrade_url` when restoring would go over the note limit. An agent token needs write access.","tags":["Notes"],"responses":{"200":{"description":"The restored note.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Note"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/notes/{note_id}/files":{"parameters":[{"$ref":"#/components/parameters/NoteIdForFiles"}],"post":{"operationId":"attachFileFromUrl","summary":"Attach a file to a note from a URL","description":"Hjarni downloads `url` (http or https, up to 3 redirects, no private or internal addresses, 25 MB at most) and attaches the result to the note, answering 201. Personal notes only, for agent tokens too. On the Free plan, personal attachments are limited to 20 MB and five files; going over is refused with 403 and an `upgrade_url`. A URL that cannot be fetched answers 422 with the reason.","tags":["Files"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"The file to fetch. Missing or blank answers 422 with `{\"error\":\"url is required\"}`."},"filename":{"type":"string","description":"Overrides the name taken from the URL's path (`download` when it has none)."},"content_type":{"type":"string","description":"Overrides the type from the response's Content-Type (`application/octet-stream` when absent)."},"description":{"type":"string","description":"Shown with the attachment."}}},"example":{"url":"https://example.com/slides.pdf","description":"Slide deck"}}}},"responses":{"201":{"description":"The attached file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatedNoteFile"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers":{"get":{"operationId":"listContainers","summary":"List folders","description":"Lists active folders by position, then name; folders with no position come after positioned ones. With a full-access token the default is the person's top-level personal folders; an agent token gets every folder its grants reach, flat. `scope=all` lists every active folder flat and `scope=archived` the archived ones. Paginated.","tags":["Containers"],"parameters":[{"name":"scope","in":"query","description":"`all` for every active folder at any depth, `archived` for archived folders. Omit for the default described above.","schema":{"type":"string","enum":["all","archived"]}},{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of folders.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Container"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"createContainer","summary":"Create a folder","description":"Creates a folder, at the top level or under `parent_id`, and returns it with 201. A full-access token creates personal folders; an agent token creates in the space of the parent it names and needs write access there.","tags":["Containers"],"requestBody":{"$ref":"#/components/requestBodies/ContainerCreate"},"responses":{"201":{"description":"The created folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Container"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/root_instructions":{"get":{"operationId":"getRootInstructions","summary":"Get personal root AI instructions","description":"Returns the person's personal root instructions, the AI instructions that apply to their whole personal space. Agent tokens are refused with 403.","tags":["Containers"],"responses":{"200":{"description":"The personal root instructions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RootInstructions"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/update_root_instructions":{"patch":{"operationId":"updateRootInstructions","summary":"Replace personal root AI instructions","description":"Sets the personal root instructions to `personal_llm_instructions` and returns them. The value replaces what is there; sending null or leaving the key out clears them. Agent tokens are refused with 403.","tags":["Containers"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"personal_llm_instructions":{"type":["string","null"],"description":"The new instructions, in Markdown. Null or omitted clears them."}}},"example":{"personal_llm_instructions":"Answer in British English and keep notes short."}}}},"responses":{"200":{"description":"The saved instructions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RootInstructions"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/reorder":{"patch":{"operationId":"reorderContainers","summary":"Reorder folders","description":"Sets folder positions to the order of `ordered_ids` and answers 204. The list must name every active top-level personal folder, or with `parent_id` every active child of that folder, and nothing else (422 otherwise; repeated ids are ignored). Agent tokens are refused with 403.","tags":["Containers"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ordered_ids"],"properties":{"ordered_ids":{"type":"array","items":{"type":"integer"},"description":"Folder ids in the new order. Missing answers 400."},"parent_id":{"type":"integer","description":"Reorder this folder's children instead of the top level. Unknown answers 404."}}},"example":{"ordered_ids":[3,1,2]}}}},"responses":{"204":{"description":"The new order is saved."},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"get":{"operationId":"getContainer","summary":"Get a folder","description":"Returns one folder with its note and child counts and its parent. A full-access token reaches the person's personal folders; an agent token reaches what its grants cover. Folders in the Trash answer 404.","tags":["Containers"],"responses":{"200":{"description":"The folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Container"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"operationId":"updateContainer","summary":"Update a folder","description":"Changes only the fields sent (name, description, parent, position, AI instructions) and returns the folder. A space's root folder (`root: true`) refuses every change with 422. An agent token needs write access to the folder, and to the new parent when moving it.","tags":["Containers"],"requestBody":{"$ref":"#/components/requestBodies/ContainerUpdate"},"responses":{"200":{"description":"The updated folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Container"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"operationId":"updateContainerWithPut","summary":"Update a folder (PUT)","description":"The same action as PATCH /containers/{id}: a partial update that changes only the fields sent. Prefer PATCH.","tags":["Containers"],"requestBody":{"$ref":"#/components/requestBodies/ContainerUpdate"},"responses":{"200":{"description":"The updated folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Container"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"operationId":"deleteContainer","summary":"Move a folder to the Trash","description":"Moves the folder, its sub-folders and their notes to the Trash as one unit and answers 204. Restorable with PATCH /containers/{id}/restore for 30 days, then purged. Answers 409 if the folder was deleted by a concurrent request, and 422 for a space's root folder. An agent token needs write access to every folder in the subtree.","tags":["Containers"],"responses":{"204":{"description":"The folder and its contents are in the Trash."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The folder was already deleted by a concurrent request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}/archive":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"patch":{"operationId":"archiveContainer","summary":"Archive a folder","description":"Archives the folder and returns it with `containers_changed` and `notes_changed` counts. `include_notes=true` also archives the notes filed in it, and `include_nested=true` extends the change to every sub-folder (and with both, their notes). An agent token needs write access to every folder it touches. A space's root folder answers 422.","tags":["Containers"],"parameters":[{"$ref":"#/components/parameters/IncludeNotes"},{"$ref":"#/components/parameters/IncludeNested"}],"responses":{"200":{"description":"The archived folder and what changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerArchiveResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}/unarchive":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"patch":{"operationId":"unarchiveContainer","summary":"Unarchive a folder","description":"Unarchives the folder, and any archived ancestors so it stays reachable, and returns it with `containers_changed` and `notes_changed` counts. Takes the same `include_notes` and `include_nested` options as archive; they reactivate everything they touch, including items archived on their own before. An agent token needs write access.","tags":["Containers"],"parameters":[{"$ref":"#/components/parameters/IncludeNotes"},{"$ref":"#/components/parameters/IncludeNested"}],"responses":{"200":{"description":"The unarchived folder and what changed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerArchiveResult"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}/restore":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"patch":{"operationId":"restoreContainer","summary":"Restore a folder from the Trash","description":"Brings a deleted folder back with everything its delete took, plus any trashed ancestors, and returns it. A folder that is not in the Trash answers 404; 409 means it left the Trash mid-request; 422 means the restore would go over the note limit. An agent token needs write access to every folder it brings back.","tags":["Containers"],"responses":{"200":{"description":"The restored folder.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Container"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The folder left the Trash during the request (restored elsewhere, or purged).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationErrors"}}}},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}/children":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"get":{"operationId":"listContainerChildren","summary":"List a folder's sub-folders","description":"Returns the folder's active direct children that the token can reach, as one array. Not paginated.","tags":["Containers"],"responses":{"200":{"description":"The child folders.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Container"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}/notes":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"get":{"operationId":"listContainerNotes","summary":"List a folder's notes","description":"Lists the active notes filed directly in this folder (not in its sub-folders), with bodies, in the same order as GET /notes. Paginated.","tags":["Containers"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of the folder's notes.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/containers/{id}/tree":{"parameters":[{"$ref":"#/components/parameters/ContainerId"}],"get":{"operationId":"getContainerTree","summary":"Get a folder with its ancestors and children","description":"Returns the folder plus its ancestor chain (top level first) and its active direct children, limited to what the token can reach. Useful for breadcrumbs and one level of navigation in a single call.","tags":["Containers"],"responses":{"200":{"description":"The folder, its ancestors and its children.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContainerTree"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/tags":{"get":{"operationId":"listTags","summary":"List tags","description":"Lists the person's tags by name, each with the number of non-trashed notes carrying it. An agent token sees only tags on notes it can read, counted over those notes. Paginated.","tags":["Tags"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of tags.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"operationId":"createTag","summary":"Create a tag","description":"Creates a tag and returns it with 201. Names are unique per person (422 for a duplicate). To tag a note, set the note's `tag_list` instead, which also creates missing tags. Agent tokens are refused with 403.","tags":["Tags"],"requestBody":{"$ref":"#/components/requestBodies/TagCreate"},"responses":{"201":{"description":"The created tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/tags/{id}":{"parameters":[{"$ref":"#/components/parameters/TagId"}],"get":{"operationId":"getTag","summary":"Get a tag","description":"Returns one tag with its note count. An agent token can read only tags on notes it can read; others answer 404.","tags":["Tags"],"responses":{"200":{"description":"The tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"operationId":"updateTag","summary":"Rename a tag","description":"Renames the tag everywhere it is used and returns it. Agent tokens are refused with 403.","tags":["Tags"],"requestBody":{"$ref":"#/components/requestBodies/TagUpdate"},"responses":{"200":{"description":"The renamed tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"operationId":"updateTagWithPut","summary":"Rename a tag (PUT)","description":"The same action as PATCH /tags/{id}. Prefer PATCH.","tags":["Tags"],"requestBody":{"$ref":"#/components/requestBodies/TagUpdate"},"responses":{"200":{"description":"The renamed tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/UnprocessableEntity"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"operationId":"deleteTag","summary":"Delete a tag","description":"Deletes the tag and answers 204. Notes keep their content; only the tag is removed from them. This cannot be undone. Agent tokens are refused with 403.","tags":["Tags"],"responses":{"204":{"description":"The tag is deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/tags/{id}/merge":{"parameters":[{"$ref":"#/components/parameters/TagId"}],"patch":{"operationId":"mergeTag","summary":"Merge a tag into another","description":"Moves every note carrying this tag onto `target_id`, deletes this tag, and returns the target tag. Merging a tag into itself is not handled and fails with a 500. Agent tokens are refused with 403.","tags":["Tags"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["target_id"],"properties":{"target_id":{"type":"integer","description":"The tag that survives. Missing or unknown answers 404."}}},"example":{"target_id":5}}}},"responses":{"200":{"description":"The target tag, after the merge.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/tags/{id}/notes":{"parameters":[{"$ref":"#/components/parameters/TagId"}],"get":{"operationId":"listTagNotes","summary":"List a tag's notes","description":"Lists the active notes carrying this tag, with bodies, in the same order as GET /notes. An agent token sees only the notes it can read. Paginated.","tags":["Tags"],"parameters":[{"$ref":"#/components/parameters/Page"},{"$ref":"#/components/parameters/PerPage"}],"responses":{"200":{"description":"One page of notes with this tag.","headers":{"X-Total-Count":{"$ref":"#/components/headers/X-Total-Count"},"X-Page":{"$ref":"#/components/headers/X-Page"},"X-Per-Page":{"$ref":"#/components/headers/X-Per-Page"}},"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NoteSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API token in `Authorization: Bearer \u003ctoken\u003e`. Tokens are created in Settings \u003e Connections, or issued to an assistant through the OAuth flow. A new token made in Settings reaches only the folders it is given, at Read or Write per folder, unless it is made with Everything I can reach (see https://hjarni.com/docs/agent-tokens); a token issued through OAuth acts with the person's full access. A missing, unknown or expired token answers 401."}},"parameters":{"Page":{"name":"page","in":"query","description":"Page number, starting at 1. Values below 1 are treated as 1.","schema":{"type":"integer","minimum":1,"default":1}},"PerPage":{"name":"per_page","in":"query","description":"Items per page. Values outside 1-100 are clamped.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},"ExcludeBody":{"name":"exclude_body","in":"query","description":"`true` leaves `body` out of every note, so a sync client can page through metadata cheaply and fetch bodies one at a time with GET /notes/{id}.","schema":{"type":"boolean","default":false}},"NoteId":{"name":"id","in":"path","required":true,"description":"The note's id.","schema":{"type":"integer"}},"NoteIdForFiles":{"name":"note_id","in":"path","required":true,"description":"The id of the personal note to attach to.","schema":{"type":"integer"}},"ContainerId":{"name":"id","in":"path","required":true,"description":"The folder's id.","schema":{"type":"integer"}},"TagId":{"name":"id","in":"path","required":true,"description":"The tag's id.","schema":{"type":"integer"}},"IncludeNotes":{"name":"include_notes","in":"query","description":"`true` also changes the archived state of the notes filed in the folder (and, with `include_nested`, in its sub-folders). Also accepted in a JSON body.","schema":{"type":"boolean","default":false}},"IncludeNested":{"name":"include_nested","in":"query","description":"`true` extends the change to every sub-folder at any depth. Also accepted in a JSON body.","schema":{"type":"boolean","default":false}}},"headers":{"X-Total-Count":{"description":"Total number of records matching the query, across all pages.","schema":{"type":"integer"}},"X-Page":{"description":"The page returned.","schema":{"type":"integer"}},"X-Per-Page":{"description":"The page size used, after clamping.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds until the current rate-limit window ends.","schema":{"type":"integer"}}},"requestBodies":{"NoteCreate":{"required":true,"description":"Fields go in a `note` object. Real note columns (title, body, summary, source_url, container_id, position) sent at the top level are wrapped into `note` for you; other keys sent there are refused with 422.","content":{"application/json":{"schema":{"type":"object","required":["note"],"properties":{"note":{"$ref":"#/components/schemas/NoteCreateFields"}}},"example":{"note":{"title":"Weekly review","body":"# Weekly review\n\nKey decisions...","summary":"Review of the week's decisions and what moved.","source_url":"https://example.com/source","container_id":12,"tag_list":"review,planning"}}}}},"NoteUpdate":{"required":true,"description":"Fields go in a `note` object, and only the ones sent change. Real note columns sent at the top level are wrapped into `note` for you; other keys sent there are refused with 422. Keys from a GET response (`id`, `lock_version`, `summary_stale`, `created_at`, `updated_at`, `last_edited_by`, `last_edited_by_agent`, `team`, `files`, `linked_note_ids`, and `archived`, `favorited`, `tags`, `container` when unchanged) are tolerated, so a full payload can be sent back; an echoed `lock_version` acts as `expected_lock_version`, and a changed `archived`, `favorited`, `tags` or `container` is refused with 422 naming the endpoint or field that makes that change.","content":{"application/json":{"schema":{"type":"object","required":["note"],"properties":{"note":{"$ref":"#/components/schemas/NoteUpdateFields"}}},"examples":{"appendToSection":{"summary":"Add a line under a heading","value":{"note":{"append_to_section":"## Open Questions","section_body":"- Should we ship Friday?"}}},"guardedReplace":{"summary":"Replace the body, failing with 409 if someone else saved first","value":{"note":{"body":"Updated content","expected_lock_version":5}}}}}}},"ContainerCreate":{"required":true,"description":"Fields go in a `container` object; the folder columns sent at the top level are wrapped into it for you.","content":{"application/json":{"schema":{"type":"object","required":["container"],"properties":{"container":{"$ref":"#/components/schemas/ContainerCreateFields"}}},"example":{"container":{"name":"Research","description":"Papers and reading notes","parent_id":5}}}}},"ContainerUpdate":{"required":true,"description":"Fields go in a `container` object, and only the ones sent change. Folder columns sent at the top level are wrapped into it for you.","content":{"application/json":{"schema":{"type":"object","required":["container"],"properties":{"container":{"$ref":"#/components/schemas/ContainerUpdateFields"}}},"example":{"container":{"llm_instructions":"Summaries in one paragraph; link related papers."}}}}},"TagCreate":{"required":true,"description":"Fields go in a `tag` object; a top-level `name` is wrapped into it for you.","content":{"application/json":{"schema":{"type":"object","required":["tag"],"properties":{"tag":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"The tag name, unique per person. Stored as sent (not lowercased)."}}}}},"example":{"tag":{"name":"research"}}}}},"TagUpdate":{"required":true,"description":"Fields go in a `tag` object; a top-level `name` is wrapped into it for you.","content":{"application/json":{"schema":{"type":"object","required":["tag"],"properties":{"tag":{"type":"object","properties":{"name":{"type":"string","description":"The new name, unique per person."}}}}},"example":{"tag":{"name":"new-name"}}}}}},"responses":{"BadRequest":{"description":"The body could not be read (malformed JSON), or a required wrapper or parameter such as `note`, `container`, `tag` or `ordered_ids` is missing or empty.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"status":400,"error":"Bad Request","code":"bad_request","message":"The ordered_ids parameter is missing or empty. Each endpoint's request body is in https://hjarni.com/openapi.json.","docs_url":"https://hjarni.com/docs/api#errors"}}}},"Unauthorized":{"description":"The bearer token is missing, unknown or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Unauthorized","code":"unauthorized","message":"Missing or invalid token. Send it as Authorization: Bearer \u003ctoken\u003e; tokens are created in Settings \u003e Connections.","docs_url":"https://hjarni.com/docs/api#auth"}}}},"Forbidden":{"description":"Refused, for one of three reasons. (1) A plan limit: the Free plan's note limit on create or restore, the Free file allowance on an attachment, or an account that is read-only because it holds more notes than its plan carries. The body has `error` and an `upgrade_url`, and the personal note-limit refusal also a `team_url`. (2) An agent token outside its grants: reading or writing where it was not given access, writing where it only reads, or calling an endpoint agent tokens cannot use. The body has `error` \"Forbidden: outside token scope\" with `code` `out_of_scope`, `message` and `docs_url`, and no `upgrade_url`. (3) A team folder where the person's role is below editor: `error` only, \"You don't have permission to do that (editor required).\"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"outOfScope":{"summary":"Agent token outside its grants","value":{"error":"Forbidden: outside token scope","code":"out_of_scope","message":"This token cannot do this. An agent token reaches only the folders it was given, at the level it was given, and never manages tags, personal instructions or folder order; those need a full-access token. A token's access is set in Settings \u003e Connections.","docs_url":"https://hjarni.com/docs/agent-tokens"}},"noteLimit":{"summary":"Free plan note limit reached","value":{"error":"You've reached the 25 personal note limit on the Free plan. Upgrade to Pro for unlimited notes, or start a shared team knowledge base if this should live with your teammates.","upgrade_url":"/checkout/new?reason=note_limit\u0026ref=paywall_note_limit\u0026t=CHECKOUT_TOKEN","team_url":"/teams/new?ref=paywall_note_limit"}},"editorRequired":{"summary":"Team role below editor","value":{"error":"You don't have permission to do that (editor required)."}}}}}},"NotFound":{"description":"No record with that id that this token can reach (including notes and folders in the Trash, except where an endpoint says otherwise), or no endpoint for this method and path. A revision that does not exist answers with `error` only.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"status":404,"error":"Not Found","code":"not_found","message":"No endpoint matches this method and path, or the record is not one this token can reach. Every endpoint is listed in https://hjarni.com/openapi.json.","docs_url":"https://hjarni.com/docs/api#errors"}}}},"UnprocessableEntity":{"description":"The request was understood but not applied. Model validations answer with an `errors` array of messages; parameter checks (an unknown note key, a surgical edit whose anchor does not match, a missing file `url`, `ordered_ids` that do not match the folders in scope, a URL that could not be fetched) answer with an `errors` array or a single `error` string, as noted on each endpoint.","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ValidationErrors"},{"$ref":"#/components/schemas/Error"}]},"examples":{"validation":{"summary":"Model validation","value":{"errors":["Title can't be blank"]}},"parameterCheck":{"summary":"Parameter check","value":{"error":"ordered_ids must contain exactly all containers in this scope"}}}}}},"LockConflict":{"description":"Someone saved the note after the `expected_lock_version` you sent. Nothing was changed; read the note again and re-apply the edit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LockConflict"}}}},"TooManyRequests":{"description":"Over the rate limit of 100 requests a minute per account, counted across all of its tokens (counters are kept per server process, so the ceiling actually enforced can be somewhat higher). Wait the number of seconds in `Retry-After`. The body has `error` only.","headers":{"Retry-After":{"$ref":"#/components/headers/Retry-After"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Rate limit exceeded. Retry after 12 seconds."}}}}},"schemas":{"Error":{"type":"object","description":"Every error response carries `error`. The generic statuses also carry `code`, `message` and `docs_url`: 401, a 403 for an agent token outside its grants, and any status answered for a raised error or an unknown endpoint (400, 404, 5xx). Plan-limit 403s carry `upgrade_url` instead. Some endpoint-specific errors carry `error` alone.","required":["error"],"properties":{"status":{"type":"integer","description":"The HTTP status again. Present on errors raised inside the app and on unknown endpoints (400, 404, 5xx), not on 401 or the 403s."},"error":{"type":"string","description":"Human-readable message."},"errors":{"type":"array","items":{"type":"string"},"description":"Only on a validation failure raised inside the app (422): one message per problem."},"code":{"type":"string","description":"Machine-readable code: `unauthorized` (401), `out_of_scope` (403, agent token), or for a raised error or unknown endpoint the snake_case name of the HTTP status, such as `bad_request`, `not_found`, `unprocessable_content` or `internal_server_error`.","examples":["unauthorized","out_of_scope","not_found","internal_server_error"]},"message":{"type":"string","description":"What to do about it."},"docs_url":{"type":"string","format":"uri","description":"The documentation page that explains this error."},"upgrade_url":{"type":"string","format":"uri-reference","description":"Only on plan-limit 403s. A path on hjarni.com (relative, so prefix https://hjarni.com) to the checkout that lifts the limit."},"team_url":{"type":"string","format":"uri-reference","description":"Only on the personal note-limit 403 from POST /notes. A relative path to creating a team, the other way past the personal limit."}}},"ValidationErrors":{"type":"object","description":"The 422 model-validation shape, also used by a few 409s.","required":["errors"],"properties":{"errors":{"type":"array","items":{"type":"string"},"description":"One human-readable message per problem."}}},"LockConflict":{"type":"object","description":"A stale write refused with 409.","required":["error","current_lock_version","last_edited_by","last_edited_by_agent","last_edited_at"],"properties":{"error":{"type":"string"},"current_lock_version":{"type":"integer","description":"The note's lock_version now. Send it as expected_lock_version after re-reading."},"last_edited_by":{"type":["string","null"],"description":"Email address of the person who saved last."},"last_edited_by_agent":{"type":["string","null"],"description":"Name of the agent or token that saved last, when it was not the person directly."},"last_edited_at":{"type":"string","format":"date-time"}}},"RevisionUnreadable":{"type":"object","description":"A revision whose stored history no longer verifies, so its body cannot be rebuilt.","required":["error","seq"],"properties":{"error":{"type":"string"},"seq":{"type":"integer","description":"The revision that could not be rebuilt. Other revisions may still be readable."}}},"TagRef":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"ContainerRef":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer"},"name":{"type":"string"}}},"TeamRef":{"type":"object","required":["id","name"],"properties":{"id":{"type":"integer"},"name":{"type":["string","null"]}}},"NoteAttachment":{"type":"object","description":"A file attached to a note.","required":["id","description","filename","content_type","byte_size","url","url_expires_at"],"properties":{"id":{"type":"integer"},"description":{"type":["string","null"]},"filename":{"type":"string"},"content_type":{"type":["string","null"]},"byte_size":{"type":"integer"},"url":{"type":"string","format":"uri","description":"Signed download link that works without a token until `url_expires_at` (15 minutes). Treat it as a credential and do not store it; fetch the note again for a fresh one."},"url_expires_at":{"type":"string","format":"date-time"}}},"NoteSummary":{"type":"object","description":"A note as list endpoints return it. `body` is left out when the request sets `exclude_body=true`; `last_edited_by` and `last_edited_by_agent` appear only once someone has edited the note; `team` appears only on team notes.","required":["id","title","summary","summary_stale","source_url","archived","favorited","position","lock_version","created_at","updated_at","tag_list","tags","container","files"],"properties":{"id":{"type":"integer"},"title":{"type":"string"},"body":{"type":["string","null"],"description":"Markdown. `[[id:Title]]` is a wiki-link to another note."},"summary":{"type":["string","null"],"description":"A short summary for scanning."},"summary_stale":{"type":"boolean","description":"True when the body changed after the summary was written."},"source_url":{"type":["string","null"]},"archived":{"type":"boolean"},"favorited":{"type":"boolean"},"position":{"type":["integer","null"],"description":"Sort position among its siblings; null when unpositioned."},"lock_version":{"type":"integer","description":"Increases on every save. Send it back as expected_lock_version to guard a write."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"last_edited_by":{"type":["string","null"],"description":"Email address of whoever saved the note last."},"last_edited_by_agent":{"type":["string","null"],"description":"Name of the agent or token that saved last, if one did."},"tag_list":{"type":"string","description":"Tag names joined by a comma and a space, e.g. \"planning, review\"."},"tags":{"type":"array","items":{"$ref":"#/components/schemas/TagRef"}},"container":{"description":"The folder the note is filed in; null for the inbox.","oneOf":[{"$ref":"#/components/schemas/ContainerRef"},{"type":"null"}]},"team":{"$ref":"#/components/schemas/TeamRef"},"files":{"type":"array","items":{"$ref":"#/components/schemas/NoteAttachment"}}}},"Note":{"description":"A full note, as GET /notes/{id} and every note write return it.","allOf":[{"$ref":"#/components/schemas/NoteSummary"},{"type":"object","required":["body","linked_note_ids"],"properties":{"body":{"type":["string","null"],"description":"Always present on a single note."},"linked_note_ids":{"type":"array","items":{"type":"integer"},"description":"Ids of the linked notes this token can read."}}}]},"TrashedNote":{"description":"A note in the Trash, as GET /notes/trash returns it.","allOf":[{"$ref":"#/components/schemas/NoteSummary"},{"type":"object","required":["body","deleted_at","purge_after","deleted_by"],"properties":{"body":{"type":["string","null"],"description":"Always present on a trashed note."},"deleted_at":{"type":"string","format":"date-time"},"purge_after":{"type":["string","null"],"format":"date-time","description":"When it is permanently removed, 30 days after deletion."},"deleted_by":{"type":["string","null"],"description":"Email address of whoever deleted it."}}}]},"NoteFileAttributes":{"type":"object","description":"One attachment row. To add a file, send `file`; to change one, send its `id` with a new `file` or `description`; to remove one, send its `id` with `_destroy: true`. In JSON, `file` is the signed id of an Active Storage upload; a multipart/form-data request can send the file itself. POST /notes/{note_id}/files is the simpler way to attach from a URL.","properties":{"id":{"type":"integer","description":"An existing attachment of this note."},"file":{"type":"string","description":"Signed blob id of an uploaded file."},"description":{"type":["string","null"]},"_destroy":{"type":"boolean","description":"True removes the attachment named by `id`."}}},"NoteFilesAttributes":{"description":"Attachment rows, as an array or as an object keyed by index (\"0\", \"1\", ...).","oneOf":[{"type":"array","items":{"$ref":"#/components/schemas/NoteFileAttributes"}},{"type":"object","additionalProperties":{"$ref":"#/components/schemas/NoteFileAttributes"}}]},"NoteCreateFields":{"type":"object","required":["title"],"properties":{"title":{"type":"string","maxLength":500},"body":{"type":["string","null"],"description":"Markdown, at most 256 KB. `[[id:Title]]` links another note."},"summary":{"type":["string","null"],"description":"A short summary for scanning. Give every note one."},"source_url":{"type":["string","null"]},"container_id":{"type":["integer","null"],"description":"The folder to file the note in. Omit for the inbox. With a full-access token it must be one of the person's personal folders (422 otherwise)."},"position":{"type":["integer","null"],"description":"Sort position among its siblings. Omit to leave it unpositioned."},"tag_list":{"type":"string","description":"Comma-separated tag names, e.g. \"review,planning\". Missing tags are created; names are lowercased."},"note_files_attributes":{"$ref":"#/components/schemas/NoteFilesAttributes"}}},"NoteUpdateFields":{"type":"object","description":"Send only what should change. For the body, send `body` (full replacement) or one surgical mode with its companion keys; `body` wins if both are sent, and two modes at once are refused with 422. Anchors (`insert_after`, `insert_before`, `replace_find`) must match exactly one place, compared exactly first, then ignoring whitespace, then ignoring case outside code blocks; headings and checklist items match case- and whitespace-insensitively. A miss or an ambiguous match answers 422 and changes nothing.","properties":{"title":{"type":"string","maxLength":500},"body":{"type":["string","null"],"description":"Replaces the whole body. Markdown, at most 256 KB."},"summary":{"type":["string","null"]},"source_url":{"type":["string","null"]},"container_id":{"type":["integer","null"],"description":"Moves the note; null moves it to the inbox."},"position":{"type":["integer","null"]},"tag_list":{"type":"string","description":"Replaces all of the note's tags with these comma-separated names; an empty string removes them all."},"expected_lock_version":{"type":"integer","description":"The lock_version you read. If the note has moved on, the update answers 409 and changes nothing."},"lock_version":{"type":"integer","description":"Tolerated when echoed from a GET response, and then honored as expected_lock_version."},"append_body":{"type":"string","description":"Text added at the end of the body, on a new line."},"insert_body":{"type":"string","description":"Text inserted next to an anchor. Needs exactly one of insert_after or insert_before."},"insert_after":{"type":"string","description":"Anchor text for insert_body; the text goes right after it."},"insert_before":{"type":"string","description":"Anchor text for insert_body; the text goes right before it."},"replace_find":{"type":"string","description":"Text to replace. Must match exactly one place."},"replace_with":{"type":"string","description":"Replacement for replace_find. Omitted, the matched text is deleted."},"replace_section":{"type":"string","description":"A heading (with or without leading \"#\"). Everything under it is replaced by section_body, keeping the heading line."},"append_to_section":{"type":"string","description":"A heading. section_body is added at the end of its section, before the next heading of the same or higher level."},"section_body":{"type":"string","description":"Content for replace_section or append_to_section."},"rename_heading":{"type":"string","description":"The heading to rename. Needs new_heading."},"new_heading":{"type":"string","description":"New heading text. Keeps the level unless it starts with its own \"#\" markers."},"check_item":{"type":"string","description":"Text of a checklist item to tick, e.g. \"ship it\"."},"uncheck_item":{"type":"string","description":"Text of a checklist item to untick."},"note_files_attributes":{"$ref":"#/components/schemas/NoteFilesAttributes"}}},"CreatedNoteFile":{"type":"object","description":"The attachment created by POST /notes/{note_id}/files.","required":["id","filename","content_type","byte_size","description"],"properties":{"id":{"type":"integer"},"filename":{"type":"string"},"content_type":{"type":"string"},"byte_size":{"type":"integer"},"description":{"type":["string","null"]}}},"Container":{"type":"object","description":"A folder. `last_edited_by` and `last_edited_by_agent` appear only once someone has edited it.","required":["id","name","description","position","archived","llm_instructions","created_at","updated_at","root","notes_count","children_count","parent"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"description":{"type":["string","null"]},"position":{"type":["integer","null"],"description":"Sort position among its siblings; null when unpositioned."},"archived":{"type":"boolean"},"llm_instructions":{"type":["string","null"],"description":"AI instructions that apply to the notes in this folder and below."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"root":{"type":"boolean","description":"True for a space's root, which holds the notes filed outside any folder and refuses every change. False for an ordinary folder."},"last_edited_by":{"type":["string","null"],"description":"Email address of whoever saved the folder last."},"last_edited_by_agent":{"type":["string","null"]},"notes_count":{"type":"integer","description":"Notes filed directly in this folder, archived included, Trash excluded."},"children_count":{"type":"integer","description":"Sub-folders directly under this one that are not in the Trash (for an agent token, the ones it can reach)."},"parent":{"description":"The parent folder, or null at the top level or when the token cannot reach the parent.","oneOf":[{"$ref":"#/components/schemas/ContainerRef"},{"type":"null"}]}}},"ContainerArchiveResult":{"description":"A folder after archive or unarchive, with what the change touched.","allOf":[{"$ref":"#/components/schemas/Container"},{"type":"object","required":["containers_changed","notes_changed"],"properties":{"containers_changed":{"type":"integer","description":"Folders whose archived flag actually flipped. A repeat call reports 0."},"notes_changed":{"type":"integer","description":"Notes whose archived flag flipped; 0 unless include_notes was set."}}}]},"ContainerTree":{"description":"A folder with its ancestors and children.","allOf":[{"$ref":"#/components/schemas/Container"},{"type":"object","required":["ancestors","children"],"properties":{"ancestors":{"type":"array","description":"The chain above this folder, top level first, limited to what the token can reach.","items":{"$ref":"#/components/schemas/ContainerRef"}},"children":{"type":"array","description":"Active direct sub-folders the token can reach.","items":{"$ref":"#/components/schemas/Container"}}}}]},"ContainerCreateFields":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"parent_id":{"type":["integer","null"],"description":"Nest under this folder. Omit for the top level."},"llm_instructions":{"type":["string","null"],"description":"AI instructions for this folder and everything below it."},"position":{"type":["integer","null"],"description":"Sort position among its siblings. Omit to leave it unpositioned."}}},"ContainerUpdateFields":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":["string","null"]},"parent_id":{"type":["integer","null"],"description":"Moves the folder under this one; null moves it to the top level."},"llm_instructions":{"type":["string","null"]},"position":{"type":["integer","null"]}}},"RootInstructions":{"type":"object","required":["personal_llm_instructions"],"properties":{"personal_llm_instructions":{"type":["string","null"],"description":"Instructions that apply to the person's whole personal space; null when none are set."}}},"Tag":{"type":"object","required":["id","name","created_at","updated_at","notes_count"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"notes_count":{"type":"integer","description":"Notes carrying the tag that are not in the Trash, archived included."}}},"RevisionAuthor":{"type":"object","description":"Who made a revision.","required":["label","kind","client","agent","source"],"properties":{"label":{"type":["string","null"],"description":"Display name, e.g. an email address, an agent token's name, or \"(system)\"."},"kind":{"type":"string","enum":["user","agent","system","anonymous"]},"client":{"type":["string","null"],"description":"The AI client, for agent edits."},"agent":{"type":["string","null"],"description":"The token or agent name, when there was one."},"source":{"type":"string","description":"The surface the edit came through, such as web, api, mcp or system."}}},"Revision":{"type":"object","description":"One revision of a note. `meta_changes` appears only when fields other than the body changed; `body` only with include_body=true or seq.","required":["seq","at","kind","changed","edit_count","reverted_from_seq","summary","by"],"properties":{"seq":{"type":"integer","description":"Revision number, starting at 1."},"at":{"type":"string","format":"date-time","description":"When the revision was last written (quick successive edits by one author fold into one)."},"kind":{"type":"string","enum":["diff","keyframe","delete","restore"],"description":"How the revision is stored or what it records."},"changed":{"type":"array","items":{"type":"string"},"description":"What changed, e.g. body, title, summary, container, source_url, favorited, archived, or link_title for a system edit."},"edit_count":{"type":"integer","description":"How many edits were folded into this revision."},"reverted_from_seq":{"type":["integer","null"],"description":"For a revert, the revision it brought back."},"summary":{"type":"string","description":"One readable line, e.g. \"alice@example.com edited the body and renamed it\"."},"by":{"$ref":"#/components/schemas/RevisionAuthor"},"meta_changes":{"type":"object","additionalProperties":true,"description":"Non-body fields that changed, keyed by column (title, summary, container_id, source_url, favorited, archived) with [old, new] pairs, plus revert_to for a revert."},"body":{"type":["string","null"],"description":"The body as of this revision; null when it could not be rebuilt."},"body_error":{"type":"string","description":"Present when body is null because the stored history did not verify."}}},"NoteHistory":{"type":"object","required":["note_id","revision_count","revisions"],"properties":{"note_id":{"type":"integer"},"revision_count":{"type":"integer","description":"The highest seq, 0 when the note has no history."},"revisions":{"type":"array","description":"Newest first.","items":{"$ref":"#/components/schemas/Revision"}}}},"MeUser":{"type":"object","required":["id","first_name","email_address","plan","email"],"properties":{"id":{"type":"integer"},"first_name":{"type":["string","null"]},"email_address":{"type":"string","format":"email"},"plan":{"type":"string","description":"The stored plan name, \"free\" or \"pro\"."},"email":{"type":"string","format":"email","deprecated":true,"description":"Same as email_address, kept for older clients."}}},"AgentGrantInfo":{"type":"object","description":"One folder an agent token was given.","required":["container_id","name","team_id","level","effective"],"properties":{"container_id":{"type":"integer"},"name":{"type":"string","description":"The folder's name, or for a space's root the team's name or \"Personal\"."},"team_id":{"type":["integer","null"]},"level":{"type":"string","enum":["read","write"],"description":"What was granted. Everything below the folder inherits it unless another grant says otherwise."},"effective":{"type":"string","enum":["none","read","write"],"description":"What the token can do there now, after the person's own role caps it."}}},"MeToken":{"type":"object","description":"The token making the request. `instructions`, `follows_brain_instructions` and `grants` appear only for an agent token (`restricted: true`).","required":["id","name","restricted","scope_container"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"restricted":{"type":"boolean","description":"True for an agent token, which reaches only its grants."},"scope_container":{"description":"Kept for older clients: the folder when the token holds exactly one grant and it is write, otherwise null. Read `grants` instead.","oneOf":[{"$ref":"#/components/schemas/ContainerRef"},{"type":"null"}]},"instructions":{"type":"string","description":"What the person wrote for this agent; an empty string when nothing."},"follows_brain_instructions":{"type":"boolean","description":"Whether this agent should also follow the person's brain-wide instructions (the API does not serve those to agent tokens)."},"grants":{"type":"array","items":{"$ref":"#/components/schemas/AgentGrantInfo"}}}},"Onboarding":{"type":"object","required":["completed","completed_at","signals","missing_steps"],"properties":{"completed":{"type":"boolean"},"completed_at":{"type":["string","null"],"format":"date-time"},"signals":{"type":"object","required":["connected_mcp","has_real_notes","has_custom_instructions","team_brain_available"],"properties":{"connected_mcp":{"type":"boolean"},"has_real_notes":{"type":"boolean"},"has_custom_instructions":{"type":"boolean"},"team_brain_available":{"type":"boolean"}}},"missing_steps":{"type":"array","items":{"type":"string","enum":["connect_mcp","first_note"]}},"next_action":{"type":"string","description":"Setup guidance for an assistant, present only while setup is incomplete and a first note is the gap."}}},"TeamMembershipInfo":{"type":"object","required":["id","name","role","notes_used","notes_limit"],"properties":{"id":{"type":"integer"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","member"]},"notes_used":{"type":"integer"},"notes_limit":{"type":["integer","null"],"description":"Null when the team has no limit."}}},"Limits":{"type":"object","description":"Personal allowances; a null limit means unlimited.","required":["notes_used","notes_limit","file_storage_bytes_used","file_storage_bytes_limit","files_used","files_limit"],"properties":{"notes_used":{"type":"integer"},"notes_limit":{"type":["integer","null"]},"file_storage_bytes_used":{"type":"integer"},"file_storage_bytes_limit":{"type":["integer","null"]},"files_used":{"type":"integer"},"files_limit":{"type":["integer","null"]}}},"Me":{"type":"object","description":"`onboarding`, `teams`, `limits` and `suggestions` are present for a full-access token and absent for an agent token.","required":["user","token"],"properties":{"user":{"$ref":"#/components/schemas/MeUser"},"token":{"$ref":"#/components/schemas/MeToken"},"onboarding":{"$ref":"#/components/schemas/Onboarding"},"teams":{"type":"array","description":"Teams the person belongs to, by name.","items":{"$ref":"#/components/schemas/TeamMembershipInfo"}},"limits":{"$ref":"#/components/schemas/Limits"},"suggestions":{"type":"object","required":["create_team"],"properties":{"create_team":{"type":"boolean","description":"True when the person is a good fit to be offered a team."}}}}},"Dashboard":{"type":"object","required":["inbox_count","notes_count","archived_count","containers_count","tags_count","recent_notes"],"properties":{"inbox_count":{"type":"integer","description":"Active personal notes in no folder."},"notes_count":{"type":"integer","description":"Active notes (not archived, not trashed)."},"archived_count":{"type":"integer"},"containers_count":{"type":"integer","description":"Active folders."},"tags_count":{"type":"integer"},"recent_notes":{"type":"array","description":"The five most recently created active notes, with bodies.","items":{"$ref":"#/components/schemas/NoteSummary"}}}}}}}