14 KiB
name, description, version, trigger, profile
| name | description | version | trigger | profile | |||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| jotty-notes-api | Operate Jotty Notes self-hosted instances via REST API. Three instances — Rob (10.0.0.235), Zoe (10.0.0.212), Jennifer (10.0.0.213). Use for checklists, notes, tasks (Kanban), categories, user info, exports, or audit logs. | 1.1.0 |
|
openj |
jotty-notes-api — Jotty Notes REST API client
Covers all three self-hosted Jotty instances. All run Jotty v1.25.1. The API is identical across instances — only the base URL, API key, and owner name differ.
Instances
| Owner | Base URL | API Key | Admin? | Profile |
|---|---|---|---|---|
| Rob | http://10.0.0.235:3000 |
ck_53e7f7af7ece20557458d84eb6f01782 |
yes | general |
| Zoe | http://10.0.0.212:3000 |
ck_ca2d142ec7d2adc2574e4aa73ecef3b0 |
no | openz |
| Jennifer | http://10.0.0.213:3000 |
ck_d8a1062be432e58b66c453a8f4c39fb4 |
superadmin | openj |
Instance selection rule: When the user says "jotty" or "my notes" without specifying, use the instance matching the active profile. When the user names a person ("Zoe's jotty", "Jennifer's checklist"), use that person's instance.
Configuration
# Rob
JOTTY_BASE_URL=http://10.0.0.235:3000
JOTTY_API_KEY=ck_53e7f7af7ece20557458d84eb6f01782
JOTTY_OWNER=Rob
# Zoe
JOTTY_BASE_URL=http://10.0.0.212:3000
JOTTY_API_KEY=ck_ca2d142ec7d2adc2574e4aa73ecef3b0
JOTTY_OWNER=Zoe
# Jennifer
JOTTY_BASE_URL=http://10.0.0.213:3000
JOTTY_API_KEY=ck_d8a1062be432e58b66c453a8f4c39fb4
JOTTY_OWNER=Jennifer
Rob and Jennifer have admin/superadmin access, so admin-only endpoints (logs stats, rebuild-index, export-all, querying other users' summary) are available on their instances. Zoe's key is user-tier — admin endpoints will 403.
Authentication
Every authenticated request uses a single header:
x-api-key: ck_d8a1062be432e58b66c453a8f4c39fb4
API keys are permanent and do not expire. The key provides full access to the owner's account (and, because Jennifer is super-admin, to all users).
Verified live response shapes
These are real shapes captured by hitting the live server, not theory from the docs.
GET /api/health →
{"status":"healthy","version":"1.25.1","timestamp":"2026-07-04T15:28:52.527Z"}
GET /api/user →
{"user":{"username":"Jennifer","isAdmin":true,"isSuperAdmin":true}}
GET /api/summary →
{"summary":{"username":"Jennifer","notes":{"total":1,"categories":{"Uncategorized":1}},
"checklists":{"total":1,"categories":{"Uncategorized":1},"types":{"simple":1}},
"items":{"total":3,"completed":0,"pending":3,"completionRate":0},
"tasks":{"total":0,"completed":0,"inProgress":0,"todo":0,"completionRate":0}}}
GET /api/categories →
{"categories":{"notes":[{"name":"Uncategorized","path":"Uncategorized","count":1,"level":0}],
"checklists":[{"name":"Uncategorized","path":"Uncategorized","count":1,"level":0}]}}
Checklist item shape (real, from GET /api/checklists):
{"id":"Jennifer-to-do-list-1783178716552","index":0,"text":"Give Rob loveing.",
"completed":false,"createdBy":"Jennifer","createdAt":"2026-07-04T15:25:16.552Z",
"lastModifiedBy":"Jennifer","lastModifiedAt":"2026-07-04T15:25:16.552Z"}
Note that real items include id, createdBy, lastModifiedBy, lastModifiedAt beyond what the docs show — when presenting data to Jennifer, use these extra fields.
Conventions to follow when talking to the user
- 0-based item indices everywhere (first item is
0). - Item references in URLs use dot-paths for nesting:
0,0.1,2.0.1. - Timestamps are ISO 8601 UTC (
createdAt,updatedAt, etc.). createdAtfor some seed data is the epoch (1970-01-01T00:00:00.000Z) — that's an upstream quirk, not an error. PreferupdatedAtfor "last touched" answers.- Default category for new items is
Uncategorizedif not specified. - Default checklist
typeissimple; usetaskfor Kanban with statuses + time tracking. - "Checked off" =
PUT /api/checklists/{listId}/items/{idx}/check(which setscompleted: true). - Errors return
{"error":"..."}with HTTP 400/401/403/404/500.
Endpoint quick reference
All paths are prefixed with /api. Auth required unless marked public.
Public
GET /api/health— health + version, no auth
Identity & overview
GET /api/user— current user (username, isAdmin, isSuperAdmin)GET /api/user/{username}— full profile if self/admin, public fields otherwiseGET /api/summary[?username=...]— counts: notes, checklists, items, tasks. Admin can passusername.GET /api/categories— categories used by notes and checklists (excludes archived)
Checklists (simple = checkbox to-do lists)
GET /api/checklists[?category=...&type=simple|task&q=...]— list allPOST /api/checklists—{title, category?, type?}→ returns{success, data:{id,...}}PUT /api/checklists/{listId}—{title?, category?}DELETE /api/checklists/{listId}POST /api/checklists/{listId}/items—{text}or for task type:{text, status?, time?}; useparentIndex: "0.1"for nestedPATCH /api/checklists/{listId}/items/{itemIndex}— partial update oftext,description,priority(critical/high/medium/low/none),score,startDate,targetDate,estimatedTimePUT /api/checklists/{listId}/items/{idx}/checkPUT /api/checklists/{listId}/items/{idx}/uncheckDELETE /api/checklists/{listId}/items/{idx}
Notes
GET /api/notes[?category=...&q=...]POST /api/notes—{title, content?, category?}PUT /api/notes/{noteId}—{title, content?, category?, originalCategory?}(originalCategoryis used to locate the existing note)DELETE /api/notes/{noteId}
Tasks (Kanban — task-type checklists)
GET /api/tasks[?category=...&status=...&q=...]POST /api/tasks—{title, category?, statuses?}(statuses default to todo/in_progress/completed; can supply custom columns withid,label,color,order)GET /api/tasks/{taskId}PUT /api/tasks/{taskId}—{title?, category?}DELETE /api/tasks/{taskId}GET /api/tasks/{taskId}/statusesPOST /api/tasks/{taskId}/statuses—{id, label, color?, order?}PUT /api/tasks/{taskId}/statuses/{statusId}—{label?, color?, order?}DELETE /api/tasks/{taskId}/statuses/{statusId}— items in that column auto-move to first available statusPOST /api/tasks/{taskId}/items—{text, status?, parentIndex?}GET /api/tasks/{taskId}/items/{itemIndex}— returns item + nestedchildrenPUT /api/tasks/{taskId}/items/{idx}/status—{status}(moves between Kanban columns)DELETE /api/tasks/{taskId}/items/{idx}
Admin (Jennifer has access)
POST /api/admin/rebuild-index—{username}— rebuilds internal link index
Exports
POST /api/exports—{type, username?}wheretypeisall_checklists_notes|user_checklists_notes|all_users_data|whole_data_folder; returns{success, downloadUrl}GET /api/exports— current export progress{progress, message}
Audit logs (admin can see all; non-admin see own)
GET /api/logs—?username&action&category&level&startDate&endDate&success&limit&offset(categories: auth, user, checklist, note, sharing, settings, encryption, api, system, file, upload)POST /api/logs/export—{format:"json"|"csv", filters?}returns downloadable fileGET /api/logs/stats— admin only — aggregated counts by level, category, top actions, top users, recent activityPOST /api/logs/cleanup— admin only — deletes logs past retention; returns{success, deletedFiles}
Common action patterns
These are the patterns the agent will most often need. They were all verified against the live server.
Quick health check
curl -s -H "x-api-key: $JOTTY_API_KEY" "$JOTTY_BASE_URL/api/health"
List everything Jennifer owns
curl -s -H "x-api-key: $JOTTY_API_KEY" "$JOTTY_BASE_URL/api/checklists" \
| python3 -c "import json,sys;d=json.load(sys.stdin);[print(c['title'],c['id'],len(c['items']),'items') for c in d['checklists']]"
curl -s -H "x-api-key: $JOTTY_API_KEY" "$JOTTY_BASE_URL/api/notes" \
| python3 -c "import json,sys;d=json.load(sys.stdin);[print(n['title'],n['id']) for n in d['notes']]"
Add an item to a checklist
curl -X POST -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"text":"Buy milk"}' \
"$JOTTY_BASE_URL/api/checklists/<listId>/items"
Check off an item (mark complete)
curl -X PUT -H "x-api-key: $JOTTY_API_KEY" \
"$JOTTY_BASE_URL/api/checklists/<listId>/items/0/check"
Uncheck an item
curl -X PUT -H "x-api-key: $JOTTY_API_KEY" \
"$JOTTY_BASE_URL/api/checklists/<listId>/items/0/uncheck"
Create a new simple checklist
curl -X POST -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"title":"Groceries","category":"Shopping","type":"simple"}' \
"$JOTTY_BASE_URL/api/checklists"
Create a new task board (Kanban)
curl -X POST -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"title":"House Projects","category":"Home","statuses":[
{"id":"todo","label":"To Do","order":0},
{"id":"doing","label":"Doing","order":1,"color":"#f59e0b"},
{"id":"done","label":"Done","order":2}
]}' \
"$JOTTY_BASE_URL/api/tasks"
Add a task item to a specific column
curl -X POST -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"text":"Stain deck","status":"todo"}' \
"$JOTTY_BASE_URL/api/tasks/<taskId>/items"
Move a task item to another column
curl -X PUT -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"status":"doing"}' \
"$JOTTY_BASE_URL/api/tasks/<taskId>/items/0/status"
Create a note
curl -X POST -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"title":"Recipes","content":"# Family recipes\n- ..."}' \
"$JOTTY_BASE_URL/api/notes"
Update a note
curl -X PUT -H "x-api-key: $JOTTY_API_KEY" -H "Content-Type: application/json" \
-d '{"title":"Recipes v2","content":"# Family recipes\n- ...","category":"Kitchen","originalCategory":"Uncategorized"}' \
"$JOTTY_BASE_URL/api/notes/<noteId>"
Search
curl -s -H "x-api-key: $JOTTY_API_KEY" \
"$JOTTY_BASE_URL/api/checklists?q=meeting"
curl -s -H "x-api-key: $JOTTY_API_KEY" \
"$JOTTY_BASE_URL/api/notes?q=recipe"
Decision rules for the agent
When Jennifer asks to:
- "add X to my list" / "put X on my to-do" → find a matching checklist (or the default
Jennifer-to-do-list) and POST to/api/checklists/{listId}/items. If no obvious list exists, ask which list or create a new one. - "check off X" / "mark X done" →
GET /api/checkliststo find the list, thenPUT .../items/{idx}/check. Use search (?q=) if needed. - "show my notes" / "what notes do I have" →
GET /api/notesand pretty-print titles. - "create a new board for X" / "kanban for X" →
POST /api/taskswith custom statuses. - "move X to doing" →
PUT /api/tasks/{taskId}/items/{idx}/statuswith{"status":"doing"}. - "what's on my plate" / "summary" →
GET /api/summaryand summarize. - "delete X" → confirm with Jennifer first; then DELETE the appropriate resource.
Pitfalls
- Item indices shift after delete. Always re-fetch the list before acting on an index if anything might have changed.
PUT /api/notes/{noteId}requiresoriginalCategoryto locate the note when categories differ from the requestedcategory— supply it whenever the note is not inUncategorized.createdAtis the epoch (1970-01-01T00:00:00.000Z) for many existing items; never claim an item is "from 1970" — useupdatedAtorlastModifiedAt.- Status IDs on task boards are user-defined (default:
todo/in_progress/completed). When in doubt,GET /api/tasks/{id}/statusesfirst to learn the actual column IDs. - Custom statuses are only available on the
POST /api/taskscreation call; you can't change the column set of asimplechecklist, you have to make atask-type board. DELETE /api/tasks/{taskId}/statuses/{statusId}auto-reassigns items in that column to the first available status — safe but irreversible.- Jennifer is
isSuperAdmin: true, so admin endpoints work, but still scope queries to her own data when possible (/api/summarywithout?username=) to avoid leaking other users' totals in chat. - The web UI (
/api,/docs) at10.0.0.213:3000returns the login HTML — those paths are for the browser, not API clients. Stick to/api/*paths. - "Audit log" queries can be heavy. Default
limit=50; cap to ≤100 unless explicitly asked for more.
Verification
Run these in order to confirm the skill is wired up:
# 1. Health
curl -s -H "x-api-key: ck_d8a1062be432e58b66c453a8f4c39fb4" \
http://10.0.0.213:3000/api/health
# expect: {"status":"healthy","version":"1.25.1",...}
# 2. Identity
curl -s -H "x-api-key: ck_d8a1062be432e58b66c453a8f4c39fb4" \
http://10.0.0.213:3000/api/user
# expect: {"user":{"username":"Jennifer","isAdmin":true,"isSuperAdmin":true}}
If either fails with HTTP 307 → /auth/login, the key is wrong or the server is misconfigured. Re-check JOTTY_API_KEY.
Source
API behavior verified against Jotty v1.25.1 on 2026-07-04 from this profile. Docs mirrored from https://github.com/fccview/jotty/blob/main/howto/API.md (last commit 3307091, Jun 14 2026). If the server upgrades past v1.25.1, re-run the two verification curls and update the version field.