TaskPrio ← board  ·  llms.txt  ·  openapi.json

API reference

TaskPrio is agent-native. Everything the board does, agents can do over HTTP or the built-in MCP server. One queue, one priority order, top to bottom.

Contents

Auth

Two ways to authenticate: Bearer token (agents · CLI · curl) or session cookie (the board · set by Google Sign-In). Bearer is the agent path.

Get your token from the account dialog: click Connect on the board → sign in with Google → click your account chip → Copy agent token. Then put it in your shell config — never paste a bearer token into a chat:

# macOS / zsh — paste your real token in place of the placeholder
printf '\nexport PROMPTPRIO_API_TOKEN="REPLACE_ME"\n' >> ~/.zshenv
source ~/.zshenv

All authenticated requests need the header:

Authorization: Bearer $PROMPTPRIO_API_TOKEN

To rotate your token (the old one stops working immediately):

curl -X POST https://promptprio.com/api/auth/token/rotate \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN"
# → { "apiToken": "pp_..." }

To check who you are:

curl https://promptprio.com/api/auth/me \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN"
# → { "user": { "id": ..., "email": ..., "plan": ..., "apiToken": ... }, "via": "token" }

Note: a 401 response on /api/auth/me means your token is invalid; on any other path it usually means your token is fine but the route doesn't exist (catch-all auth gate fires before 404).

MCP server

Native to Claude Code · Cursor · ChatGPT. Same tools as the REST API; the agent calls them by name instead of curl.

1-command install (recommended)

Open the Account dialog (sidebar foot → your email) → click Install MCP (1 command). Paste the copied command into your terminal. Done.

 PROMPTPRIO_API_TOKEN=pp_xxx bash <(curl -fsSL https://promptprio.com/install.sh)

What it does:

  1. Verifies your token against /api/auth/me.
  2. Downloads the bundled MCP server to ~/.local/share/promptprio/mcp-server.js.
  3. Merges a promptprio entry into ~/.claude/mcp.json (preserves your other servers).

Re-run any time to update — idempotent. Then restart Claude Code and ask "list my promptprio tasks".

Note: the leading space in the command keeps the token out of ~/.zsh_history on most shells.

Manual install (JSON config)

If you'd rather edit ~/.claude/mcp.json yourself, use the Copy MCP config button. The snippet is self-installing — first run caches the bundled server, subsequent runs reuse it:

{
  "mcpServers": {
    "promptprio": {
      "command": "bash",
      "args": ["-c", "mkdir -p ~/.local/share/promptprio && [ -s ~/.local/share/promptprio/mcp-server.js ] || curl -fsSL https://promptprio.com/mcp-server.js -o ~/.local/share/promptprio/mcp-server.js; exec node ~/.local/share/promptprio/mcp-server.js"],
      "env": {
        "PROMPTPRIO_API_TOKEN": "pp_…",
        "PROMPTPRIO_API_URL": "https://taskprio.com"
      }
    }
  }
}

From source (development)

Clone the repo and run with tsx:

git clone https://gitlab.com/acevault-lab/promptprio-com.git
cd promptprio-com
npm install
PROMPTPRIO_API_TOKEN="$PROMPTPRIO_API_TOKEN" npm run mcp

Then point at src/server/mcp.ts in your MCP config:

{
  "mcpServers": {
    "promptprio": {
      "command": "node",
      "args": ["--import", "tsx", "/path/to/promptprio-com/src/server/mcp.ts"],
      "env": { "PROMPTPRIO_API_TOKEN": "$PROMPTPRIO_API_TOKEN" }
    }
  }
}

Tools exposed: get_next_task, list_tasks, search_tasks, export_queue, create_task, triage_task, update_task, reprioritize_task, schedule_task, complete_task, flag_needs_human, add_project.

Board read

GET /api/board

All non-terminal tasks + projects + organisations + single-select lists, in one round trip. The board UI uses this on load and every 15 s.

curl https://promptprio.com/api/board \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN"
# → { tasks: [...], projects: [...], organisations: [...], selectLists: [...] }

Get next task

GET /api/next

Returns the single highest-priority actionable task, leased to your agent for 15 minutes. Optional query params: project, agent, count.

Response includes context — the merged system prompt for that task (project Stack/Commands/Don't/Persona/Done/Notes + the task body itself).

curl https://promptprio.com/api/next \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN"
# → { task: {...}, priority: 1, context: "# Project: ...\n## Persona\n..." }
# When the queue is empty: { task: null }

Batch mode (multiple tasks at once):

curl 'https://promptprio.com/api/next?count=5&agent=claude-code' \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN"
# → { tasks: [...up to 5...] }

Tasks CRUD

POST /api/tasks

Create a task. place: inbox (default) · top · bottom.

curl -X POST https://promptprio.com/api/tasks \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Refactor the auth middleware",
    "body": "Extract token validation into lib/auth.ts and add tests.",
    "projectId": "proj_...",
    "assignee": "llm",
    "place": "top",
    "subtasks": [{"title":"Write tests","done":false}]
  }'

GET /api/tasks

List ranked tasks. Filter with ?project=... or ?status=....

GET /api/tasks/{id}

Fetch a single task by id.

PATCH /api/tasks/{id}

Update any of: title, body, assignee, projectId, tags, scheduledFor, dependsOn, attachments, subtasks, status, selectValues.

# set Status property to "Doing" + reassign to your agent
curl -X PATCH https://promptprio.com/api/tasks/$TASK_ID \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "assignee": "llm", "selectValues": { "list_status": "opt_doing" } }'

DELETE /api/tasks/{id}

Soft-delete (moves to trash; recoverable via POST /api/tasks/{id}/restore).

Complete · needs human · schedule · reprioritize

POST /api/tasks/{id}/complete

Mark done. result is required (one-line summary; agents log what they did).

curl -X POST https://promptprio.com/api/tasks/$TASK_ID/complete \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "result": "Extracted to lib/auth.ts. 12 tests added, all green." }'

POST /api/tasks/{id}/needs-human

Park the task — agent is blocked, operator needs to unblock. question is required.

POST /api/tasks/{id}/schedule

Defer until scheduledFor (epoch ms). Optional targetPriority for explicit slot on activation.

POST /api/tasks/{id}/reprioritize

Move within the single global queue. Body: {beforeId} · {afterId} · {top:true} · {bottom:true}.

POST /api/tasks/{id}/triage

Move an Inbox task into the ranked queue. Body: {place: "top"|"bottom"}.

Projects

GET /api/projects · POST /api/projects · PATCH /api/projects/{id} · DELETE /api/projects/{id}

Project fields: name, color, workingDir, instructions (Notes), organisationId, plus the structured LLM-context fields stack · commands · repo · dontDo · persona · definitionOfDone.

curl -X POST https://promptprio.com/api/projects \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "myapp",
    "stack": "Next.js 14, TypeScript, Tailwind, Drizzle, Postgres",
    "commands": "dev: npm run dev\ntest: npm test\ndeploy: npm run deploy",
    "repo": "https://gitlab.com/me/myapp",
    "dontDo": "Don'\''t touch /legacy. Don'\''t add deps without asking."
  }'

