DoneNestDevelopers
Start free trial

API documentation

DoneNest public developer API — token-authenticated REST endpoints for projects, work items, pages, forms, and assets, plus an MCP server.

Overview

DoneNest exposes a token-authenticated REST API under /api/v1. It covers the same objects you see in the app: workspaces, projects, work items, pages, forms, and file assets.

The base URL is https://donenest.com/api/v1. Request and response bodies are JSON with snake_case keys. Ids are UUIDs and timestamps are RFC 3339 in UTC.

List endpoints return JSON arrays. Errors return an HTTP status code with a JSON body like {"error": "Project not found"}.

List projects in a workspace
curl -H "X-Api-Key: YOUR_KEY" \
  https://donenest.com/api/v1/workspaces/your-workspace/projects/

Authentication

Create an API key in Settings → Developer. The key is shown once — copy it before closing the dialog.

Send the key in the X-Api-Key header on every request. Optionally bind a key to one workspace when you create it; a bound key cannot read other workspaces.

Keys are rate limited to 60 requests per minute. Exceeding the limit returns 429.

Get the current user
GET/users/me/Request
X-Api-Key: YOUR_KEY
200Response
{
  "id": "11111111-1111-4111-8111-111111111111",
  "email": "[email protected]",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "display_name": "ada",
  "avatar": null
}
Missing or invalid API key
GET/users/me/Request
X-Api-Key: dn_live_expired
401Response
{ "error": "Invalid or expired API key" }
Rate limited — over 60 requests per minute
GET/users/me/Request
X-Api-Key: YOUR_KEY
429Response
{ "error": "Too many requests" }
Authenticated request
curl -H "X-Api-Key: dn_live_..." \
  https://donenest.com/api/v1/users/me/

Projects

Projects live under a workspace slug. Members are managed on the project; workspace members are listed on the workspace.

Planning helpers are available on the same project path — /states/, /labels/, /estimates/, /cycles/, and /modules/. See the OpenAPI spec for their fields.

  • GET/workspaces/{slug}/members/workspace members
  • GET/workspaces/{slug}/projects/list
  • POST/workspaces/{slug}/projects/create
  • GET/workspaces/{slug}/projects/{id}/retrieve
  • PATCH/workspaces/{slug}/projects/{id}/update
  • POST/workspaces/{slug}/projects/{id}/archive/archive
  • POST/workspaces/{slug}/projects/{id}/unarchive/restore
  • DELETE/workspaces/{slug}/projects/{id}/delete
  • GET/workspaces/{slug}/projects/{id}/members/list members
  • POST/workspaces/{slug}/projects/{id}/members/add members
  • PATCH/workspaces/{slug}/projects/{id}/members/{member_id}/update role
  • DELETE/workspaces/{slug}/projects/{id}/members/{member_id}/remove
Create a project
POST/workspaces/acme/projects/Request
X-Api-Key: YOUR_KEY
{
  "name": "Website relaunch",
  "identifier": "WEB"
}
201Response
{
  "id": "22222222-2222-4222-8222-222222222222",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "name": "Website relaunch",
  "description": "",
  "identifier": "WEB",
  "emoji": null,
  "created_at": "2026-10-30T12:00:00Z",
  "updated_at": "2026-10-30T12:00:00Z"
}
List projects in a workspace
GET/workspaces/acme/projects/Request
X-Api-Key: YOUR_KEY
200Response
[
  {
    "id": "22222222-2222-4222-8222-222222222222",
    "workspace_id": "00000000-0000-4000-8000-000000000000",
    "name": "Website relaunch",
    "identifier": "WEB",
    "emoji": null,
    "created_at": "2026-10-30T12:00:00Z",
    "updated_at": "2026-10-30T12:00:00Z"
  },
  {
    "id": "99999999-9999-4999-8999-999999999999",
    "workspace_id": "00000000-0000-4000-8000-000000000000",
    "name": "Mobile app",
    "identifier": "MOB",
    "emoji": null,
    "created_at": "2026-09-14T08:30:00Z",
    "updated_at": "2026-10-01T17:45:00Z"
  }
]
Create a project
curl -X POST -H "X-Api-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Website relaunch", "identifier": "WEB"}' \
  https://donenest.com/api/v1/workspaces/your-workspace/projects/

Issues

Work items are available at both /issues/ and /work-items/ — the paths are aliases with identical behavior.

