Harbor
Developer docs menu

API reference

Tasks & Reminders API

Tasks are first-class, syncable to-dos — standalone or embedded in a note. Notes can also carry a lightweight reminder of their own.

Tasks are their own records — a client-generated UUID, a title, and scheduling fields — that sync across devices like notes do (every write allocates a fresh USN; deletes are tombstones). Reminders are simpler: a pair of timestamp fields on a note itself. Everything on this page requires a bearer token with the notes scope.

The task object

A task is just a title plus scheduling fields — there is no assignee, and no body of its own. For richer detail, embed the task in a note.

FieldTypeDescription
idstring (UUID)Client-generated; stable across devices.
note_idstringOwning note id, or "" for a standalone task.
titlestringShort plaintext label.
due_atint | nullDue moment, epoch-ms UTC.
due_has_timebooltrue (default) = date+time; false = date-only, clients ignore the time portion. Only meaningful when due_at is set.
reminder_atint | nullReminder moment, epoch-ms UTC. Stored and served only — notifications are your client’s job.
recurrencestring | nullRecurrence rule — see Due dates & recurrence.
prioritystringnone | low | medium | high. Default none.
flagboolSimple flagged/starred marker.
done_atint | nullCompletion moment, epoch-ms. null = not done.
positionintOrdering index within its list or note (lower sorts first).
usnintServer-assigned sync ordering.
deletedboolTombstone (soft-delete).
created_at / updated_atintEpoch-ms UTC.
{
  "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
  "note_id": "",
  "title": "Renew passport",
  "due_at": 1751000000000,
  "due_has_time": true,
  "reminder_at": null,
  "recurrence": "yearly",
  "priority": "high",
  "flag": false,
  "done_at": null,
  "position": 0,
  "usn": 12,
  "deleted": false,
  "created_at": 1750000000000,
  "updated_at": 1750000000000
}

Every task mutation returns the task plus its newly assigned USN: { "task": { … }, "usn": N }.

Due dates & recurrence

Date-only vs timed. due_at is always a full timestamp, but due_has_time says whether the time part means anything. Set due_has_time: false for a “due Friday” style task; leave it (or set true) for “due Friday at 3pm”.

Recurrence rules. recurrence accepts two formats, validated on write (unparseable values are rejected with 422 invalid_recurrence):

  • Simple rules: daily, weekly, monthly, yearly, and every:N:days / every:N:weeks / every:N:months / every:N:years (N ≥ 1). Stored lower-cased and trimmed.
  • iCalendar RRULE (RFC 5545): any value starting with FREQ= (an RRULE: prefix is fine), supporting FREQ (DAILY/WEEKLY/MONTHLY/YEARLY), INTERVAL, BYDAY (weekdays and nth-weekday like 1FR / -1FR), BYMONTHDAY (131, or a negative day counted back from the end of the month — -1 is the last day, -2 the day before it), and an UNTIL / COUNT end condition. Stored verbatim, and case-sensitive: write it in upper case, because freq=monthly is rejected.
ExampleMeaning
every:2:weeksevery 2 weeks
FREQ=WEEKLY;BYDAY=MO,WE,FRweekly on Mon/Wed/Fri
FREQ=MONTHLY;BYDAY=-1FRmonthly on the last Friday
FREQ=MONTHLY;BYMONTHDAY=-1monthly on the last day of the month
FREQ=WEEKLY;BYDAY=FR;UNTIL=20261231T235959Zweekly on Friday until Dec 31 2026

Those middle two rows are easy to mix up. BYDAY=-1FR is the last Friday, which in April 2026 is the 24th. BYMONTHDAY=-1 is the last day, which is the 30th.

There is no DTSTART — the task’s due date anchors the series, and each completion re-anchors it at the new due date.

Completing a recurring task advances it. POST /tasks/:id/done on a task with a recurrence does not set done_at; instead the same task rolls forward to its next occurrence — due_at and reminder_at advance, reminder_at keeps its lead time relative to due_at, and done_at stays null. Simple rules roll forward as fixed UTC intervals; RRULE occurrences are computed in the user’s timezone, so BYDAY and BYMONTHDAY land on the right calendar day. A recurring task with neither due_at nor reminder_at has nothing to advance and simply completes.

UNTIL ends a series: once the last occurrence has passed, completing the task completes it for good and it stops recurring. COUNT is accepted on write but does not currently end a series — because each completion re-anchors the rule at the new due date, the count starts over and the task repeats indefinitely. Use UNTIL when you need a series to stop.

What happens at the end of a month

A task due on the 29th, 30th or 31st has to do something in a month that short, and the two formats do different things. The difference is worth spelling out. Take a task due Saturday 31 January 2026 and complete it over and over:

