REST API · v1

Todo4you REST API
Developer reference

A JSON REST API to manage tickets, post comments, move and archive tickets, read project data, and list tags. Authenticate with a personal Bearer token - no OAuth, no SDKs required.

Postman Download collection

Authentication

Every request must include your personal API token as a Bearer token in the Authorization header. There are no other authentication methods.

1 - Get your token

Log in to Todo4you, go to Profile - API Access, and click Generate token. Your token is a 64-character hex string. Copy it immediately - it is only displayed once.

Profile → API Access
2 - Include the header
Authorization: Bearer YOUR_64_CHAR_TOKEN
3 - Test your token

Paste your token below to verify it works and preview your project list:

API Token

            

Errors

All errors return JSON with an error field describing the problem. Successful responses never include an error field.

// 422 example { "error": "title is required." }
StatusMeaning
401Missing or invalid API token
403Token valid but role insufficient for this action (viewer trying to create/move)
404Project or ticket not found, or not accessible with your token
422Validation failed - read the error message for the exact field
Projects

List projects

GET /api/v1/projects

Returns all projects the authenticated user owns or is a member of, sorted alphabetically. Use the id field for all subsequent requests that need a project ID. The role field is the calling user's role on the project (manager, editor, contributor or viewer) and docs_enabled indicates whether the documentation area is turned on for the project.

Response
200 OK200
{ "projects": [ { "id": 12, "name": "My Project", "prefix": "TDL", "description": "Main development board", "role": "manager", "docs_enabled": true } ] }
Example
curl https://api.todo4you.com/api/v1/projects \ -H "Authorization: Bearer YOUR_TOKEN"

Create project

POST /api/v1/projects

Creates a new project. You will automatically become the project owner with manager role.

Request body (JSON)
FieldTypeDescription
name string required Project name (min 2 characters)
prefix string optional Ticket prefix, e.g. TDL. Alphanumeric only, auto-uppercased
description string optional Short project description
Response
201 Created201
{ "project": { "id": 25, "name": "My New Project", "prefix": "MNP", "description": "A fresh project" } }
Example
curl -X POST https://api.todo4you.com/api/v1/projects \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"My New Project","prefix":"MNP","description":"A fresh project"}'

Project stats

GET /api/v1/projects/{id}/stats

Returns the number of open tickets in a project (all statuses except done). Useful for condition checks and dashboards.

Path parameters
ParamTypeDescription
idintegerProject ID - from List projects
Response
200 OK200
{ "open_tickets": 14 }
Example
curl https://api.todo4you.com/api/v1/projects/12/stats \ -H "Authorization: Bearer YOUR_TOKEN"

Project statuses

GET /api/v1/projects/{id}/statuses

Returns the valid status values for a project. Pass one of these to Move ticket.

Path parameters
ParamTypeDescription
idintegerProject ID
Response
200 OK200
{ "statuses": [ { "slug": "backlog", "label": "Backlog", "color": "#6c757d", "icon": "fa-inbox", "category": "backlog" }, { "slug": "todo", "label": "To Do", "color": "#0dcaf0", "icon": "fa-list-ul", "category": "todo" }, { "slug": "in_progress", "label": "In Progress", "color": "#ffc107", "icon": "fa-tasks", "category": "active" }, { "slug": "review", "label": "Review", "color": "#0d6efd", "icon": "fa-eye", "category": "review" }, { "slug": "done", "label": "Done", "color": "#198754", "icon": "fa-check-circle", "category": "done" } ] }
Example
curl https://api.todo4you.com/api/v1/projects/12/statuses \ -H "Authorization: Bearer YOUR_TOKEN"

List members

GET /api/v1/projects/{id}/members

Returns all members of a project with their roles. Use the id values when assigning tickets via Assign member.

Path parameters
ParamTypeDescription
idintegerProject ID
Response
200 OK200
{ "members": [ { "id": 3, "name": "Alice", "avatar": null, "role": "manager" }, { "id": 8, "name": "Bob", "avatar": null, "role": "developer" } ] }
Example
curl https://api.todo4you.com/api/v1/projects/12/members \ -H "Authorization: Bearer YOUR_TOKEN"
Tickets

List tickets

GET /api/v1/projects/{id}/tickets

Returns all non-archived tickets in a project. Optionally filter by status column. Each ticket includes its tags and a prefix_ref field (e.g. TDL-47).

