Complete reference for the TaskFlow REST API. All responses follow a consistent JSON structure.
http://localhost:5000/api
All routes except /auth/register and /auth/login require an active session via an httpOnly token cookie:
Cookie: token=<your_jwt_token>
Tokens are issued on registration and login and are valid for 30 days.
Success:
{ "success": true, "data": { ... } }Error:
{ "success": false, "error": "A descriptive error message" }Auth endpoints (/auth/register, /auth/login) return a flat structure (no success wrapper) for compatibility.
Three endpoints enforce IP-based rate limiting:
| Endpoint | Limit | Window |
|---|---|---|
POST /auth/register |
5 requests | 1 hour |
POST /auth/login |
10 requests | 15 minutes |
POST /auth/forgot-password |
3 requests | 1 hour |
Exceeded limits return 429 Too Many Requests with { success: false, error: "..." }.
POST /auth/register
Creates a new account. If the registered email matches any pendingInvites, the user is automatically added to those boards.
Rate limit: 5 requests/hour/IP
Body:
{
"username": "johndoe",
"email": "john@example.com",
"password": "password123"
}Validation rules:
username: required, 3–30 characters, alphanumeric + underscoresemail: required, valid email formatpassword: required, minimum 6 characters
Response 201:
{
"_id": "60d5ec...",
"username": "johndoe",
"email": "john@example.com"
}(Also returns a Set-Cookie header containing the JWT session)
Error 400: Email or username already exists.
POST /auth/login
Authenticates an existing user and returns a JWT token.
Rate limit: 10 requests/15 minutes/IP
Body:
{
"email": "john@example.com",
"password": "password123"
}Response 200:
{
"_id": "60d5ec...",
"username": "johndoe",
"email": "john@example.com"
}(Also returns a Set-Cookie header containing the JWT session)
Error 401: Invalid email or password (generic message — prevents user enumeration).
POST /auth/logout
Clears the user's httpOnly session cookie to securely log them out.
Response 200:
{
"success": true,
"message": "Logged out successfully"
}(Also returns a Set-Cookie header to clear the token)
GET /api/auth/me
Retrieves the currently authenticated user's profile using the session cookie. Requires an active httpOnly cookie.
Response 200:
{
"_id": "60d5ec...",
"username": "johndoe",
"email": "john@example.com"
}POST /auth/forgot-password
Generates a 10-minute reset token and sends it to the user's email.
Rate limit: 3 requests/hour/IP
Body:
{ "email": "john@example.com" }Response 200: Always returns a generic success message regardless of whether the email is registered.
{
"success": true,
"data": "If an account exists with that email, a password reset link has been sent."
}POST /auth/reset-password/:resetToken
Completes the password reset using the token from the email link.
Body:
{ "password": "newpassword123" }Response 200:
{ "success": true, "data": "Password reset successful" }Error 400: Token is invalid or has expired.
All board endpoints require authentication.
POST /boards
Creates a new board and automatically initialises 4 default columns: To Do, In Progress, Review, Done.
Body:
{ "title": "Project Alpha" }Response 201:
{
"success": true,
"data": {
"_id": "60d5ee...",
"title": "Project Alpha",
"user": "60d5ec...",
"columns": [
{ "_id": "...", "title": "To Do", "position": 0 },
{ "_id": "...", "title": "In Progress", "position": 1 },
{ "_id": "...", "title": "Review", "position": 2 },
{ "_id": "...", "title": "Done", "position": 3 }
],
"coworkers": [],
"pendingInvites": []
}
}GET /boards
Returns all boards where the user is owner or coworker.
Response 200:
{
"success": true,
"count": 2,
"data": [...]
}GET /boards/:id
Returns a deeply populated board tree: board → columns → tasks (with assignees) → comments (with authors).
Response 200:
{
"success": true,
"data": {
"_id": "60d5ee...",
"title": "Project Alpha",
"columns": [
{
"_id": "...",
"title": "To Do",
"tasks": [
{
"_id": "...",
"title": "Fix login bug",
"priority": "high",
"assignedTo": { "_id": "...", "username": "johndoe" },
"comments": [...]
}
]
}
]
}
}Error 403: User is not a member of this board.
DELETE /boards/:id
Permanently removes the board and all its columns, tasks, comments, and notifications (cascade delete).
Access: Board owner only.
Response 200:
{ "success": true, "message": "Board and all associated data removed" }PUT /boards/:boardId/reorder
Updates the display order of columns on a board. All provided IDs must belong to the board.
Body:
{ "columnIds": ["60d5ef...", "60d5f2...", "60d5f0..."] }Response 200:
{ "success": true, "data": ["60d5ef...", "60d5f2...", "60d5f0..."] }GET /boards/:boardId/members
Returns the full list of board participants (owner + coworkers) with username and email.
Response 200:
[
{ "_id": "...", "username": "johndoe", "email": "john@example.com" },
{ "_id": "...", "username": "jane_doe", "email": "jane@example.com" }
]POST /boards/:boardId/invite
Invites a user to the board. Board owner only.
- If the email is registered → user is added to
coworkersimmediately and receives an invitation email + in-app notification. - If the email is unregistered → email is added to
pendingInvitesand a sign-up invitation email is sent. Upon registration, the user is auto-added to the board.
Body:
{ "email": "newuser@example.com" }Response 200 (registered user):
{
"message": "User invited successfully",
"coworkers": ["60d5ed...", "60d5f1..."]
}Response 200 (unregistered user):
{
"message": "Invitation email sent to unregistered user. They will be added when they sign up."
}Error 403: Only the board owner can invite members.
Error 400: User is already a member or already invited.
DELETE /boards/:boardId/members/:memberId
Removes a coworker from the board. Board owner only. Owner cannot remove themselves.
Response 200:
{ "success": true, "message": "Member removed successfully" }POST /columns
Adds a new column to an existing board.
Body:
{
"title": "Backlog",
"boardId": "60d5ee..."
}Response 201:
{
"success": true,
"data": {
"_id": "60d5f2...",
"title": "Backlog",
"board": "60d5ee...",
"position": 0,
"tasks": []
}
}GET /columns/board/:boardId
Returns all columns for a board with their tasks populated.
Response 200:
{ "success": true, "data": [...] }DELETE /columns/:id
Deletes the column and cascade-deletes all tasks, comments, and notifications within it.
Response 200:
{ "success": true, "message": "Column and associated tasks removed" }POST /tasks
Creates a new task in the specified column.
Body:
{
"title": "Fix Auth Bug",
"columnId": "60d5ef...",
"description": "Token is not being cleared on logout",
"priority": "high",
"label": "Bug",
"dueDate": "2024-12-31T12:00:00Z",
"assignedTo": "60d5ed..."
}Accepted values:
priority:low,medium,high(default:medium)label:Bug,Frontend,Backend,Documentation,DevOps,Design,Testing,Feature,Other
Response 201:
{
"success": true,
"data": {
"_id": "60d5f3...",
"title": "Fix Auth Bug",
"column": "60d5ef...",
"priority": "high",
"label": "Bug",
"isDone": false,
"activityLog": []
}
}GET /tasks
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
boardId |
ObjectID | Required. Scope to a specific board |
columnId |
ObjectID | Filter by a specific column |
assignedTo |
ObjectID | Filter by assignee user ID |
priority |
string | low, medium, or high |
search |
string | Full-text search in title and description |
startDate |
ISO Date | Due date range start |
endDate |
ISO Date | Due date range end |
Response 200:
{
"success": true,
"count": 3,
"data": [...]
}GET /tasks/:id
Returns a single task with populated comments and activity log.
Response 200:
{ "success": true, "data": { ... } }GET /tasks/:id/activity
Returns only the task's activity log with actor usernames populated.
Response 200:
{
"success": true,
"data": [
{
"action": "Title changed from 'Old Title' to 'New Title'",
"performedBy": { "_id": "...", "username": "johndoe" },
"timestamp": "2024-10-27T10:00:00Z"
}
]
}PUT /tasks/:id
Updates task fields. Changes are automatically logged to activityLog.
Body (any combination of fields):
{
"title": "New Title",
"priority": "medium",
"description": "Updated description",
"dueDate": "2024-12-31T00:00:00Z",
"label": "Feature",
"assignedTo": "60d5ed..."
}Response 200:
{ "success": true, "data": { ... } }PATCH /tasks/move
Moves a task from one column to another. Atomically updates both source and destination columns and the task's column reference. If the destination column is named "done" (case-insensitive), the task is marked isDone: true.
Body:
{
"taskId": "60d5f3...",
"sourceColumnId": "60d5ef...",
"destinationColumnId": "60d5f0..."
}Response 200:
{ "success": true, "message": "Task moved successfully" }PATCH /tasks/column/:columnId/reorder
Reorders tasks within a single column. All taskIds must belong to the specified column.
Body:
{ "taskIds": ["60d5f3...", "60d5f5...", "60d5f4..."] }Response 200:
{ "success": true, "data": ["60d5f3...", "60d5f5...", "60d5f4..."] }DELETE /tasks/:id
Deletes a task and cascade-deletes all associated comments and notifications.
Access: Board owner only.
Response 200:
{ "success": true, "message": "Task deleted successfully" }Error 403:
{
"success": false,
"error": "Only the board owner can delete tasks. Contact your board owner to delete this task."
}POST /tasks/:taskId/comments
Adds a comment to a task. Triggers a COMMENT notification to the task assignee.
Body:
{ "content": "I am working on this." }Response 201:
{
"success": true,
"data": {
"_id": "60d5f6...",
"content": "I am working on this.",
"task": "60d5f3...",
"author": { "_id": "...", "username": "johndoe" },
"createdAt": "2024-10-27T10:00:00Z"
}
}GET /tasks/:taskId/comments
Returns all comments for a task, sorted by creation date descending (newest first).
Response 200:
{
"success": true,
"data": [
{
"_id": "...",
"content": "...",
"author": { "_id": "...", "username": "johndoe" },
"createdAt": "..."
}
]
}DELETE /comments/:commentId
Deletes a comment. Restricted to the comment author or board owner.
Response 200:
{ "success": true, "message": "Comment deleted successfully" }GET /notifications
Returns all notifications for the authenticated user, sorted newest-first.
Response 200:
{
"success": true,
"count": 3,
"data": [
{
"_id": "...",
"message": "johndoe assigned you to 'Fix Auth Bug'",
"type": "TASK_ASSIGNED",
"isRead": false,
"sender": { "_id": "...", "username": "johndoe" },
"createdAt": "2024-10-27T11:00:00Z"
}
]
}PATCH /notifications/read-all
Response 200:
{ "success": true, "message": "All notifications marked as read" }PATCH /notifications/:id/read
Response 200:
{ "success": true, "data": { "_id": "...", "isRead": true, ... } }DELETE /notifications/read
Clears all notifications where isRead: true for the current user.
Response 200:
{ "success": true, "message": "Read notifications cleared" }DELETE /notifications/:id
Response 200:
{ "success": true, "message": "Notification deleted" }All AI endpoints require authentication.
POST /ai/suggest-priority
Uses Google Gemini (gemini-2.5-flash) to analyse the task title and description and recommend a priority level.
Body:
{
"title": "Fix login crash on mobile",
"description": "App crashes on iOS 17 when submitting the login form"
}Response 200:
{ "success": true, "priority": "high" }Notes:
- Returns one of:
high,medium,low - Falls back to
mediumif the AI response is ambiguous - Requires
GEMINI_API_KEYin the environment
POST /ai/auto-label
Performs fast, local keyword matching to suggest a task label — no external API call required.
Body:
{
"title": "Update login page button styles",
"description": "Change button colours to match new brand guide"
}Response 200:
{ "success": true, "label": "Frontend" }Possible labels: Bug · Frontend · Backend · Documentation · DevOps · Testing · Feature · Design · Other
POST /ai/board-insight
Uses Google Gemini to analyse all tasks on a board and return a single short insight summary (max 15 words) for display in the board banner.
Body:
{ "boardId": "60d5ee..." }Response 200:
{ "insight": "3 high-priority tasks are overdue — review your backlog today." }Notes:
- Returns
{ insight: "Add some tasks to see AI insights!" }if the board has no tasks - Falls back to a demo message if the Gemini API quota is exceeded (HTTP 429)
- Requires
GEMINI_API_KEYin the environment
POST /ai/auto-prioritize
Bulk re-calculates priority for all tasks on a board using Google Gemini. Returns an array of { id, priority } objects that the client can use to batch-update task priorities.
Body:
{ "boardId": "60d5ee..." }Response 200:
{
"priorities": [
{ "id": "60d5f3...", "priority": "high" },
{ "id": "60d5f4...", "priority": "low" }
]
}Notes:
- Returns
{ priorities: [] }if the board has no tasks - Requires
GEMINI_API_KEYin the environment - The response is a raw JSON array parsed directly from the Gemini output
| Code | Type | Description |
|---|---|---|
200 |
OK | Request succeeded |
201 |
Created | Resource created successfully |
400 |
Bad Request | Validation failure, duplicate key, or business rule violation |
401 |
Unauthorized | Missing, invalid, or expired JWT token |
403 |
Forbidden | Authenticated but insufficient permissions |
404 |
Not Found | Resource not found |
429 |
Too Many Requests | Rate limit exceeded |
500 |
Server Error | Unexpected server-side error |
Validation failure (400):
{ "success": false, "error": "Username must be at least 3 characters long" }Token expired (401):
{ "success": false, "error": "Session expired, please log in again." }Permission denied (403):
{ "success": false, "error": "Only the board owner can invite members" }Rate limit exceeded (429):
{ "success": false, "error": "Too many login attempts, please try again later" }