Two auth modes accept all v1 endpoints:
teamId must be supplied as a query parameter.Authorization: Bearer qf_live_…. The token is bound to one team and a set of scopes at creation. Get one at Settings → API Keys.Token plaintext follows the shape qf_<mode>_<prefix>_<secret>. Test-mode tokens use the qf_test_ prefix and bind to Stripe test products.
| Scope | Purpose |
|---|---|
jobs:read | Read jobs and history. |
jobs:write | Create, update, move jobs. |
stages:read | Read pipeline stages. |
stages:write | Create or update stages. |
tags:read | Read tags. |
tags:write | Create or update tags. |
members:read | Read team membership list (email masked for tokens). |
mcp:claim | Claim / release / report progress on jobs. |
mcp:assign | Assign jobs to members. Requires the DIAMOND plan. |
mcp:decide | Request a human decision on a job. |
mcp:resolve | Resolve an open decision. |
mcp:evidence | Attach evidence to a job. |
team:read | Read team metadata. |
team:admin | Reserved — destructive verbs intentionally NOT bound to this scope today. |
| Method | Path | Scope |
|---|---|---|
| POST | /api/auth/tokensIssue a Personal Access Token. Returns plaintext ONCE. | session, owner+admin |
| GET | /api/auth/tokensList tokens for a team. | session, owner+admin |
| DELETE | /api/auth/tokens/[id]Soft-revoke a token (sets revokedAt). | session |
| GET | /api/v1/jobsList jobs (cursor-paginated, max 100/req). | jobs:read |
| POST | /api/v1/jobsCreate a job in the first stage unless stageId is supplied. | jobs:write |
| GET | /api/v1/jobs/[id]Read a single job with tags + assignee. | jobs:read |
| PATCH | /api/v1/jobs/[id]Update title, description, priority, dueDate, poNumber, value. | jobs:write |
| POST | /api/v1/jobs/[id]/moveMove a job to another stage with workflow validation. | jobs:write |
| POST | /api/v1/jobs/[id]/assignAssign a job to a team member (or null to unassign). DIAMOND plan. | mcp:assign |
| GET | /api/v1/stagesList stages, ordered. | stages:read |
| POST | /api/v1/stagesCreate a stage (inserted before the final stage). | stages:write |
| PATCH | /api/v1/stages/[id]Rename, change SLA, change color. | stages:write |
| GET | /api/v1/tagsList tags. | tags:read |
| POST | /api/v1/tagsCreate a tag. | tags:write |
| PATCH | /api/v1/tags/[id]Rename / recolor. | tags:write |
| GET | /api/v1/membersList members with role + joinedAt. | members:read |
| GET | /api/v1/audit-logRead token-authed request log. Tokens cannot read this. | session, owner+admin |
| GET | /api/healthShallow liveness (no DB). Add ?deep=1 for DB + Stripe readiness. No auth. | public |
429 with Retry-After and X-RateLimit-* headers.DELETE /api/teams/[id] requires session auth AND a body of { "confirm": "DELETE <team-slug>" } matched exactly. Tokens cannot delete teams. Bulk-delete and Stripe mutation are not exposed via the API at all.
The API and MCP enforce the same plan matrix as the app. Reads and the agent-collaboration loop (claim, progress, evidence, decisions) are open on every plan; scale and premium capabilities are gated:
| Capability | Minimum plan |
|---|---|
| Create / move jobs (within active-job cap) | FREE |
| Flag priority | PREMIUM |
| Tags | PREMIUM |
| Assign jobs to members | DIAMOND |
Exceeding a gate returns a structured upgrade hint (see Errors). Active-job caps: FREE 10 (up to 20 with referrals), PREMIUM 40, DIAMOND 150.
Stdio MCP server published as qodflow-mcp. Point your AI client at it and pass QODFLOW_API_TOKEN as an env var (and QODFLOW_API_BASE=https://www.qodflow.com if overriding). Tools exposed:
list_jobs, list_stages, list_tags, list_members, get_timeline, list_decisions, list_evidencecreate_job, update_job, move_job, assign_job (DIAMOND), create_tag, update_stageclaim_job, release_job, report_progress, request_human_decision, resolve_decision, attach_evidenceDestructive verbs are intentionally NOT exposed via MCP. See /security.
All errors follow the shape { success: false, error: { code, message, details? } }. Codes include UNAUTHORIZED, FORBIDDEN, INVALID_INPUT, NOT_FOUND, RATE_LIMIT_EXCEEDED, PLAN_LIMIT_REACHED, PLAN_UPGRADE_REQUIRED.
Plan and quota errors carry a machine-readable upgrade hint so an agent can relay it in-context:
{
"success": false,
"error": {
"code": "PLAN_UPGRADE_REQUIRED",
"message": "Feature \"assign_job\" requires the DIAMOND plan. You're on FREE.",
"details": {
"feature": "assign_job",
"currentPlan": "FREE",
"requiredPlan": "DIAMOND",
"upgradeUrl": "https://www.qodflow.com/settings/billing",
"docsUrl": "https://www.qodflow.com/api-docs#plans"
}
}
}