Path parameters
ParamTypeDescription
idintegerProject ID
Query parameters
ParamTypeDescription
status string optional Filter by status slug (use GET /projects/{id}/statuses to get valid slugs)
Response
200 OK200
{ "tickets": [ { "id": 301, "project_ticket_number": 47, "prefix_ref": "TDL-47", "title": "Fix login bug", "status": "in_progress", "type": "bug", "priority": "high", "deadline": "2026-03-15", "tags": [ { "id": 5, "name": "frontend", "color": "#e74c3c" } ], "created_at": "2026-03-01 14:22:00" } ] }
Example
curl https://api.todo4you.com/api/v1/projects/12/tickets?status=in_progress \ -H "Authorization: Bearer YOUR_TOKEN"

Get ticket

GET /api/v1/projects/{id}/tickets/{number}

Returns full ticket details including comments, checklist items, tags, assignees, and creator. The number is the per-project ticket number - the numeric part of a ref like TDL-47.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project (e.g. 47 for TDL-47)
Response
200 OK200
{ "ticket": { "id": 301, "prefix_ref": "TDL-47", "title": "Fix login bug", "status": "in_progress", "type": "bug", "priority": "high", "deadline": "2026-03-15", "tags": [ { "id": 5, "name": "frontend", "color": "#e74c3c" } ], "comments": [ { "id": 291, "message": "Found the root cause", "user_id": 8, "user_name": "Alice", "created_at": "2026-03-02 09:15:00" } ], "checklist": [ { "id": 10, "text": "Write tests", "done": 0 }, { "id": 11, "text": "Update docs", "done": 1 } ], "assignees": [ { "id": 8, "name": "Alice" } ], "creator": { "id": 3, "name": "Bob" } } }
Example
curl https://api.todo4you.com/api/v1/projects/12/tickets/47 \ -H "Authorization: Bearer YOUR_TOKEN"

Search tickets

GET /api/v1/projects/{id}/tickets/search?q={query}

Searches non-archived tickets by keyword. Matches against the ticket title and description (case-insensitive). Returns results ordered by most recently updated first.

Path parameters
ParamTypeDescription
idintegerProject ID
Query parameters
ParamTypeDescription
q string required Search keyword(s) to match against title and description
Response
200 OK200
{ "tickets": [ { "id": 301, "project_ticket_number": 47, "prefix_ref": "TDL-47", "title": "Fix login bug", "status": "in_progress", "type": "bug", "tags": [ { "id": 5, "name": "frontend", "color": "#e74c3c" } ] } ] }
Example
curl "https://api.todo4you.com/api/v1/projects/12/tickets/search?q=login" \ -H "Authorization: Bearer YOUR_TOKEN"
Tickets

Create ticket

POST /api/v1/projects/{id}/tickets

Creates a new ticket in a project and returns its reference (e.g. TDL-47). Defaults to the backlog column unless a status is specified. Requires editor or manager role on the project.

Path parameters
ParamTypeDescription
idintegerProject ID
Request body (JSON)
FieldTypeDescription
title string required Ticket title
type string optional bug - feature - release
Default: feature
priority string optional urgent - high - medium - low
Default: none
status string optional Status slug (use Project statuses to get valid slugs)
Default: first status in project
deadline string optional Date in YYYY-MM-DD format
story_points integer optional 0 - 3. Only accepted when the project uses story points estimation
estimated_hours number optional Estimated hours (e.g. 4.5). Only accepted when the project uses hours estimation
checklist string[] optional Array of checklist item texts, e.g. ["Write tests", "Update docs"]
tags integer[] optional Array of tag IDs from List tags
Response
201 Created201
{ "ticket_ref": "TDL-47" }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Fix login bug", "type": "bug", "priority": "high", "status": "todo", "deadline": "2026-03-15", "checklist": ["Write tests", "Update docs"], "tags": [5, 12] }'

Update ticket

POST /api/v1/projects/{id}/tickets/{number}/update

Updates one or more fields on a ticket. Only send the fields you want to change. Requires editor or manager role. To change the status column, use Move ticket instead.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Request body (JSON)
FieldTypeDescription
titlestringoptionalNew title (cannot be empty)
descriptionstringoptionalNew description (empty string to clear)
typestringoptionalbug - feature - release
prioritystring|nulloptionalurgent - high - medium - low - null to clear
deadlinestring|nulloptionalYYYY-MM-DD or null to clear
story_pointsinteger|nulloptional0-3 or null to clear (story points mode only)
estimated_hoursnumber|nulloptionalHours or null to clear (hours mode only)
tagsinteger[]optionalReplace all tags with this list of tag IDs
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/update \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"Updated title","priority":"urgent","tags":[5,12]}'

Add comment

POST /api/v1/projects/{id}/tickets/{number}/comments