POST /api/projects/reorder

Reorder columns. Body: {order: ["proj_a", "proj_b", ...]}. Any project not in the array keeps its existing position (appended).

Organisations

GET /api/organisations · POST /api/organisations · PATCH · DELETE · POST /api/organisations/reorder

Group projects in the board overview. Every cloud account has at least one ("Personal" by default). Deleting an org reparents its projects to the first remaining org.

Single-select properties

GET /api/select-lists · POST /api/select-lists · PATCH · DELETE

Reusable single-select lists — e.g. "Status" with options "Todo / Doing / Blocked / Done". Each task assigns one optionId per list.

curl -X POST https://promptprio.com/api/select-lists \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Status",
    "options": [{"label":"Todo"},{"label":"Doing"},{"label":"Done"}]
  }'

POST /api/select-lists/{id}/options · PATCH /api/select-lists/{id}/options/{optionId} · DELETE

Per-option CRUD. Deleting an option clears it from every task.

Export · search · upload

GET /api/export?format=md|json

Whole queue as markdown (ordered, id-tagged, with property tags inline) or JSON.

GET /api/search?q=<query>

Full-text against title · body · result. Same matching logic as the board search box.

POST /api/upload

Attach a file to a task. Body: raw bytes. Headers: Content-Type, X-Filename. Limits: 1 MB free · 4 MB Pro. Returns {url, name, type, size} — use the URL in the task's attachments field.

Webhooks

Opt-in outbound webhooks: TaskPrio POSTs a signed JSON payload to your URL when a task changes — the push alternative to the change-feed. HTTPS only; URLs are SSRF-guarded (private / loopback / link-local / cloud-metadata hosts are rejected). Delivery is best-effort with a ~2.5s timeout (no retry yet), so make your endpoint idempotent.

POST /api/webhooks

Subscribe. events defaults to ["*"] (all); valid values: task.created, task.updated, task.completed, task.deleted. The signing secret is returned once, here — store it. Up to 25 webhooks per account.

curl -X POST https://promptprio.com/api/webhooks \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/hook","events":["task.completed"]}'
# -> {"webhook":{"id":"...","url":"...","events":[...],"secret":"whsec_...","recent":[]}}

GET /api/webhooks

List your webhooks. The secret is masked (full value only at create). recent holds the last 20 delivery attempts (status · ok · error).

DELETE /api/webhooks/{id}

Unsubscribe.

Payload

{
  "event": "task.completed",
  "timestamp": "2026-06-02T09:00:00.000Z",
  "data": { "task": { /* full task */ }, "previous": { /* prior task — task.updated only */ } }
}

Headers: X-TaskPrio-Event and X-TaskPrio-Signature: sha256=<hex>.

Verify the signature

The signature is HMAC-SHA256(secret, rawRequestBody). Verify it before trusting a delivery:

import crypto from "node:crypto";
// `body` = the RAW request body string; `secret` = this webhook's signing secret
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(body).digest("hex");
const got = req.headers["x-promptprio-signature"] || "";
const ok = got.length === expected.length &&
  crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected));
if (!ok) return res.status(401).end(); // reject forgeries

Change-feed (polling)

GET /api/changes?since=<epoch-ms>

Returns {tasks, now} — every task (any status) updated at or after since, oldest-first, capped at 200. Poll on an interval and pass the previous response's now back as the next since; dedupe by task id. Completions and deletions appear here (with their new status) so a live view can drop them. Lighter than refetching /api/board; the push alternative is webhooks.

curl "https://promptprio.com/api/changes?since=0" \
  -H "Authorization: Bearer $PROMPTPRIO_API_TOKEN"
# -> {"tasks":[ ...changed, oldest-first... ],"now":1780000000000}
# next poll: use the returned `now` as ?since=

Errors

CodeMeaningCommon cause
200OK
201CreatedPOST succeeded
400Bad requestMissing required field (e.g. title, result, project name)
401UnauthorizedToken invalid OR you're hitting a route that doesn't exist (the auth-gate middleware fires before route-not-found)
402Payment requiredFree-tier cap hit (150 active tasks · 3 projects · 50 daily agent completions)
403ForbiddenToken missing a required scope
404Not foundTask / project / org / list id doesn't exist for your account
413Payload too largeAttachment exceeds size limit
500ServerStorage backend transient — retry with exponential backoff