Authentication
Two auth modes accept all v1 endpoints:
- Browser session via NextAuth — used by the dashboard.
teamIdmust be supplied as a query parameter. - Personal Access Token via
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.
Scopes
| 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 PREMIUM plan or higher. |
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. |
Endpoints
| 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). PREMIUM+ 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 |
Rate limits
- Token-authed reads: 120 requests / minute per token.
- Token-authed writes: 30 requests / minute per token (mutation tier).
- Anonymous (newsletter, public boards): 20 / minute per IP.
- Rate-limited responses return
429withRetry-AfterandX-RateLimit-*headers.
Destructive operations
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.
Plans & limits
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 | PREMIUM |
Exceeding a gate returns a structured upgrade hint (see Errors). Active-job caps: FREE 10 (up to 20 with referrals), PREMIUM 40, DIAMOND 150.
MCP server
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:
- Read:
list_jobs,list_stages,list_tags,list_members,get_timeline,list_decisions,list_evidence - Write:
create_job,update_job,move_job,assign_job(PREMIUM+),create_tag,update_stage - Agent loop:
claim_job,release_job,report_progress,request_human_decision,resolve_decision,attach_evidence
Destructive verbs are intentionally NOT exposed via MCP. See /security.
Errors
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 PREMIUM plan. You're on FREE.",
"details": {
"feature": "assign_job",
"currentPlan": "FREE",
"requiredPlan": "PREMIUM",
"upgradeUrl": "https://www.qodflow.com/settings/billing",
"docsUrl": "https://www.qodflow.com/api-docs#plans"
}
}
}