Posts a comment on a ticket. Any project member can comment. The number is the per-project ticket number - the numeric part of a ref like TDL-47.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project (e.g. 47 for TDL-47)
Request body (JSON)
FieldTypeDescription
commentstringrequiredComment text
Response
201 Created201
{ "ok": true, "reaction_id": 291 }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/comments \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"comment":"Triggered by Homey at 08:32"}'

Move ticket

POST /api/v1/projects/{id}/tickets/{number}/move

Moves a ticket to a different status column. Triggers a real-time board update for all active viewers. Requires editor or manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Request body (JSON)
FieldTypeDescription
status string required Status slug (use Project statuses to get valid slugs)
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/move \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"status":"done"}'

Archive ticket

POST /api/v1/projects/{id}/tickets/{number}/archive

Archives a ticket, removing it from the active board. Archived tickets can be restored from the project archive page. Requires editor or manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/archive \ -H "Authorization: Bearer YOUR_TOKEN"

Unarchive ticket

POST /api/v1/projects/{id}/tickets/{number}/unarchive

Restores a previously archived ticket back onto the board. Returns the full ticket payload (with creator, assignees, tags and checklist counts) so the client can re-render immediately. Requires manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Response
200 OK200
{ "ok": true, "ticket": { "id": 312, "project_ticket_number": 47, "prefix_ref": "TDL-47", "title": "Set up CI", "status": "in_progress", "archived_at": null } }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/unarchive \ -H "Authorization: Bearer YOUR_TOKEN"

List archived tickets

GET /api/v1/projects/{id}/archived-tickets

Returns up to 100 most-recently archived tickets in a project, newest first. Optionally filter by title with the q query parameter (minimum 2 characters). The response also includes the calling user's role on the project so a client can decide whether to expose Restore (managers) and Delete (managers or ticket creator). Requires viewer role.

Path parameters
ParamTypeDescription
idintegerProject ID
Query parameters
ParamTypeDescription
qstringOptional title search, case-insensitive. Minimum 2 characters.
Response
200 OK200
{ "success": true, "role": "manager", "tickets": [ { "id": 312, "project_id": 12, "project_ticket_number": 47, "prefix_ref": "TDL-47", "title": "Set up CI", "type": "feature", "status": "done", "priority": "medium", "deadline": null, "story_points": 2, "estimated_hours": null, "sort_order": 0, "archived_at": "2026-04-19 14:32:11", "created_by": 7 } ] }
Example
curl "https://api.todo4you.com/api/v1/projects/12/archived-tickets?q=ci" \ -H "Authorization: Bearer YOUR_TOKEN"

Delete ticket

POST /api/v1/projects/{id}/tickets/{number}/delete

Permanently deletes a ticket (soft delete). The ticket creator can delete their own tickets; otherwise manager role is required.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Assign member

POST /api/v1/projects/{id}/tickets/{number}/assign

Assigns a project member to a ticket. The user must be a member of the project. Use List members to find valid user IDs. Requires editor or manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Request body (JSON)
FieldTypeDescription
user_idintegerrequiredThe project member's user ID
Response
201 Created201
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/assign \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"user_id":8}'

Unassign member

POST /api/v1/projects/{id}/tickets/{number}/unassign

Removes a member from a ticket's assignee list. Requires editor or manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
numberintegerTicket number within the project
Request body (JSON)
FieldTypeDescription
user_idintegerrequiredThe user ID to unassign
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/47/unassign \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"user_id":8}'
Board

Board data

GET /api/v1/projects/{id}/board

Returns the full kanban board for a project in a single request: all columns with their tickets, project tags, members, velocity (tickets done in the last 7 days), and the authenticated user's role. Each ticket includes tags, assignee list, reaction count, checklist progress, and creator info.

Path parameters
ParamTypeDescription
idintegerProject ID
Response
200 OK200
{ "project": { "id": 12, "name": "My Project", "prefix": "TDL", "estimation_mode": "story_points", "role": "manager", "docs_enabled": true }, "columns": [ { "status": "backlog", "hidden": false, "tickets": [ { "id": 101, "title": "Fix bug", "prefix_ref": "TDL-1", "tags": [...], "assignees": [...], "creator": {...}, "reaction_count": 3, "checklist_total": 5, "checklist_done": 2 } ] }, ... ], "tags": [...], "members": [...], "velocity": 8 }
Example
curl https://api.todo4you.com/api/v1/projects/12/board \ -H "Authorization: Bearer YOUR_TOKEN"

Sort tickets

POST /api/v1/projects/{id}/tickets/sort