RuleThe next few due datesWhat it does
monthlyMar 3, Apr 3, May 3Overflows into the next month, then stays there
FREQ=MONTHLY;BYMONTHDAY=31Mar 31, May 31, Jul 31Skips months with no 31st
FREQ=MONTHLY;BYMONTHDAY=-1Feb 28, Mar 31, Apr 30Lands on the real last day, every month

monthly overflows, then drifts. It adds one calendar month and keeps the day number, so 31 January becomes “31 February” — which is really 3 March. The task never finds its way back to the 31st: from then on it is a task due on the 3rd. The same happens to yearly on a leap day (29 Feb 2028 becomes 1 Mar 2029, and stays on the 1st), and to every:N:months whenever it lands on a short month — every:2:months from 31 January gets as far as Mar 31, May 31 and Jul 31 before September pushes it to 1 October.

This behaviour may change — don’t depend on it. If a task needs to land on a particular day near the end of the month, use an RRULE.

BYMONTHDAY=31 skips. RFC 5545 leaves out dates that don’t exist rather than moving them, so a task on the 31st simply doesn’t occur in February, April, June, September or November. That is the right rule for “the 31st or not at all” and the wrong one for “the end of every month”. A bare FREQ=MONTHLY behaves the same way, because it takes its day number from the task’s due date.

BYMONTHDAY=-1 is the one that means “end of the month”. It resolves to whatever the last day actually is — Feb 28, Mar 31, Apr 30 — and never skips a month. INTERVAL works alongside it: FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=-1 from 31 January gives Apr 30, Jul 31, Oct 31.

The Harbor apps don’t offer “last day of the month” in their repeat pickers yet, so for now this is a rule you set through the API. A task configured this way keeps its rule, but the Apple apps currently summarise it as “day -1”.

Tasks inside notes

A note embeds a task with a <harbor-task id="<task-uuid>"> element (only the id attribute is allowed). On every note write the server derives the note↔task linkage from these blocks: a referenced task is claimed by the note, and a task whose block was removed is deleted (tombstoned) — not detached back to standalone. That makes cut/paste-moving a task between notes unsupported: the first note’s save deletes the task before the second note’s save can re-claim it. Linkage extraction is skipped for encrypted notes, so an encrypted note’s tasks are not aggregated or indexed. A note’s “N of M done” progress is derivable by counting done_at over GET /notes/:id/tasks.

Create a task

POST /api/v1/tasks · scope: notes

All fields are optional. Pass your own id to create a task minted offline; omit it and the server generates one.

FieldTypeRequiredDescription
idstring (UUID)noClient UUID; generated when omitted. Duplicate id → 409 conflict.
note_idstringnoOwning note id; "" or omitted = standalone.
titlestringno
due_atint (epoch-ms)no
due_has_timeboolnofalse for a date-only due. Omitted defaults to true.
reminder_atint (epoch-ms)no
recurrencestringnoSee Due dates & recurrence.
prioritystringnonone / low / medium / high. Default none.
flagboolno
positionintno
curl https://app.harbor.my/api/v1/tasks \
  -H "Authorization: Bearer $HARBOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Renew passport",
    "due_at": 1751000000000,
    "priority": "high",
    "recurrence": "yearly"
  }'

Response 201 Created:

{
  "task": {
    "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
    "note_id": "",
    "title": "Renew passport",
    "due_at": 1751000000000,
    "due_has_time": true,
    "reminder_at": null,
    "recurrence": "yearly",
    "priority": "high",
    "flag": false,
    "done_at": null,
    "position": 0,
    "usn": 12,
    "deleted": false,
    "created_at": 1750000000000,
    "updated_at": 1750000000000
  },
  "usn": 12
}

Errors:

  • 422 validation_failed — bad id or invalid JSON.
  • 422 invalid_priority / 422 invalid_recurrence — bad enum or rule.
  • 409 conflict — the supplied id already exists.

Python

import os
import requests

BASE = "https://app.harbor.my/api/v1"
headers = {"Authorization": f"Bearer {os.environ['HARBOR_TOKEN']}"}

resp = requests.post(
    f"{BASE}/tasks",
    headers=headers,
    json={
        "title": "Renew passport",
        "due_at": 1751000000000,
        "priority": "high",
        "recurrence": "yearly",
    },
)
resp.raise_for_status()
body = resp.json()
print(body["task"]["id"], "usn", body["usn"])

JavaScript

const BASE = "https://app.harbor.my/api/v1";

