# Taskwood API Core API: /api/v1. OpenAPI: /api/openapi.json. MCP: /mcp (Streamable HTTP JSON). Authenticate with an owner-issued personal Bearer token; read, write and attachments scopes are independent. 600 calls/minute/token, shared across REST and MCP. Never send a token in query parameters. Seed allows read + attachments scopes for reading owned photos/audio; API mutations still require a paid plan and write scope. Implemented: trees/projects/tasks CRUD, task notes/status/deadline, literal FTS5 search including transcripts, tree JSON export, HMAC cursor pagination and private ETags. updated_since is inclusive; deduplicate by id and fetch snapshots to observe hard deletions. Cursor ordering is stable by creation sequence and excludes new inserts after page one; it is not a frozen MVCC snapshot of content or filters. MCP: initialize stable 2025-11-25, then notifications/initialized. Send Accept: application/json, text/event-stream, MCP-Protocol-Version and Mcp-Session-Id. Tools: list_trees, list_tasks, get_task, search, create_task, complete_task, get_attachment, transcribe_audio. list_trees and list_tasks accept limit/cursor; follow next_cursor until null. Resource: taskwood://tree/{id}. Sessions expire in one hour; GET/SSE unavailable. Public OAuth discovery and registration are available with explicit browser consent; see the OAuth paragraph below. Attachments: POST /tasks/{id}/attachments multipart file up to25 MiB; GET /attachments/{id}/content is private, supports single ranges, HEAD and ETag. GET /attachments/{id}/link returns an owner-bound signed URL valid at most300 seconds. Photos strip GPS/camera metadata; safe dimensions/orientation remain. Task responses include attachments/messages only with attachments scope, while transcript/summary/status are readable task fields. GET /speech/status reports provider availability; POST /speech/transcribe accepts an audio file or JSON attachment_id, and GET /speech/jobs/{id} reports the real job. Unconfigured speech returns503 without making a fake job. Multipart retries must retain Idempotency-Key, bytes and filename; changed content returns409. Authorized team trees, comments, assignments, history and atomic CSV import are implemented; Grove seat billing remains unverified. Webhook delivery remains disabled until server and receiver configuration are present. Browser token creation returns a secret once and cannot use Idempotency-Key/offline replay. Token values are never included in token listings or audit metadata. OAuth public clients Use /.well-known/oauth-protected-resource/mcp and /.well-known/oauth-authorization-server on the exact configured issuer. Register exact callbacks at /oauth/register. Authorization requires response_type=code, resource=/mcp, state and mandatory S256 PKCE. The Taskwood owner explicitly allows or denies the visibly unverified client in the browser; consent is never queued or replayed. Public /oauth/token accepts form-urlencoded client_id and exact resource, plus a single-use code/redirect_uri/code_verifier or rotating refresh_token. Access expires after15minutes; a refresh family expires after30days and reuse revokes the whole connection. The same current actor, read/write/attachments scopes, verified paid-write entitlement, team grants and600/min bucket apply to REST and MCP. Browser-only GET /api/oauth/grants and DELETE /api/oauth/grants/{id} list/revoke retained connections with live session/CSRF; token secrets and request nonces are not persisted by the UI. All OAuth/discovery/management responses are no-store. No Client ID Metadata Documents, remote metadata fetch or OpenID Connect id_token is supported. Teams: shared access always rechecks the original owner’s effective Grove plan and current actor membership. Owner-only settings/invites/revocation, author-or-owner comment edits, history pages (Seed30days), atomic CSV validate/import (1MiB/1000rows) and full bounded JSON export are available. Invitations are recipient-bound manual one-time links, not email delivery; seat billing is unverified. Shared data stays online and is never written to browser offline snapshots. MCP also exposes list_comments, task_history, add_comment, edit_comment, delete_comment, assign_task, validate_csv and import_csv. Configured integrations: GET /api/v1/connectors exposes actual availability. Paid accounts may configure owner-scoped /api/v1/webhooks when delivery is enabled; signing secrets are supplied during setup and absent from metadata, URLs stay sealed, event IDs remain stable across bounded delivery retries. Browser-only Telegram link codes require a session and CSRF and reject replay keys. Telegram callbacks authenticate their dedicated secret header. /api/v1/admin/* requires a current admin browser session, never PAT/OAuth access. External delivery remains unavailable until configured; no test message is implied by reading metadata. Grove seats: actual verified Stripe test quantities include the owner and each distinct participant across owned trees. Unknown quantities do not authorize shared membership; over-capacity denies member grants and retains all records. Existing seat changes use the customer portal; this API does not automatically purchase or increase seats. Assigned-task reminders are a separate recipient opt-in and recheck current grants before delivery.