Reorders tickets within a column. Pass the status and the full ordered list of ticket IDs. Requires contributor role or higher.

Path parameters
ParamTypeDescription
idintegerProject ID
Request body (JSON)
FieldTypeDescription
statusstringrequiredColumn status being reordered
ticket_idsinteger[]requiredOrdered array of ticket IDs
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tickets/sort \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"status":"todo","ticket_ids":[45,12,78]}'
Checklist

Add checklist item

POST /api/v1/tickets/{ticketId}/checklist

Adds a checklist item to a ticket. The item starts unchecked and is appended at the end. Requires editor or manager role.

Path parameters
ParamTypeDescription
ticketIdintegerTicket ID (not the project ticket number)
Request body (JSON)
FieldTypeDescription
textstringrequiredItem text (max 500 characters)
Response
201 Created201
{ "ok": true, "item": { "id": 42, "ticket_id": 101, "text": "Write tests", "done": 0, "sort_order": 3 } }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/101/checklist \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"text":"Write tests"}'

Toggle checklist item

POST /api/v1/checklist/{itemId}/toggle

Toggles a checklist item between done and not done. Requires editor or manager role.

Path parameters
ParamTypeDescription
itemIdintegerChecklist item ID
Response
200 OK200
{ "ok": true, "done": 1 }
Example
curl -X POST https://api.todo4you.com/api/v1/checklist/42/toggle \ -H "Authorization: Bearer YOUR_TOKEN"

Update checklist item

POST /api/v1/checklist/{itemId}/update

Updates the text of a checklist item. Requires editor or manager role.

Path parameters
ParamTypeDescription
itemIdintegerChecklist item ID
Request body (JSON)
FieldTypeDescription
textstringrequiredNew item text (max 500 characters)
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/checklist/42/update \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"text":"Write integration tests"}'

Delete checklist item

POST /api/v1/checklist/{itemId}/delete

Removes a checklist item from a ticket. Requires editor or manager role.

Path parameters
ParamTypeDescription
itemIdintegerChecklist item ID
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/checklist/42/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Sort checklist items

POST /api/v1/tickets/{ticketId}/checklist/sort

Reorders all checklist items for a ticket. Pass the full ordered list of item IDs. Requires editor or manager role.

Path parameters
ParamTypeDescription
ticketIdintegerTicket ID
Request body (JSON)
FieldTypeDescription
item_idsinteger[]requiredOrdered array of checklist item IDs
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/101/checklist/sort \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"item_ids":[42,43,41]}'
Blockers

Add blocker

POST /api/v1/tickets/{ticketId}/blockers

Marks another ticket in the same project as a blocker for this ticket. A ticket cannot block itself. Requires editor or manager role.

Path parameters
ParamTypeDescription
ticketIdintegerTicket ID of the blocked ticket
Request body (JSON)
FieldTypeDescription
blocker_ticket_idintegerrequiredTicket ID of the blocking ticket (must be in the same project)
Response
201 Created201
{ "ok": true, "blockers": [ { "id": 55, "title": "Setup database", "status": "in_progress", "project_ticket_number": 3 } ] }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/101/blockers \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"blocker_ticket_id":55}'

Remove blocker

POST /api/v1/tickets/{ticketId}/blockers/{blockerTicketId}/delete

Removes a blocker relationship from a ticket. Returns the updated blocker list. Requires editor or manager role.

Path parameters
ParamTypeDescription
ticketIdintegerTicket ID of the blocked ticket
blockerTicketIdintegerTicket ID of the blocker to remove
Response
200 OK200
{ "ok": true, "blockers": [] }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/101/blockers/55/delete \ -H "Authorization: Bearer YOUR_TOKEN"
Attachments

Upload files

POST /api/v1/tickets/{ticketId}/attachments

Uploads one or more files to a ticket. Send as multipart/form-data with files in the files[] field. Maximum file size is 10 MB per file. Accepted types: images, PDF, Office documents, CSV, plain text, and archives. Requires editor or manager role.

Path parameters
ParamTypeDescription
ticketIdintegerTicket ID
Request body (multipart/form-data)
FieldTypeDescription
files[]filerequiredOne or more files to upload
Response
200 OK200
{ "ok": true, "attachments": [ { "id": 7, "ticket_id": 101, "original_name": "screenshot.png", "filesize": 48210, "mime_type": "image/png" } ] }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/101/attachments \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "files[]=@screenshot.png" \ -F "files[]=@report.pdf"

Get file

GET /api/v1/attachments/{id}