const res = await fetch(`${BASE}/tasks`, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.HARBOR_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    title: "Renew passport",
    due_at: 1751000000000,
    priority: "high",
    recurrence: "yearly",
  }),
});
const { task, usn } = await res.json();
console.log(task.id, "usn", usn);

Go

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

const base = "https://app.harbor.my/api/v1"

func main() {
	payload, _ := json.Marshal(map[string]any{
		"title":      "Renew passport",
		"due_at":     1751000000000,
		"priority":   "high",
		"recurrence": "yearly",
	})

	req, _ := http.NewRequest("POST", base+"/tasks", bytes.NewReader(payload))
	req.Header.Set("Authorization", "Bearer "+os.Getenv("HARBOR_TOKEN"))
	req.Header.Set("Content-Type", "application/json")

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var out struct {
		Task struct {
			ID string `json:"id"`
		} `json:"task"`
		USN int `json:"usn"`
	}
	json.NewDecoder(res.Body).Decode(&out)
	fmt.Println(out.Task.ID, "usn", out.USN)
}

List tasks

GET /api/v1/tasks · scope: notes

The aggregated task list across all notes plus standalone tasks. Tombstoned tasks are never returned.

FieldTypeRequiredDescription
limitintnoDefault 100, hard cap 500 (clamped).
offsetintnoDefault 0.
orderstringnoDefault due (asc), then usn. Sortable: due, priority, created, updated, position, usn; prefix - for descending.
statusstringnoDefault active (= not done). today = not done and due today (server-local day); done; all.
due_beforeint (epoch-ms)noOnly tasks with due_at <= this value.
note_idstringnoOnly tasks owned by that note; the literal none selects standalone tasks.
curl "https://app.harbor.my/api/v1/tasks?status=today&order=due&limit=50" \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 200 OK:

{
  "data": [
    {
      "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
      "note_id": "",
      "title": "Renew passport",
      "due_at": 1751000000000,
      "due_has_time": true,
      "reminder_at": null,
      "recurrence": "yearly",
      "priority": "high",
      "flag": false,
      "done_at": null,
      "position": 0,
      "usn": 12,
      "deleted": false,
      "created_at": 1750000000000,
      "updated_at": 1750000000000
    }
  ],
  "paging": { "limit": 50, "offset": 0, "total": 1, "has_more": false }
}

Errors:

  • 422 validation_failed — unknown sort field, invalid status, or malformed due_before.

One quirk worth knowing: order=priority sorts the stored string lexically (high < low < medium < none), not semantically — pick the direction that fits your view.

Python

import os
import requests

BASE = "https://app.harbor.my/api/v1"
headers = {"Authorization": f"Bearer {os.environ['HARBOR_TOKEN']}"}

resp = requests.get(
    f"{BASE}/tasks",
    headers=headers,
    params={"status": "today", "order": "due", "limit": 50},
)
resp.raise_for_status()
for task in resp.json()["data"]:
    print(task["title"], task["due_at"])

JavaScript

const BASE = "https://app.harbor.my/api/v1";

const params = new URLSearchParams({ status: "today", order: "due", limit: "50" });
const res = await fetch(`${BASE}/tasks?${params}`, {
  headers: { Authorization: `Bearer ${process.env.HARBOR_TOKEN}` },
});
const { data, paging } = await res.json();
for (const task of data) console.log(task.title, task.due_at);
console.log("total:", paging.total);

Go

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

const base = "https://app.harbor.my/api/v1"