Fields include name, description_html, priority (urgent, high, medium, low, none), state_id, start_date, target_date, assignees, and labels.

  • GET/workspaces/{slug}/projects/{id}/issues/list
  • POST/workspaces/{slug}/projects/{id}/issues/create
  • GET/workspaces/{slug}/projects/{id}/issues/{issue_id}/retrieve
  • PATCH/workspaces/{slug}/projects/{id}/issues/{issue_id}/update
  • DELETE/workspaces/{slug}/projects/{id}/issues/{issue_id}/delete
  • GET/workspaces/{slug}/projects/{id}/issues/{issue_id}/comments/list comments
  • POST/workspaces/{slug}/projects/{id}/issues/{issue_id}/comments/add comment
  • GET/workspaces/{slug}/projects/{id}/issues/{issue_id}/activities/activity log
  • GET/workspaces/{slug}/projects/{id}/issues/{issue_id}/links/external links
  • GET/workspaces/{slug}/projects/{id}/issues/{issue_id}/relations/issue relations
Create a work item
POST/workspaces/acme/projects/22222222-2222-4222-8222-222222222222/issues/Request
X-Api-Key: YOUR_KEY
{
  "name": "Fix checkout totals",
  "priority": "high"
}
201Response
{
  "id": "33333333-3333-4333-8333-333333333333",
  "project_id": "22222222-2222-4222-8222-222222222222",
  "name": "Fix checkout totals",
  "priority": "high",
  "sequence_id": 42,
  "state_id": null,
  "start_date": null,
  "target_date": null,
  "created_at": "2026-10-30T12:00:00Z",
  "updated_at": "2026-10-30T12:00:00Z"
}
Retrieve a work item
GET/workspaces/acme/projects/22222222-2222-4222-8222-222222222222/issues/33333333-3333-4333-8333-333333333333/Request
X-Api-Key: YOUR_KEY
200Response
{
  "id": "33333333-3333-4333-8333-333333333333",
  "project_id": "22222222-2222-4222-8222-222222222222",
  "name": "Fix checkout totals",
  "priority": "high",
  "sequence_id": 42,
  "state_id": "88888888-8888-4888-8888-888888888888",
  "assignee_ids": ["11111111-1111-4111-8111-111111111111"],
  "label_ids": [],
  "description_html": "<p>Rounding error on multi-currency orders.</p>",
  "created_at": "2026-10-30T12:00:00Z",
  "updated_at": "2026-10-30T13:15:00Z"
}
Create a work item
curl -X POST -H "X-Api-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Fix checkout totals", "priority": "high"}' \
  https://donenest.com/api/v1/workspaces/your-workspace/projects/PROJECT_ID/issues/

Pages & designs

Pages are project documents. /sheets/, /slides/, and /designs/ are aliases of /pages/ with a fixed kind — every operation below works on each alias.

POST .../description/ replaces a page's description. It accepts plain text, HTML, or a JSON document string; designs use the JSON form for canvas content.

Archive with POST .../archive/ and restore with DELETE .../archive/.

  • GET/workspaces/{slug}/projects/{id}/pages/list
  • POST/workspaces/{slug}/projects/{id}/pages/create
  • GET/workspaces/{slug}/projects/{id}/pages/{page_id}/retrieve
  • PATCH/workspaces/{slug}/projects/{id}/pages/{page_id}/update
  • DELETE/workspaces/{slug}/projects/{id}/pages/{page_id}/delete
  • POST/workspaces/{slug}/projects/{id}/pages/{page_id}/description/replace description
  • POST/workspaces/{slug}/projects/{id}/pages/{page_id}/archive/archive
  • DELETE/workspaces/{slug}/projects/{id}/pages/{page_id}/archive/restore
Create a design page
POST/workspaces/acme/projects/22222222-2222-4222-8222-222222222222/designs/Request
X-Api-Key: YOUR_KEY
{
  "name": "Hero banner"
}
201Response
{
  "id": "44444444-4444-4444-8444-444444444444",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "name": "Hero banner",
  "parent_id": null,
  "logo_props": { "kind": "design" },
  "project_ids": ["22222222-2222-4222-8222-222222222222"],
  "is_locked": false,
  "archived_at": null,
  "created_at": "2026-10-30T12:00:00Z",
  "updated_at": "2026-10-30T12:00:00Z"
}
Replace a page description
POST/workspaces/acme/projects/22222222-2222-4222-8222-222222222222/pages/44444444-4444-4444-8444-444444444444/description/Request
X-Api-Key: YOUR_KEY
{
  "description_html": "<p>Launch checklist and notes.</p>",
  "description_json": { "type": "doc", "content": [] }
}
200Response
{
  "id": "44444444-4444-4444-8444-444444444444",
  "name": "Hero banner",
  "description_html": "<p>Launch checklist and notes.</p>",
  "updated_at": "2026-10-30T13:20:00Z"
}
Create a design page and set its description
curl -X POST -H "X-Api-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"name": "Hero banner"}' \
  https://donenest.com/api/v1/workspaces/your-workspace/projects/PROJECT_ID/designs/