Downloads or displays an attachment. Images and PDFs are returned inline; other file types trigger a download. The user must have at least viewer access to the project.

Path parameters
ParamTypeDescription
idintegerAttachment ID
Response

Returns the file binary with the appropriate Content-Type and Content-Disposition headers.

Example
curl https://api.todo4you.com/api/v1/attachments/7 \ -H "Authorization: Bearer YOUR_TOKEN" \ --output screenshot.png

Delete file

POST /api/v1/attachments/{id}/delete

Deletes an attachment. You can delete files you uploaded, files on tickets you created, or any file if you are a manager.

Path parameters
ParamTypeDescription
idintegerAttachment ID
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/attachments/7/delete \ -H "Authorization: Bearer YOUR_TOKEN"
Comments

Edit comment

POST /api/v1/reactions/{id}/update

Updates the message text of a comment. You can only edit your own comments.

Path parameters
ParamTypeDescription
idintegerReaction (comment) ID
Request body (JSON)
FieldTypeDescription
messagestringrequiredNew comment text
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/reactions/15/update \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"message":"Updated comment text"}'

Delete comment

POST /api/v1/reactions/{id}/delete

Soft-deletes a comment. You can delete your own comments; managers can delete any comment.

Path parameters
ParamTypeDescription
idintegerReaction (comment) ID
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/reactions/15/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Upload comment files

POST /api/v1/reactions/{id}/attachments

Uploads files attached to a specific comment. Works the same as ticket attachments but the files are linked to the comment. Send as multipart/form-data with files[].

Path parameters
ParamTypeDescription
idintegerReaction (comment) ID
Request body (multipart/form-data)
FieldTypeDescription
files[]filerequiredOne or more files to upload
Response
200 OK200
{ "ok": true, "attachments": [...] }
Example
curl -X POST https://api.todo4you.com/api/v1/reactions/15/attachments \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "files[]=@image.png"
Tags

List tags

GET /api/v1/projects/{id}/tags

Returns all tags defined in a project. Use the id values when creating tickets with the tags field.

Path parameters
ParamTypeDescription
idintegerProject ID
Response
200 OK200
{ "tags": [ { "id": 5, "name": "frontend", "color": "#e74c3c", "sort_order": 1 }, { "id": 12, "name": "backend", "color": "#3498db", "sort_order": 2 } ] }
Example
curl https://api.todo4you.com/api/v1/projects/12/tags \ -H "Authorization: Bearer YOUR_TOKEN"

Create tag

POST /api/v1/projects/{id}/tags

Creates a new tag in a project. Requires manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
Request body (JSON)
FieldTypeDescription
namestringrequiredTag name (max 100 characters)
colorstringoptionalHex color, e.g. #e74c3c
Default: #6c757d
Response
201 Created201
{ "tag": { "id": 18, "name": "frontend", "color": "#e74c3c", "sort_order": 3 } }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tags \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"frontend","color":"#e74c3c"}'

Delete tag

POST /api/v1/projects/{id}/tags/{tagId}/delete

Deletes a tag from a project. The tag is automatically removed from all tickets that use it. Requires manager role.

Path parameters
ParamTypeDescription
idintegerProject ID
tagIdintegerTag ID from List tags
Response
200 OK200
{ "ok": true }
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/tags/5/delete \ -H "Authorization: Bearer YOUR_TOKEN"
Time Tracking

List time entries

GET /api/v1/tickets/{ticketId}/time-entries

Returns all time entries for a ticket.

Path parameters
ParamTypeDescription
ticketIdintegerThe ticket ID
Response
200 OK200
{ "success": true, "entries": [ { "id": 1, "ticket_id": 42, "user_id": 3, "project_id": 5, "minutes": 30, "is_running": 0, "started_at": "2025-01-15 09:00:00", "stopped_at": "2025-01-15 09:30:00", "user_name": "Alice", "user_avatar": "avatar.jpg" } ], "total_minutes": 45 }
Example
curl https://api.todo4you.com/api/v1/tickets/42/time-entries \ -H "Authorization: Bearer YOUR_TOKEN"

Add manual entry

POST /api/v1/tickets/{ticketId}/time-entries

Adds a manual time entry (not a running timer).

Path parameters
ParamTypeDescription
ticketIdintegerThe ticket ID
Request body (JSON)
FieldTypeDescription
minutesintegerrequiredDuration in minutes (min 1)
Response
200 OK200
{ "success": true, "entry": { "id": 2, "ticket_id": 42, "minutes": 30, "is_running": 0, "started_at": null, "stopped_at": null } }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/42/time-entries \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"minutes": 30}'

Start timer