func main() {
	req, _ := http.NewRequest("GET", base+"/tasks?status=today&order=due&limit=50", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("HARBOR_TOKEN"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	var out struct {
		Data []struct {
			Title string `json:"title"`
			DueAt int64  `json:"due_at"`
		} `json:"data"`
	}
	json.NewDecoder(res.Body).Decode(&out)
	for _, t := range out.Data {
		fmt.Println(t.Title, t.DueAt)
	}
}

Get a task

GET /api/v1/tasks/:id · scope: notes

Fetch a single live task by UUID.

curl https://app.harbor.my/api/v1/tasks/9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 200 OK: { "task": { … }, "usn": 12 } — the full task object.

Errors:

  • 404 not_found — no such task, or it has been tombstoned.

Update a task

PATCH /api/v1/tasks/:id · scope: notes

Partial update, last-write-wins: only the fields present in the body change, and a fresh USN is allocated. Because JSON null and “field omitted” are indistinguishable in a PATCH, nullable fields have explicit clear_* booleans. done_at is not updatable here — completion goes through POST /tasks/:id/done so recurrence is handled correctly.

FieldTypeRequiredDescription
note_idstringnoSet the owning note; "" = standalone.
titlestringno
due_atint (epoch-ms)no
clear_due_atboolnotrue nulls due_at (ignored if due_at is also sent).
due_has_timeboolnoToggle date-only (false) vs timed (true).
reminder_atint (epoch-ms)no
clear_reminder_atboolnotrue nulls reminder_at.
recurrencestringnoSee Due dates & recurrence.
clear_recurrenceboolnotrue nulls recurrence.
prioritystringnonone / low / medium / high.
flagboolno
positionintno
curl -X PATCH https://app.harbor.my/api/v1/tasks/9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a \
  -H "Authorization: Bearer $HARBOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Renew US passport",
    "priority": "medium",
    "clear_recurrence": true
  }'

Response 200 OK:

{
  "task": {
    "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
    "title": "Renew US passport",
    "priority": "medium",
    "recurrence": null,
    "done_at": null,
    "usn": 13,
    "deleted": false
  },
  "usn": 13
}

Errors:

  • 404 not_found — no such live task.
  • 422 invalid_priority / 422 invalid_recurrence — bad enum or rule.
  • 422 validation_failed — invalid JSON.

Delete a task

DELETE /api/v1/tasks/:id · scope: notes

Soft-delete (tombstone) a task with a fresh USN so the deletion propagates to every device. Deleting a note-linked task also strips its <harbor-task> block from the owning note in the same transaction (the note is re-derived and its USN bumped). This cleanup is a no-op for standalone tasks; for an encrypted owning note the server cannot edit ciphertext, so the client self-heals the dangling block instead.

curl -X DELETE https://app.harbor.my/api/v1/tasks/9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 204 No Content.

Errors:

  • 404 not_found — missing or already tombstoned.

Complete a task

POST /api/v1/tasks/:id/done · scope: notes

Mark a task done. A non-recurring task gets done_at set (defaulting to the server’s current time). A recurring task instead advances to its next occurrence — done_at stays null and due_at/reminder_at roll forward (see Due dates & recurrence).

FieldTypeRequiredDescription
done_timeint (epoch-ms)noCompletion time for a non-recurring task; defaults to now. Must be >= 0. Ignored for a recurring advance.
curl -X POST https://app.harbor.my/api/v1/tasks/9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a/done \
  -H "Authorization: Bearer $HARBOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "done_time": 1750090000000 }'

Response 200 OK (non-recurring):

{
  "task": {
    "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
    "title": "Renew US passport",
    "done_at": 1750090000000,
    "usn": 14,
    "deleted": false
  },
  "usn": 14
}

For a recurring task the returned due_at is the next occurrence and done_at is null.

Errors:

  • 404 not_found — no such live task.
  • 422 validation_failed — negative done_time or invalid JSON.

Reopen a task

DELETE /api/v1/tasks/:id/done · scope: notes

Undo completion by nulling done_at, with a fresh USN. Idempotent — reopening an already-open task just re-numbers it. Does not rewind recurrence.

curl -X DELETE https://app.harbor.my/api/v1/tasks/9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a/done \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 200 OK:

{
  "task": {
    "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
    "done_at": null,
    "usn": 15,
    "deleted": false
  },
  "usn": 15
}

Errors:

  • 404 not_found — no such live task.

List a note’s tasks

GET /api/v1/notes/:id/tasks · scope: notes

The tasks owned by a note (its <harbor-task> blocks), in stable in-note order.

FieldTypeRequiredDescription
limitintnoDefault 100, cap 500.
offsetintnoDefault 0.
orderstringnoDefault position (asc), then created. Sortable: position, created, updated, due, usn.
curl https://app.harbor.my/api/v1/notes/a1b2c3d4-8e2f-4b7a-9c0d-6f5e4d3c2b1a/tasks \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 200 OK:

{
  "data": [
    {
      "id": "9c2e7b10-4f6d-4c1a-9d3e-2b8a51c47f0a",
      "note_id": "a1b2c3d4-8e2f-4b7a-9c0d-6f5e4d3c2b1a",
      "title": "Renew passport",
      "position": 0,
      "done_at": null,
      "usn": 12,
      "deleted": false
    }
  ],
  "paging": { "limit": 100, "offset": 0, "total": 1, "has_more": false }
}

Errors:

  • 404 not_found — the note is missing or expunged.

Note reminders

A reminder is not a separate record — it is the reminder_time and reminder_done_time fields (both epoch-ms UTC) on the note row itself, so it syncs with the note’s USN machinery. A note “is a reminder” if and only if reminder_time is non-null; a set reminder_done_time marks it completed but keeps it listed under “done”. Every mutation below allocates a fresh USN and returns { "note": { … }, "usn": N }.

Two rules apply across all reminder endpoints:

  • Trash rule: a trashed note returns 409 note_in_trash (restore it first); a missing or expunged note returns 404.
  • Notifications are out of scope — the API stores and serves reminder state; delivering the notification is your client’s job.

Encrypted-note reminders are included in the list (the times are not secret), but the note’s title stays ciphertext for the client to decrypt.

List reminders

GET /api/v1/reminders · scope: notes

List the user’s reminders — live, non-trashed notes with reminder_time set. Returns a collection of note objects.

FieldTypeRequiredDescription
limitintnoDefault 100, hard cap 500 (clamped).
offsetintnoDefault 0.
orderstringnoDefault reminder_time (asc). Sortable: reminder_time, updated_at, created_at, usn; prefix - for descending.
statusstringnoDefault active (active/upcoming = not completed; done/completed = completed; all).
due_beforeint (epoch-ms)noOnly reminders with reminder_time <= this — an “upcoming/overdue” view.
curl "https://app.harbor.my/api/v1/reminders?status=active&due_before=1750200000000" \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 200 OK:

{
  "data": [
    {
      "id": "f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f",
      "title": "Pay invoice",
      "notebook_id": "5b1f2c9a-7d3e-4a1b-8c6f-2e9d0b4a7c5e",
      "reminder_time": 1750100000000,
      "is_encrypted": false,
      "usn": 95,
      "deleted": false,
      "updated_at": 1750000000000,
      "created_at": 1749000000000
    }
  ],
  "paging": { "limit": 100, "offset": 0, "total": 1, "has_more": false }
}

Errors:

  • 422 validation_failed — unknown sort field, invalid status, or malformed due_before.

Set a note’s reminder

PUT /api/v1/notes/:id/reminder · scope: notes

Set or update a note’s reminder_time. POST /api/v1/notes/:id/reminder is an equivalent alternate. Setting a time does not clear an existing reminder_done_time — re-arm a completed reminder explicitly via the clear and complete endpoints.

FieldTypeRequiredDescription
reminder_timeint (epoch-ms)yesThe due moment, UTC. Must be >= 0.
curl -X PUT https://app.harbor.my/api/v1/notes/f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f/reminder \
  -H "Authorization: Bearer $HARBOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "reminder_time": 1750100000000 }'

Response 200 OK:

{
  "note": {
    "id": "f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f",
    "title": "Pay invoice",
    "reminder_time": 1750100000000,
    "usn": 96
  },
  "usn": 96
}

Errors:

  • 404 not_found — no live note.
  • 409 note_in_trash — restore the note first.
  • 422 validation_failed — missing or negative reminder_time, or invalid JSON.

Complete a note’s reminder

POST /api/v1/notes/:id/reminder/done · scope: notes

Mark a reminder done by setting reminder_done_time (defaults to the server’s current time). reminder_time is kept, so the note stays listed under “done”. Only a note that is a reminder can be completed. POST /api/v1/notes/:id/reminder/complete is an equivalent alias.

FieldTypeRequiredDescription
done_timeint (epoch-ms)noCompletion time; defaults to now. Must be >= 0.
curl -X POST https://app.harbor.my/api/v1/notes/f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f/reminder/done \
  -H "Authorization: Bearer $HARBOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "done_time": 1750090000000 }'

Response 200 OK:

{
  "note": {
    "id": "f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f",
    "title": "Pay invoice",
    "reminder_time": 1750100000000,
    "usn": 97
  },
  "usn": 97
}

Errors:

  • 404 not_found — no live note.
  • 409 note_in_trash — restore the note first.
  • 422 not_a_reminder — the note has no reminder_time set.
  • 422 validation_failed — negative done_time, or invalid JSON.

Clear a note’s reminder

DELETE /api/v1/notes/:id/reminder · scope: notes

Remove a note’s reminder entirely: nulls both reminder_time and reminder_done_time. Idempotent — clearing a note with no reminder still succeeds and returns the re-numbered note.

curl -X DELETE https://app.harbor.my/api/v1/notes/f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f/reminder \
  -H "Authorization: Bearer $HARBOR_TOKEN"

Response 200 OK:

{
  "note": {
    "id": "f4d8a6b2-1c3e-4f5a-8b7d-9e0c2a4b6d8f",
    "title": "Pay invoice",
    "usn": 98
  },
  "usn": 98
}

Errors:

  • 404 not_found — no live note.
  • 409 note_in_trash — restore the note first.
  • Notes API — the notes tasks embed in, and the note object returned by the reminder endpoints.
  • API conventions — envelopes, pagination, timestamps, and the USN sync model.
  • Errors — the error envelope and the full catalog of error codes.