Forms

Forms collect structured responses on a project. Responses are listed newest first, up to 200 per request.

  • GET/workspaces/{slug}/projects/{id}/forms/list
  • POST/workspaces/{slug}/projects/{id}/forms/create
  • GET/workspaces/{slug}/projects/{id}/forms/{form_id}/retrieve
  • PATCH/workspaces/{slug}/projects/{id}/forms/{form_id}/update
  • GET/workspaces/{slug}/projects/{id}/forms/{form_id}/responses/responses
Create a form
POST/workspaces/acme/projects/22222222-2222-4222-8222-222222222222/forms/Request
X-Api-Key: YOUR_KEY
{
  "name": "Bug report",
  "description": "Report a problem with the app"
}
201Response
{
  "id": "55555555-5555-4555-8555-555555555555",
  "name": "Bug report",
  "accepting": true,
  "share_token": null,
  "field_count": 0,
  "updated_at": "2026-10-30T12:00:00Z"
}
List form responses
GET/workspaces/acme/projects/22222222-2222-4222-8222-222222222222/forms/55555555-5555-4555-8555-555555555555/responses/Request
X-Api-Key: YOUR_KEY
200Response
[
  {
    "id": "66666666-6666-4666-8666-666666666666",
    "submitted_at": "2026-10-30T11:42:00Z",
    "answers": {
      "summary": "Checkout button is missing",
      "severity": "high"
    },
    "issue_id": "33333333-3333-4333-8333-333333333333"
  }
]

Assets

File upload is two steps. POST /assets/ with the file name and size to reserve an asset id — the response includes upload_url and asset_url.

PUT the raw file bytes to upload_url with the correct Content-Type header. Once uploaded, the file is served at /media/{asset_id}.

  • GET/workspaces/{slug}/assets/list
  • POST/workspaces/{slug}/assets/reserve
  • GET/workspaces/{slug}/assets/{asset_id}/retrieve
  • PUT/workspaces/{slug}/assets/{asset_id}/upload/upload bytes
  • DELETE/workspaces/{slug}/assets/{asset_id}/delete
Reserve an asset
POST/workspaces/acme/assets/Request
X-Api-Key: YOUR_KEY
{
  "name": "logo.png",
  "size": 40210
}
201Response
{
  "id": "77777777-7777-4777-8777-777777777777",
  "upload_url": "/api/v1/workspaces/acme/assets/77777777-7777-4777-8777-777777777777/upload/",
  "asset_url": "/media/77777777-7777-4777-8777-777777777777",
  "is_uploaded": false
}
Upload the file bytes — raw body, not JSON
PUT/workspaces/acme/assets/77777777-7777-4777-8777-777777777777/upload/Request
X-Api-Key: YOUR_KEY
Content-Type: image/png
200Response
{
  "id": "77777777-7777-4777-8777-777777777777",
  "name": "logo.png",
  "size": 40210,
  "content_type": "image/png",
  "asset_url": "/media/77777777-7777-4777-8777-777777777777",
  "is_uploaded": true,
  "created_at": "2026-10-30T12:00:00Z"
}
Upload a file
# 1. Reserve the asset
curl -X POST -H "X-Api-Key: YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"name": "logo.png", "size": 40210}' \
  https://donenest.com/api/v1/workspaces/your-workspace/assets/

# 2. PUT the bytes to the upload_url from step 1
curl -X PUT -H "X-Api-Key: YOUR_KEY" -H "Content-Type: image/png" \
  --data-binary @logo.png \
  https://donenest.com/api/v1/workspaces/your-workspace/assets/ASSET_ID/upload/

MCP

DoneNest exposes a streamable-HTTP MCP endpoint at {origin}/mcp. Authenticate with the same X-Api-Key header — no OAuth flow.

Available tools: list_projects, get_project, list_issues, create_issue, update_issue, list_pages, get_page, create_page, update_page_description, list_assets, list_cycles, list_modules.

In Cursor, add a remote MCP server pointing at https://donenest.com/mcp with the X-Api-Key header.

List available tools (JSON-RPC)
POST/mcpRequest
X-Api-Key: YOUR_KEY
Content-Type: application/json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
200Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      { "name": "list_projects" },
      { "name": "list_issues" },
      { "name": "create_issue" }
    ]
  }
}
Cursor / client MCP config
{
  "mcpServers": {
    "donenest": {
      "url": "https://donenest.com/mcp",
      "headers": { "X-Api-Key": "YOUR_KEY" }
    }
  }
}

OpenAPI

The full machine-readable spec is served same-origin. Import it into Postman or Insomnia, or feed it to an OpenAPI client generator.

/openapi/v1.json