POST /api/v1/tickets/{ticketId}/time-entries/start

Starts a running timer on a ticket. Only one timer can run per user at a time.

Path parameters
ParamTypeDescription
ticketIdintegerThe ticket ID
Response
200 OK200
{ "success": true, "entry": { "id": 3, "ticket_id": 42, "minutes": 0, "is_running": 1, "started_at": "2025-01-15 09:00:00", "stopped_at": null, "ticket_title": "Fix login bug", "project_name": "My App", "ticket_ref": "APP-42" } }
422 Unprocessable Entity422
{ "error": "You already have a running timer.", "running_ticket_id": 55 }
Example
curl -X POST https://api.todo4you.com/api/v1/tickets/42/time-entries/start \ -H "Authorization: Bearer YOUR_TOKEN"

Stop timer

POST /api/v1/time-entries/{entryId}/stop

Stops a running or paused timer and calculates the final duration.

Path parameters
ParamTypeDescription
entryIdintegerThe time entry ID
Response
200 OK200
{ "success": true, "entry": { "id": 3, "ticket_id": 42, "minutes": 45, "is_running": 0, "started_at": "2025-01-15 09:00:00", "stopped_at": "2025-01-15 09:45:00", "ticket_title": "Fix login bug", "project_name": "My App", "ticket_ref": "APP-42" } }
Example
curl -X POST https://api.todo4you.com/api/v1/time-entries/3/stop \ -H "Authorization: Bearer YOUR_TOKEN"

Pause timer

POST /api/v1/time-entries/{entryId}/pause

Pauses a running timer. Accumulated time is preserved in the minutes field.

Path parameters
ParamTypeDescription
entryIdintegerThe time entry ID
Response
200 OK200
{ "success": true, "entry": { "id": 3, "ticket_id": 42, "minutes": 15, "is_running": 2, "started_at": "2025-01-15 09:00:00", "stopped_at": null, "ticket_title": "Fix login bug", "project_name": "My App", "ticket_ref": "APP-42" } }
Example
curl -X POST https://api.todo4you.com/api/v1/time-entries/3/pause \ -H "Authorization: Bearer YOUR_TOKEN"

Resume timer

POST /api/v1/time-entries/{entryId}/resume

Resumes a paused timer. Cannot resume if another timer is already running.

Path parameters
ParamTypeDescription
entryIdintegerThe time entry ID
Response
200 OK200
{ "success": true, "entry": { "id": 3, "ticket_id": 42, "minutes": 15, "is_running": 1, "started_at": "2025-01-15 10:00:00", "stopped_at": null, "ticket_title": "Fix login bug", "project_name": "My App", "ticket_ref": "APP-42" } }
Example
curl -X POST https://api.todo4you.com/api/v1/time-entries/3/resume \ -H "Authorization: Bearer YOUR_TOKEN"

Update entry

POST /api/v1/time-entries/{entryId}/update

Updates the minutes of a stopped time entry. Owner or project manager can update.

Path parameters
ParamTypeDescription
entryIdintegerThe time entry ID
Request body (JSON)
FieldTypeDescription
minutesintegerrequiredNew duration in minutes (min 1)
Response
200 OK200
{ "success": true, "entry": { "id": 3, "ticket_id": 42, "minutes": 60, "is_running": 0, "started_at": "2025-01-15 09:00:00", "stopped_at": "2025-01-15 09:45:00" } }
Example
curl -X POST https://api.todo4you.com/api/v1/time-entries/3/update \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"minutes": 60}'

Delete entry

POST /api/v1/time-entries/{entryId}/delete

Deletes a time entry. Owner or project manager can delete.

Path parameters
ParamTypeDescription
entryIdintegerThe time entry ID
Response
200 OK200
{ "success": true }
Example
curl -X POST https://api.todo4you.com/api/v1/time-entries/3/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Running timer

GET /api/v1/time-entries/running

Returns the currently running or paused timer for the authenticated user, with ticket and project details.

Response
200 OK200
{ "success": true, "entry": { "id": 1, "ticket_id": 42, "minutes": 15, "is_running": 1, "started_at": "2025-01-15 09:00:00", "ticket_title": "Fix login bug", "project_name": "My App", "ticket_ref": "APP-5" } }

When no timer is running, entry is null.

Example
curl https://api.todo4you.com/api/v1/time-entries/running \ -H "Authorization: Bearer YOUR_TOKEN"

Active timers

GET /api/v1/time-entries/active

Returns all running and paused timers for the authenticated user, with ticket and project details. Unlike /time-entries/running which returns only one entry, this endpoint returns all active timers.

