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"}.
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.
{
"id": "11111111-1111-4111-8111-111111111111",
"email": "[email protected]",
"first_name": "Ada",
"last_name": "Lovelace",
"display_name": "ada",
"avatar": null
}{ "error": "Invalid or expired API key" }{ "error": "Too many requests" }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 membersGET/workspaces/{slug}/projects/listPOST/workspaces/{slug}/projects/createGET/workspaces/{slug}/projects/{id}/retrievePATCH/workspaces/{slug}/projects/{id}/updatePOST/workspaces/{slug}/projects/{id}/archive/archivePOST/workspaces/{slug}/projects/{id}/unarchive/restoreDELETE/workspaces/{slug}/projects/{id}/deleteGET/workspaces/{slug}/projects/{id}/members/list membersPOST/workspaces/{slug}/projects/{id}/members/add membersPATCH/workspaces/{slug}/projects/{id}/members/{member_id}/update roleDELETE/workspaces/{slug}/projects/{id}/members/{member_id}/remove
{
"name": "Website relaunch",
"identifier": "WEB"
}{
"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"
}[
{
"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"
}
]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/listPOST/workspaces/{slug}/projects/{id}/issues/createGET/workspaces/{slug}/projects/{id}/issues/{issue_id}/retrievePATCH/workspaces/{slug}/projects/{id}/issues/{issue_id}/updateDELETE/workspaces/{slug}/projects/{id}/issues/{issue_id}/deleteGET/workspaces/{slug}/projects/{id}/issues/{issue_id}/comments/list commentsPOST/workspaces/{slug}/projects/{id}/issues/{issue_id}/comments/add commentGET/workspaces/{slug}/projects/{id}/issues/{issue_id}/activities/activity logGET/workspaces/{slug}/projects/{id}/issues/{issue_id}/links/external linksGET/workspaces/{slug}/projects/{id}/issues/{issue_id}/relations/issue relations
{
"name": "Fix checkout totals",
"priority": "high"
}{
"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"
}{
"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"
}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/listPOST/workspaces/{slug}/projects/{id}/pages/createGET/workspaces/{slug}/projects/{id}/pages/{page_id}/retrievePATCH/workspaces/{slug}/projects/{id}/pages/{page_id}/updateDELETE/workspaces/{slug}/projects/{id}/pages/{page_id}/deletePOST/workspaces/{slug}/projects/{id}/pages/{page_id}/description/replace descriptionPOST/workspaces/{slug}/projects/{id}/pages/{page_id}/archive/archiveDELETE/workspaces/{slug}/projects/{id}/pages/{page_id}/archive/restore
{
"name": "Hero banner"
}{
"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"
}{
"description_html": "<p>Launch checklist and notes.</p>",
"description_json": { "type": "doc", "content": [] }
}{
"id": "44444444-4444-4444-8444-444444444444",
"name": "Hero banner",
"description_html": "<p>Launch checklist and notes.</p>",
"updated_at": "2026-10-30T13:20:00Z"
}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/listPOST/workspaces/{slug}/projects/{id}/forms/createGET/workspaces/{slug}/projects/{id}/forms/{form_id}/retrievePATCH/workspaces/{slug}/projects/{id}/forms/{form_id}/updateGET/workspaces/{slug}/projects/{id}/forms/{form_id}/responses/responses
{
"name": "Bug report",
"description": "Report a problem with the app"
}{
"id": "55555555-5555-4555-8555-555555555555",
"name": "Bug report",
"accepting": true,
"share_token": null,
"field_count": 0,
"updated_at": "2026-10-30T12:00:00Z"
}[
{
"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/listPOST/workspaces/{slug}/assets/reserveGET/workspaces/{slug}/assets/{asset_id}/retrievePUT/workspaces/{slug}/assets/{asset_id}/upload/upload bytesDELETE/workspaces/{slug}/assets/{asset_id}/delete
{
"name": "logo.png",
"size": 40210
}{
"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
}{
"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"
}# 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.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{ "name": "list_projects" },
{ "name": "list_issues" },
{ "name": "create_issue" }
]
}
}{
"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.