Workflowy API
Access a Workflowy outline through its official REST API. There is no MCP connector; use curl.
Detailed reference: references/api-reference.md (load on demand for full parameter tables and schemas).
Authentication
Every request needs the header Authorization: Bearer <API_KEY>.
- Never hardcode the key in this skill or in scripts. Read it at call time from the environment variable
$WORKFLOWY_API_KEY. - If
$WORKFLOWY_API_KEYis unset, ask the user for their key (or tell them toexport WORKFLOWY_API_KEY=...). A key is generated at https://workflowy.com/api-key and does not expire. - Base URL:
https://workflowy.com/api/v1.
Rate limits
GET /nodes-export: 1 request per minute (large response). Prefer this over walking the tree level by level when you need most of the outline.- All other endpoints: no documented rate limit; still avoid tight polling loops.
Node model
Standard node (list, retrieve, create/update responses)
{
"id": "874e6591-350f-4dbb-0f92-5310e59369d3",
"name": "AI Messages",
"note": null,
"parent_id": null,
"priority": 25,
"data": { "layoutMode": "bullets" },
"createdAt": 1757675725,
"modifiedAt": 1757675725,
"completedAt": null
}
Completion state is tracked by completedAt (Unix seconds, or null if not completed). There is no completed field in standard responses.
Export node (GET /nodes-export only)
Same fields as above, plus "completed": false. Use export when you need a boolean completion flag alongside the full flat list.
parent_id: null means a root-level bullet. Timestamps are Unix seconds.
Sorting and hierarchy
GET /nodes and GET /nodes-export return nodes unordered. Sort siblings by priority (lower = first) and rebuild the tree using parent_id.
parent_id / target values
parent_id (on create, list, move) and :id (on retrieve) accept:
- Full node ID or 12-character short ID from a Workflowy URL
- Workflowy URL (e.g.
https://workflowy.com/#/d8754237b505) - User-defined shortcut keys (e.g.
"home","rd") — discover withGET /targets "None"— root outline"inbox"— built-in inbox"calendar","today","tomorrow","next_week"- Calendar dates:
"YYYY","YYYY-MM","YYYY-MM-DD"
To list root-level bullets, use parent_id=None.
Calendar targets
| Operation | Behavior |
|---|---|
| Create / Move | Calendar nodes are created on demand if missing |
List (GET /nodes) |
Calendar targets return 404 if the node does not exist yet — create or move into it first |
Retrieve (GET /nodes/:id) |
Resolves existing calendar nodes only; does not create missing ones |
Targets (shortcuts)
GET /targets returns system targets (inbox, etc.) and user-defined shortcuts.
{
"targets": [
{ "key": "home", "type": "shortcut", "name": "My Home Page" },
{ "key": "inbox", "type": "system", "name": "Inbox" }
]
}
key— use asparent_idor path:idtype—"shortcut"(user-defined) or"system"(built-in)name— node title;nullfor system targets whose node has not been created yet
Markdown in name (create / update)
The API parses markdown in name on POST /nodes and POST /nodes/:id:
- Multiline: first line becomes the node; lines separated by
\n\nbecome child nodes (\nalone is joined into a space). - Inline styles:
**bold**,*italic*,~~strike~~,`code`,[text](url),[YYYY-MM-DD],[YYYY-MM-DD HH:MM]. - Layout prefixes:
#→ h1,##→ h2,###→ h3,- [ ]/- [x]→ todo,```→ code-block,>→ quote-block. Alternatively passlayoutModeexplicitly.
Finding content (no search endpoint)
There is no search API. Options:
GET /nodes-export— one call for everything (1 req/min limit), then filter client-side.GET /nodes— walk children level by level when you know the parent; more calls but no export rate limit.
Endpoints
All paths are under https://workflowy.com/api/v1.
| Action | Method | Path | Notes |
|---|---|---|---|
| List children | GET | /nodes |
query parent_id; sort by priority |
| Retrieve one | GET | /nodes/:id |
returns {"node": {...}}; :id accepts IDs, shortcuts, calendar targets |
| Export all | GET | /nodes-export |
flat list; 1 req/min; includes completed |
| Create | POST | /nodes |
requires name |
| Update | POST | /nodes/:id |
name, note, layoutMode |
| Move | POST | /nodes/:id/move |
parent_id, position |
| Complete | POST | /nodes/:id/complete |
— |
| Uncomplete | POST | /nodes/:id/uncomplete |
— |
| Delete | DELETE | /nodes/:id |
permanent |
| List targets | GET | /targets |
shortcuts + system targets |
Create parameters (POST /nodes)
name(required, string)parent_id(optional; see values above)note(optional, string)position(optional):"top"or"bottom"(defaulttop)layoutMode(optional):"bullets","todo","h1","h2","h3","code-block","quote-block"
Response: {"item_id": "..."}. Update/move/complete/uncomplete/delete return {"status": "ok"}.
Examples
List root-level bullets:
curl -s -G "https://workflowy.com/api/v1/nodes" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY" \
--data-urlencode "parent_id=None"
List children of a specific node:
curl -s -G "https://workflowy.com/api/v1/nodes" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY" \
--data-urlencode "parent_id=<NODE_ID>"
Retrieve one node (by ID, shortcut, or calendar target):
curl -s "https://workflowy.com/api/v1/nodes/today" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
curl -s "https://workflowy.com/api/v1/nodes/<NODE_ID>" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
List targets (discover shortcuts):
curl -s "https://workflowy.com/api/v1/targets" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
Export the entire outline (1 req/min):
curl -s "https://workflowy.com/api/v1/nodes-export" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
Create a bullet:
curl -s -X POST "https://workflowy.com/api/v1/nodes" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY" \
-d '{"parent_id":"inbox","name":"Hello API","note":"optional","position":"top"}'
Update / move / complete / uncomplete / delete:
curl -s -X POST "https://workflowy.com/api/v1/nodes/<ID>" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY" \
-d '{"name":"New title"}'
curl -s -X POST "https://workflowy.com/api/v1/nodes/<ID>/move" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY" \
-d '{"parent_id":"<TARGET>","position":"bottom"}'
curl -s -X POST "https://workflowy.com/api/v1/nodes/<ID>/complete" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
curl -s -X POST "https://workflowy.com/api/v1/nodes/<ID>/uncomplete" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
curl -s -X DELETE "https://workflowy.com/api/v1/nodes/<ID>" \
-H "Authorization: Bearer $WORKFLOWY_API_KEY"
Tips
- Add
-w "\n[HTTP %{http_code}]\n"to curl to surface the status code. - Guessed hosts like
https://workflowy.com/api/bullets/...return the marketing HTML page, not JSON. Always use the/api/v1/...paths above. - Official docs: https://workflowy.com/api-reference/