Response
200 OK200
{ "success": true, "entries": [ { "id": 1, "ticket_id": 42, "minutes": 15, "is_running": 1, "started_at": "2025-01-15 09:00:00", "ticket_title": "Fix login bug", "project_name": "My App", "ticket_ref": "APP-5" }, { "id": 2, "ticket_id": 18, "minutes": 45, "is_running": 2, "started_at": "2025-01-15 08:00:00", "ticket_title": "Update dashboard", "project_name": "My App", "ticket_ref": "APP-18" } ] }

When no timers are active, entries is an empty array. is_running is 1 for running and 2 for paused.

Example
curl https://api.todo4you.com/api/v1/time-entries/active \ -H "Authorization: Bearer YOUR_TOKEN"
Notifications

List notifications

GET /api/v1/notifications

Returns the last 20 notifications and marks all as read.

Response
200 OK200
{ "notifications": [ { "id": 1, "type": "reaction", "message": "commented on APP-5: Fix login bug", "ticket_id": 42, "project_id": 5, "read_at": null, "created_at": "2025-01-15 10:00:00" } ] }
Example
curl https://api.todo4you.com/api/v1/notifications \ -H "Authorization: Bearer YOUR_TOKEN"

Unread count

GET /api/v1/notifications/unread-count

Returns the count of unread notifications.

Response
200 OK200
{ "count": 3 }
Example
curl https://api.todo4you.com/api/v1/notifications/unread-count \ -H "Authorization: Bearer YOUR_TOKEN"

Mark read for ticket

POST /api/v1/notifications/mark-read-for-ticket

Marks all unread notifications for a specific ticket as read.

Request body (JSON)
FieldTypeDescription
ticket_idintegerrequiredThe ticket ID to mark notifications as read for
Response
200 OK200
{ "success": true, "unread_count": 3 }
Example
curl -X POST https://api.todo4you.com/api/v1/notifications/mark-read-for-ticket \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"ticket_id": 42}'
Documentation

List documentation root

GET /api/v1/projects/{id}/docs

Returns folders and articles at the documentation root of a project. The response also includes the calling user's role, so a client can decide whether to expose write actions. Returns 404 if the project does not have documentation enabled (docs_enabled is false on the project payload). All documentation endpoints share this guard.

Response
200 OK200
{ "success": true, "role": "manager", "current_folder": null, "breadcrumbs": [], "folders": [ { "id": 3, "project_id": 12, "parent_id": null, "title": "Onboarding", "slug": "onboarding", "sort_order": 0 } ], "articles": [ { "id": 7, "project_id": 12, "folder_id": null, "title": "Welcome", "slug": "welcome", "content": "# Welcome\n\nGetting started...", "sort_order": 0 } ] }
Example
curl https://api.todo4you.com/api/v1/projects/12/docs \ -H "Authorization: Bearer YOUR_TOKEN"

List folder contents

GET /api/v1/projects/{id}/docs/folders/{folder_id}

Same shape as the root listing, but scoped to the contents of a single folder. The response includes a current_folder object and the full breadcrumbs ancestor chain from the root down to this folder.

Example
curl https://api.todo4you.com/api/v1/projects/12/docs/folders/3 \ -H "Authorization: Bearer YOUR_TOKEN"

Create folder

POST /api/v1/projects/{id}/docs/folders

Creates a new folder. Requires contributor role or higher.

Request body (JSON)
FieldTypeDescription
titlestringrequiredFolder name
parent_idintegeroptionalParent folder id, or null/omitted to create at the root
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/folders \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"Onboarding","parent_id":null}'

Update folder

POST /api/v1/projects/{id}/docs/folders/{folder_id}

Renames or moves a folder. Send only the fields you want to change. Requires contributor role or higher.

Request body (JSON)
FieldTypeDescription
titlestringoptionalNew title
parent_idinteger | nulloptionalMove to this parent. Pass null to move to the root. Omit to keep the parent unchanged. A folder cannot be its own parent.
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/folders/3 \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"Onboarding (renamed)"}'

Delete folder

POST /api/v1/projects/{id}/docs/folders/{folder_id}/delete

Soft-deletes a folder. Any child folders and articles are reparented to this folder's parent rather than deleted, so nothing is lost. Requires contributor role or higher. The response includes parent_id so the client can refresh that view.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/folders/3/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Get article

GET /api/v1/projects/{id}/docs/articles/{article_id}

Returns the article's markdown content along with attachments, comments (with author info), breadcrumbs, the calling user's role, and current_user_id so the client knows whether to show "edit" / "delete" affordances on individual comments.

