Skip to content

Latest commit

 

History

History
505 lines (379 loc) · 12 KB

File metadata and controls

505 lines (379 loc) · 12 KB

Workflowy Proxy API Documentation

Overview

This proxy mirrors the Workflowy API at /api/v1/* endpoints, adding caching, rate limiting, and authentication.

Workflowy API Reference: https://beta.workflowy.com/api-reference/

Authentication

If the API_KEY environment variable is set, all /api/v1/* endpoints require authentication.

Header: Authorization: Bearer <API_KEY>

Example:

curl -H "Authorization: Bearer your-api-key" http://localhost:8168/api/v1/targets

Unauthenticated endpoints (no authentication required):

  • GET /healthcheck
  • GET /ready
  • GET /version

Error Responses

All errors follow the Workflowy error format:

{
  "error": "Error description"
}

Status Codes:

  • 400 Bad Request - Invalid request
  • 401 Unauthorized - Missing or invalid API key
  • 404 Not Found - Resource not found
  • 429 Too Many Requests - Rate limited
  • 500 Internal Server Error - Server error
  • 502 Bad Gateway - Upstream Workflowy error
  • 504 Gateway Timeout - Upstream request timeout

Cache Headers

All responses include cache status headers:

Header Values Description
X-Cache HIT, MISS, STALE Cache status
X-Cache-Source response, node-cache Where the cached data came from
X-Cache-Age Integer Age of cached entry in seconds
X-Cache-Bypass-Ignored rate-limit Present when bypass was ignored

Cache Bypass

Add X-Cache-Bypass: true header to force a fresh fetch from Workflowy.

Note: Cache bypass is ignored for rate-limited endpoints when within the rate limit window.


System Endpoints

GET /healthcheck

Health check endpoint. Always returns healthy if the server is running.

Response:

{
  "status": "healthy"
}

GET /ready

Readiness check endpoint. Returns healthy when the server is ready to accept requests.

Response:

{
  "status": "healthy"
}

GET /version

Returns version information about the running instance.

Response:

{
  "commit": "abc123def",
  "date": "2024-01-15T10:30:00Z"
}

Note: Returns null values if version.json is not present (local development).


WorkFlowy Rate Limiting

The WorkFlowy API uses a bucket-based rate limit:

  • Each bucket is 60 seconds long.
  • Within a bucket, you can make 60 requests.
  • If you exceed the limit, the API returns HTTP 429 with a message indicating how long until the current bucket resets and you can make requests again.
  • Because buckets are fixed time windows (not sliding windows), up to 120 requests can succeed within ~20 seconds if timed across a bucket boundary — 60 at the end of one bucket plus 60 at the start of the next.
  • The /nodes-export endpoint has a stricter limit of 1 request per bucket.

All endpoints share this rate limit unless noted otherwise.


Node Endpoints

All node endpoints proxy the official WorkFlowy API.

GET /api/v1/nodes

List children of a node, optionally with nested tree structure.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Query Parameters:

Parameter Required Default Description
parent_id No (root) ID of the parent node (use inbox for root nodes). Omit to get root nodes.
depth No 0 (Proxy-only) How many levels of children to nest in the response. 0 = flat list (no children expanded), 1 = include immediate children, etc. Not part of the official WorkFlowy API.

Depth behavior (Proxy-only):

  • depth=0 (default): Returns a flat list of nodes. Each node has children: null and has_children indicating whether children exist.
  • depth=1: Returns nodes with their immediate children nested in the children array. Children at the depth limit have children: null.
  • depth=N: Recursively nests children up to N levels deep.

When depth > 0, the proxy requires the export cache to build the tree. If the cache is empty, it automatically fetches /nodes-export from Workflowy first.

Nodes are sorted by priority (ascending) at every level of the tree.

Examples:

# Get root nodes (flat)
curl "http://localhost:8168/api/v1/nodes"

# Get children of a specific node
curl "http://localhost:8168/api/v1/nodes?parent_id=abc123"

# Get root nodes with one level of children
curl "http://localhost:8168/api/v1/nodes?depth=1"

# Get children of a node with 2 levels of nesting
curl "http://localhost:8168/api/v1/nodes?parent_id=abc123&depth=2"

# Workflowy-compatible style
curl -G http://localhost:8168/api/v1/nodes \
  -H "Authorization: Bearer <API_KEY>" \
  -d "parent_id=inbox"

Response (depth=0):

{
  "nodes": [
    {
      "id": "abc123",
      "name": "Node name",
      "note": null,
      "parent_id": "parent123",
      "priority": 1000,
      "completed": false,
      "layoutMode": "bullets",
      "children": null,
      "has_children": true,
      "createdAt": 1234567890,
      "modifiedAt": 1234567890,
      "completedAt": null
    }
  ]
}

Response (depth=1):

{
  "nodes": [
    {
      "id": "abc123",
      "name": "Node name",
      "note": null,
      "parent_id": "parent123",
      "priority": 1000,
      "completed": false,
      "layoutMode": "bullets",
      "children": [
        {
          "id": "child456",
          "name": "Child node",
          "parent_id": "abc123",
          "priority": 2000,
          "completed": false,
          "layoutMode": "bullets",
          "children": null,
          "has_children": false,
          "createdAt": 1234567890,
          "modifiedAt": 1234567890
        }
      ],
      "has_children": true,
      "createdAt": 1234567890,
      "modifiedAt": 1234567890,
      "completedAt": null
    }
  ]
}

has_children values (Proxy-only):

Value Meaning
true Node has children (known from export cache)
false Node has no children (known from export cache)
null Unknown (export cache not available, e.g. response served from Workflowy API directly)

GET /api/v1/nodes/:id

Get a single node by ID.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Path Parameters:

Parameter Description
id Node ID

Example:

curl http://localhost:8168/api/v1/nodes/abc123

Response:

{
  "id": "abc123",
  "name": "Node name",
  "note": "Node note",
  "parent_id": "parent123",
  "completed": null,
  "layout_mode": null,
  "children": []
}

POST /api/v1/nodes

Create a new node.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Request Body:

{
  "parent_id": "parent123",
  "name": "New node name",
  "note": "Optional note"
}

Response:

{
  "status": "ok"
}

Cache Effect: Invalidates parent's children cache.

POST /api/v1/nodes/:id

Update an existing node.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Path Parameters:

Parameter Description
id Node ID

Request Body:

{
  "name": "Updated name",
  "note": "Updated note"
}

Response:

{
  "status": "ok"
}

Cache Effect: Invalidates the node's cache entry.

DELETE /api/v1/nodes/:id

Delete a node.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Path Parameters:

Parameter Description
id Node ID

Example:

curl -X DELETE http://localhost:8168/api/v1/nodes/abc123

Response:

{
  "status": "ok"
}

Cache Effect: Invalidates the node's cache and all parent caches.

POST /api/v1/nodes/:id/move

Move a node to a new parent.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Path Parameters:

Parameter Description
id Node ID

Request Body:

{
  "parent_id": "new_parent123",
  "position": 0
}

Response:

{
  "status": "ok"
}

Cache Effect: Invalidates all parent caches.

POST /api/v1/nodes/:id/complete

Mark a node as complete.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Path Parameters:

Parameter Description
id Node ID

Example:

curl -X POST http://localhost:8168/api/v1/nodes/abc123/complete

Response:

{
  "status": "ok"
}

Cache Effect: Invalidates the node's cache entry.

POST /api/v1/nodes/:id/uncomplete

Mark a node as incomplete.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Path Parameters:

Parameter Description
id Node ID

Example:

curl -X POST http://localhost:8168/api/v1/nodes/abc123/uncomplete

Response:

{
  "status": "ok"
}

Cache Effect: Invalidates the node's cache entry.


Export Endpoints

GET /api/v1/nodes-export

Export all nodes from Workflowy. This endpoint is rate limited. Proxies the official WorkFlowy API.

WorkFlowy Rate Limit: 1 request per 60-second bucket (see WorkFlowy Rate Limiting).

Proxy Rate Limit: Minimum 60 seconds between calls (configurable via NODES_EXPORT_CACHE_TTL_SECS).

Example:

curl http://localhost:8168/api/v1/nodes-export

Response: Complete tree of all nodes.

Cache Effect:

  • Caches the full export response
  • Populates the node cache for fast individual lookups

Note: Cache bypass header is ignored when rate limited.

GET /api/v1/nodes-export-cache (Proxy-Only)

Warm the node cache without returning the full export data. Useful for pre-warming caches. This endpoint is not part of the WorkFlowy API.

Rate Limit: Same as /nodes-export.

Example:

curl http://localhost:8168/api/v1/nodes-export-cache

Response:

{
  "status": "ok",
  "cached_nodes": 1234
}

Targets Endpoint

GET /api/v1/targets

List all targets (shortcuts/starred items). Proxies the official WorkFlowy API.

WorkFlowy Rate Limit: 60 requests per 60-second bucket (see WorkFlowy Rate Limiting).

Example:

curl http://localhost:8168/api/v1/targets

Response: Array of target objects.


Node Object

{
  "id": "string",
  "name": "string | null",
  "note": "string | null",
  "parent_id": "string | null",
  "priority": "number | null",
  "completed": "boolean | null",
  "layoutMode": "string | null",
  "children": "Node[] | null",
  "has_children": "boolean | null",
  "createdAt": "number | null",
  "modifiedAt": "number | null",
  "completedAt": "number | null"
}
Field Type Description
id string Unique node identifier
name string? Node title/name
note string? Node description/note
parent_id string? Parent node ID (null for root)
priority number? Sort priority (lower = higher in list)
completed boolean? Whether the node is completed
layoutMode string? Layout mode (e.g. "bullets")
children Node[]? (Proxy-only) Child nodes (populated when depth > 0, null otherwise). Not part of the official WorkFlowy API.
has_children boolean? (Proxy-only) true if children exist, false if none, null if unknown. Not part of the official WorkFlowy API.
createdAt number? Creation timestamp (Unix seconds)
modifiedAt number? Last modification timestamp (Unix seconds)
completedAt number? Completion timestamp (Unix seconds, null if not completed)