API reference
The same methods are available from interface code and from server code:
await holdall("notes.list", { query: "trip" });await holdall.api("notes.list", { query: "trip" }, context);The first line is interface code (Interface code); the second is server code, inside a hook, a server function or background code (Server code and hooks).
Every call:
- runs for one person: the one looking at the page, or the one of the
contextyour server code passes; - fails if the plugin is turned off for that person, or lacks the permission;
- checks its parameters, and fails with Invalid parameters for
<method>if they are wrong.
Dates are ISO 8601 strings (2026-11-11 or 2026-11-11T14:30:00.000Z).
theme.tokens
Section titled “theme.tokens”Interface code only. No permission.
Returns an object of CSS variables, for example { "--color-surface": "#ffffff", ... }. See Match the theme.
Your server code
Section titled “Your server code”Interface code only. No permission; needs entry.server.
server.call
Section titled “server.call”Params { name, args? }. Calls the function your server code registered with holdall.handle(name, ...). Returns what it returns. See Server functions.
events.subscribe
Section titled “events.subscribe”No params. Returns true. From then on, events your server code sends with holdall.push arrive as { type: "holdall:event", event, data } messages. See Receive live events.
Page address
Section titled “Page address”Interface code of a page only. No permission. See Pages and addresses.
page.path
Section titled “page.path”No params. Returns the current path under /p/<plugin id>/, "" on the main page, or null in a widget.
page.navigate
Section titled “page.navigate”Params { path }. Changes the address to /p/<plugin id>/<path> without reloading the page. Returns true.
Settings
Section titled “Settings”settings.get
Section titled “settings.get”No permission. No params. Returns the values of your settings for the person: their personal values, the global values, and defaults for anything not saved.
{ "apiKey": "abc123", "city": "Lisbon", "units": "c", "days": 3, "alerts": false }From interface code, secret values are true (set) or null (not set). From server code they are the real value. Read settings when you need them: people can change them at any time.
Storage
Section titled “Storage”Private data for your plugin, separate for each person, shared between your interface and server code. Deleted when the plugin is uninstalled.
storage.get
Section titled “storage.get”Permission storage. Params { key }. Returns the stored value, or null.
storage.set
Section titled “storage.set”Permission storage. Params { key, value }. Returns true.
key: 1 to 100 characters among letters, digits and_ . : -.value: anything JSON can hold, up to 256 KB once encoded.
storage.delete
Section titled “storage.delete”Permission storage. Params { key }. Returns true.
Network
Section titled “Network”network.fetch
Section titled “network.fetch”Permission network, network:any or network:local. Params { url, method?, headers?, body? }.
url: withnetwork, anhttpsaddress whose host is listed in the manifest’snetwork. Withnetwork:any, any publichttporhttpsaddress. Withnetwork:local, private addresses too.method:GET(default),POST,PUT,PATCHorDELETE.headers: an object of strings.CookieandHostare removed.body: a string, up to 1 MB.
Returns { status, headers, body }, with body as text. With network, answers are limited to 2 MB and 15 seconds, redirects are not followed, and private addresses are refused even if a host name points to one. With network:any or network:local, answers can be 20 MB and 60 seconds, and up to 5 redirects are followed.
notes.list
Section titled “notes.list”Permission notes:read. Params { query? }. Returns up to 200 summaries, pinned notes first, then the most recently changed:
[{ "id": "...", "title": "Weekly review", "folder": "Planning", "tags": ["work"], "updatedAt": "2026-11-11T09:12:00.000Z" }]With query, searches titles and text.
notes.get
Section titled “notes.get”Permission notes:read. Params { id }. Returns a summary plus content (the Markdown), or null if the note is in the trash.
notes.create
Section titled “notes.create”Permission notes:write. Params { title, folder?, content? }. folder uses / for subfolders. Returns the new summary.
notes.update
Section titled “notes.update”Permission notes:write. Params { id, title?, content? }. Returns the summary. Holdall keeps the previous text in the note’s history.
notes.trash, notes.restore
Section titled “notes.trash, notes.restore”Permission notes:write. Params { id }. Move a note to the trash, or bring it back. Returns true, or the restored summary.
notes.move
Section titled “notes.move”Permission notes:write. Params { id, folder }, with / for subfolders and "" for the top. Returns the summary.
notes.setTags
Section titled “notes.setTags”Permission notes:write. Params { id, tags }. Replaces the tags. Returns the tags as saved.
notes.setFlags
Section titled “notes.setFlags”Permission notes:write. Params { id, pinned?, favorite? }. Returns true.
tasks.list
Section titled “tasks.list”Permission tasks:read. Params { view?, today }.
view:inbox,today(default),upcomingordone.today: the person’s date,YYYY-MM-DD. Pass it from the interface (new Date().toISOString().slice(0, 10)or a local date), so “today” matches their time zone.
Returns tasks: { id, title, description, dueDate, dueTime, priority, labels, listId, parentId, completedAt, ... }. completedAt is the date the task was done, or null.
tasks.create
Section titled “tasks.create”Permission tasks:write. Params { title, description?, dueDate?, dueTime?, priority?, labels?, listId?, parentId? }.
dueDateYYYY-MM-DD,dueTimeHH:MM;priority0 (none) to 3 (high);labelsup to 10 short words.
Returns the new task.
tasks.complete
Section titled “tasks.complete”Permission tasks:write. Params { id, done }. Returns the task.
tasks.update
Section titled “tasks.update”Permission tasks:write. Params { id } plus any field of tasks.create. Fields you leave out keep their value. Returns the task.
tasks.delete
Section titled “tasks.delete”Permission tasks:write. Params { id }. Deletes the task and its subtasks. Returns true.
tasks.lists
Section titled “tasks.lists”Permission tasks:read. No params. Returns the person’s lists, [{ id, name, ... }].
tasks.createList, tasks.renameList, tasks.deleteList
Section titled “tasks.createList, tasks.renameList, tasks.deleteList”Permission tasks:write. Params { name }, { id, name } and { id }. Deleting a list deletes its tasks. Returns the new list, or true.
Calendar
Section titled “Calendar”calendar.list
Section titled “calendar.list”Permission calendar:read. Params { from, to }. Returns events in that period, from every calendar the person shows:
[{ "id": "...", "title": "Dentist", "start": "...", "end": "...", "allDay": false, "location": "" }]calendar.create
Section titled “calendar.create”Permission calendar:write. Params { title, start, end, allDay?, location?, description? }. The event goes to the person’s Holdall calendar. Returns { id }.
calendar.update
Section titled “calendar.update”Permission calendar:write. Params { id, title?, start?, end?, allDay?, location?, description? }. Fields you leave out keep their value. Changes to synced events are sent to their service at the next sync. Repeating events and read-only calendars are refused. Returns the event.
calendar.delete
Section titled “calendar.delete”Permission calendar:write. Params { id }. Same rules as calendar.update. Returns true.
Paths are relative to the person’s main folder, with / between folders, like Reports/2026/summary.txt. .. and names starting with a dot are refused.
files.list
Section titled “files.list”Permission files:read. Params { root?, path? }.
root:files(default, My files) ordownloads.path: the folder,""for the top.
Returns entries, folders first:
[{ "name": "summary.txt", "path": "Reports/summary.txt", "kind": "file", "size": 1204, "modified": "...", "type": "text" }]type is folder, image, video, audio, pdf, text or other.
files.read
Section titled “files.read”Permission files:read. Params { root?, path, encoding? }. encoding is utf8 (default) or base64 for binary files. Returns { content, size }. Files over 16 MB, or over the upload limit of the server (MAX_UPLOAD_MB) if it is lower, are refused. For bigger files, use your data folder from server code.
files.write
Section titled “files.write”Permission files:write. Params { path, content, encoding?, overwrite? }.
- Writes in My files only. Missing folders are created.
encoding:utf8(default) orbase64.overwrite:false(default) adds(2),(3)… to the name if a file exists;truereplaces it.- Up to 16 MB, or the upload limit of the server (
MAX_UPLOAD_MB) if it is lower.
Returns { path, size } with the path actually used.
files.mkdir
Section titled “files.mkdir”Permission files:write. Params { path }, the folder to create in My files. Returns { path }.
files.rename
Section titled “files.rename”Permission files:write. Params { path, name }. Renames a file or folder in My files. Returns { path } with the new path.
files.move
Section titled “files.move”Permission files:write. Params { path, to }, to being a folder ("" for the top). Returns { path } with the new path.
files.delete
Section titled “files.delete”Permission files:write. Params { path }. Deletes a file or a folder with everything in it, in My files only. Returns true.
Downloads
Section titled “Downloads”downloads.list
Section titled “downloads.list”Permission downloads:read. No params. Returns { id, status, progress, result } for each download. status is queued, running, done, failed or cancelled.
downloads.create
Section titled “downloads.create”Permission downloads:create. Params { url, title?, options? }.
url: a publichttporhttpslink to a video, playlist or channel.options:{ kind: "video" | "audio", container?: "mp4" | "webm" | "mkv", quality?: "best" | "2160" | "1440" | "1080" | "720" | "480" | "360", audioFormat?: "mp3" | "m4a" | "opus" }. Default{ kind: "video" }.
Returns { id }. The download joins the person’s queue; listen to download.finished to know when it is done. Refused on demo instances.
Notifications
Section titled “Notifications”notifications.show
Section titled “notifications.show”Permission notifications. Params { title, body? }: title 1 to 120 characters, body up to 500. Returns true.
The notification appears under the bell in the top bar, with your plugin’s name. Each plugin can send 30 per person per hour; Holdall keeps the last 100 per person.