Response
200 OK200
{ "success": true, "role": "manager", "current_user_id": 42, "article": { "id": 7, "project_id": 12, "folder_id": null, "title": "Welcome", "slug": "welcome", "content": "# Welcome\n\nMarkdown body.", "created_by": 42, "updated_by": null }, "breadcrumbs": [], "attachments": [ { "id": 11, "original_name": "diagram.png", "filesize": 12345, "mime_type": "image/png" } ], "comments": [ { "id": 5, "user_id": 42, "user_name": "Jorden", "message": "Looks good" } ] }
Example
curl https://api.todo4you.com/api/v1/projects/12/docs/articles/7 \ -H "Authorization: Bearer YOUR_TOKEN"

Create article

POST /api/v1/projects/{id}/docs/articles

Creates a new article. Markdown is supported in content. Requires contributor role or higher.

Request body (JSON)
FieldTypeDescription
titlestringrequiredArticle title
contentstringoptionalMarkdown content. Defaults to empty string
folder_idintegeroptionalFolder to place the article in. Omit for root
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/articles \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"title":"How we deploy","content":"## Steps\n1. Push to main","folder_id":3}'

Update article

POST /api/v1/projects/{id}/docs/articles/{article_id}

Updates an article. Send only the fields you want to change. The server stamps updated_by with the calling user. Requires contributor role or higher.

Request body (JSON)
FieldTypeDescription
titlestringoptionalNew title
contentstringoptionalNew markdown content
folder_idinteger | nulloptionalMove to this folder. Pass null to move to root. Omit to leave unchanged.
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/articles/7 \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"content":"Updated body."}'

Delete article

POST /api/v1/projects/{id}/docs/articles/{article_id}/delete

Soft-deletes an article. Requires contributor role or higher.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/articles/7/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Copy article

POST /api/v1/projects/{id}/docs/articles/{article_id}/copy

Duplicates an article in the same folder. The new article gets the suffix (copy) on its title and is owned by the calling user. Requires contributor role or higher.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/articles/7/copy \ -H "Authorization: Bearer YOUR_TOKEN"

Add comment to article

POST /api/v1/projects/{id}/docs/articles/{article_id}/comments

Posts a comment on an article. Anyone with view access to the project may comment.

Request body (JSON)
FieldTypeDescription
messagestringrequiredComment body
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/articles/7/comments \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"message":"Looks good!"}'

Edit comment

POST /api/v1/projects/{id}/docs/comments/{comment_id}

Edits a comment. Only the comment author may edit their own comment.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/comments/5 \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"message":"updated comment"}'

Delete comment

POST /api/v1/projects/{id}/docs/comments/{comment_id}/delete

Deletes a comment. The comment author may delete their own comment, or a manager may delete anyone's.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/comments/5/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Upload attachments

POST /api/v1/projects/{id}/docs/articles/{article_id}/attachments

Uploads one or more files to a documentation article. Send as multipart/form-data with files in the files[] field. Maximum 10 MB per file. Same allowed types as ticket attachments (images, PDF, Office docs, CSV, plain text, archives). Requires contributor role or higher.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/articles/7/attachments \ -H "Authorization: Bearer YOUR_TOKEN" \ -F "files[]=@./diagram.png" \ -F "files[]=@./spec.pdf"

Get attachment

GET /api/v1/projects/{id}/docs/attachments/{attachment_id}

Streams the file back. Images and PDFs are served inline; other types as a download. The endpoint sets Content-Type, Content-Disposition, and a private Cache-Control header.

Example
curl -OJ https://api.todo4you.com/api/v1/projects/12/docs/attachments/11 \ -H "Authorization: Bearer YOUR_TOKEN"

Delete attachment

POST /api/v1/projects/{id}/docs/attachments/{attachment_id}/delete

Deletes an attachment from disk and from the database. Requires contributor role or higher.

Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/attachments/11/delete \ -H "Authorization: Bearer YOUR_TOKEN"

Sort folders and articles

POST /api/v1/projects/{id}/docs/sort

Sets the sort_order for folders and/or articles based on the order in the request arrays. The position in each array becomes the new sort_order. Requires contributor role or higher.

Request body (JSON)
FieldTypeDescription
foldersint[]optionalFolder ids in the desired order
articlesint[]optionalArticle ids in the desired order
Example
curl -X POST https://api.todo4you.com/api/v1/projects/12/docs/sort \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{"folders":[3,1,2],"articles":[12,10,11]}'

Coming soon

Our native app for macOS is in development and will be available on the App Store soon.