Skip to content

Tasks API

The Tasks API works with individual tasks: your personal task overview, reading and updating a task, changing its status (including completion with actual hours), comments, and deletion.

Tasks are created inside a project through POST /api/v1/projects/:id/tasks, not through this API. Project-level scheduling operations (dates, estimates, per-day allocations, and assignees with conflict checks) also live on the Projects API.

Authentication: every endpoint requires an API key. See API Keys & Authentication.

Requests run in your organisation, and every response uses the standard { "success": true, ... } envelope.

Task endpoints return a task with usage metadata:

{
"id": "4be2d871-...",
"name": "Draft homepage copy",
"description": "First pass for internal review.",
"status": "in_progress",
"priority": "high",
"projectId": "1f0e9a52-...",
"projectName": "Winter Launch",
"clientName": "Northwind",
"estimatedHours": 6,
"actualHours": 5.5,
"trackedHours": 4.25,
"progress": 60,
"plannedStartDate": "2026-07-13T00:00:00.000Z",
"plannedEndDate": "2026-07-14T00:00:00.000Z",
"actualStartDate": "2026-07-13T01:12:44.000Z",
"actualEndDate": null,
"completionNotes": null,
"commentCount": 3,
"tags": ["copy", "homepage"],
"metadata": {},
"dueCategory": "today",
"dueInDays": 1,
"createdAt": "2026-07-10T00:05:31.000Z",
"updatedAt": "2026-07-13T02:41:12.000Z"
}
  • status is one of pending, scheduled, in_progress, completed, cancelled.
  • priority is one of low, medium, high, critical.
  • dueCategory is one of overdue, today, upcoming, unscheduled, computed from the planned dates. Completed tasks report upcoming.
  • dueInDays is the number of days until the planned end date (negative when overdue), or null when the task has no planned end date.
  • trackedHours is the total of the task’s time entries. actualHours is the figure recorded when the task was completed.
  • description, clientName, estimatedHours, actualHours, the date fields, completionNotes, and tags can be null or absent.

Get an overview of the tasks assigned to you: a summary of counts and hours, plus the full task list grouped for due-date display. Cancelled tasks are excluded.

Any organisation member can call this. It only ever returns your own tasks.

Example request

Terminal window
curl https://api.runnit.io/api/v1/tasks/my \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"data": {
"summary": {
"total": 12,
"overdue": 1,
"dueToday": 2,
"upcoming": 6,
"completed": 3,
"inProgress": 2,
"scheduledHours": 64.5,
"trackedHours": 38.25
},
"tasks": [ { "id": "4be2d871-...", "name": "Draft homepage copy", "dueCategory": "today" } ]
}
}

tasks contains full task objects as described above, ordered by due date with completed tasks last. The overdue, dueToday, and upcoming counts only include tasks that are not completed.

Errors

  • 400 if no active organisation can be resolved for your account.

Get one of your assigned tasks by ID.

Any organisation member can call this, but it only resolves tasks assigned to you. A task assigned to someone else (or to nobody) returns 404.

Path parameters

NameTypeRequiredDescription
taskIdUUIDYesTask ID. Must be assigned to you.

Example request

Terminal window
curl https://api.runnit.io/api/v1/tasks/<task-id> \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "success": true, "task": { "id": "4be2d871-...", "name": "Draft homepage copy", "status": "in_progress" } }

Errors

  • 404 if the task does not exist, is deleted, is in another organisation, or is not assigned to you.

Update a task’s fields. Send only the fields you want to change. Project owners and project admins have a local override. Organisation capabilities apply on every accessible project, even when the caller is not listed on its team.

Path parameters

NameTypeRequiredDescription
taskIdUUIDYesTask ID.

Request body (all optional)

NameTypeRequiredDescription
namestringNoNew name. Must not be empty.
descriptionstringNoTask description.
prioritystringNolow, medium, high, or critical.
progressintegerNo0 to 100.
estimatedHoursnumberNo0 to 1000. On a dated task with a day-by-day breakdown, keeps the planned window and rescales the daily hours when the new total fits it; otherwise rebuilds from the start. On an undated task, saves the estimate without creating dates.
plannedStartDateISO 8601 dateNoPlanned start. Rebuilds the task schedule and recalculates planned end.
dependsOnUUID[]NoReplace the task’s finish-to-start dependency list (max 25 task ids from the same project; cycles rejected). Requires task-wide update and schedule-management access. The response includes a cascade summary when downstream tasks were rescheduled.
plannedEndDateISO 8601 dateNoCalculated output. A value supplied with start or estimate is ignored for backwards compatibility. Sending only this field returns 400.
tagsarray of stringsNoReplaces the full tag list.
assignedToIdstring or nullNoNew assignee’s user ID. Null unassigns the task. The user must be an active organisation member. On a client project they must be on the client staffing list or the explicit project team.

A start update creates or rebuilds the same working-day schedule used by the project dates endpoint, and moves a pending backlog task to scheduled. An estimate-only update on a dated task follows the same manual-aware rule as the project estimate endpoint: a manual day-by-day plan keeps its window and rescales when the new total fits, and rebuilds from the start when it does not. It never invents a start date for backlog work. Changing the assignee also updates the owner on any existing schedule segments.

General fields require task-wide update access, assigned-task access for the current assignee, or a project override. Assignment requires task:assign. Schedule fields and dependencies require both task:update:any and schedule:manage. A project’s target date is not a write boundary: segments after it are marked overdue but remain editable.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/tasks/<task-id> \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "priority": "critical", "progress": 75 }'

Response

{ "success": true, "task": { "id": "4be2d871-...", "priority": "critical", "progress": 75 } }

Errors

  • 400 if a field fails validation (empty name, progress outside 0 to 100, estimated hours outside 0 to 1000, invalid priority or date), if the new assignee is not an active organisation member, or if the new assignee is neither on the client staffing list nor the explicit project team, or if plannedEndDate is sent without a start or estimate.
  • 404 if the task does not exist, is deleted, or is in another organisation.
  • 403 when the caller lacks the capability required for the fields being changed.

Change a task’s status and optional progress atomically. Completing a task can also record the actual hours spent and a completion note.

The task’s assignee or project owner can call this. Users with organisation-wide task update access can also update the task. Assignment changes still use the Projects API.

Path parameters

NameTypeRequiredDescription
taskIdUUIDYesTask ID.

Request body

NameTypeRequiredDescription
statusstringYesOne of pending, scheduled, in_progress, completed, cancelled.
progressintegerNoWhole percentage from 0 to 100.
actualHoursnumberNo0 to 1000. Recorded with completion.
completionNotesstringNoUp to 2000 characters.

Completing a task sets its progress to 100 and records the work in your portfolio history. If you supply actualHours with completion, Runnit also creates (or updates) a draft time entry for those hours against the task.

The endpoint applies these work-state rules:

  • Progress from 1 to 99 changes pending or scheduled work to in_progress.
  • Progress at 100 changes the status to completed.
  • completed always stores progress at 100.
  • pending and scheduled store progress at 0 when progress is omitted or 0.
  • cancelled preserves the stored progress.
  • Reopening completed work as in_progress defaults to 95 when progress is omitted.

Example request

Terminal window
curl -X PATCH https://api.runnit.io/api/v1/tasks/<task-id>/status \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{
"status": "completed",
"progress": 100,
"actualHours": 5.5,
"completionNotes": "Copy approved by the internal review."
}'

Response

{ "success": true, "task": { "id": "4be2d871-...", "status": "completed", "progress": 100, "actualHours": 5.5 } }

Errors

  • 400 if status is missing or invalid, progress is not a whole number from 0 to 100, actualHours is out of range, or completionNotes exceeds 2000 characters.
  • 404 if the task does not exist, is deleted, or is in another organisation.
  • 403 if you are not the task’s assignee or project owner and do not have organisation-wide task update access.

List a task’s comments, including who wrote each one. Comments are the messages in the task’s chat thread, so entries created by replying or mentioning someone in the app appear here too. A comment may include a replyToId referencing the comment it replies to.

Any organisation member can call this for tasks in their organisation.

Path parameters

NameTypeRequiredDescription
taskIdUUIDYesTask ID.

Example request

Terminal window
curl https://api.runnit.io/api/v1/tasks/<task-id>/comments \
-H 'Authorization: Bearer rnk_your_key'

Response

{
"success": true,
"comments": [
{
"id": "b7e13f90-...",
"taskId": "4be2d871-...",
"userId": "d3a6f0c1-...",
"commentText": "First draft is up for review.",
"metadata": {},
"createdAt": "2026-07-13T02:41:12.000Z",
"updatedAt": "2026-07-13T02:41:12.000Z",
"user": { "id": "d3a6f0c1-...", "name": "Alex Chen", "email": "alex@example.com" }
}
]
}

metadata and the user’s avatarUrl can be absent. userId and user are null for system-generated entries. replyToId is present on replies. Up to 500 comments are returned.

Errors

  • 404 if the task does not exist, is deleted, or is in another organisation.

Add a comment to a task. The comment posts into the task’s chat thread: the task’s assignee, the project owner, and other thread participants are notified in the app and can reply there.

Requires task-comment access for tasks in your organisation.

Path parameters

NameTypeRequiredDescription
taskIdUUIDYesTask ID.

Request body

NameTypeRequiredDescription
commentTextstringYesComment body. Must not be empty.
replyToIdUUIDNoID of an existing comment on the same task to reply to.
mentionsarrayNoStructured mentions, e.g. [{ "targetType": "user", "targetId": "<user-id>" }]. Mentioned users must be active organisation members; they are notified directly.
metadataobjectNoFree-form metadata stored with the comment.

Example request

Terminal window
curl -X POST https://api.runnit.io/api/v1/tasks/<task-id>/comments \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "commentText": "First draft is up for review." }'

Response

Returns 201 with the task’s full comment list, including the new comment, in the same shape as the list endpoint above.

Errors

  • 400 if commentText is missing or empty, or no active organisation can be resolved for your account.
  • 404 if the task does not exist, is deleted, or is in another organisation.

Delete a task. Runnit also removes the task’s schedule entries, including schedule entries for subtasks deleted with the parent. The task no longer appears in task, dashboard, schedule, or capacity results.

The task’s assignee or the project owner can call this.

Path parameters

NameTypeRequiredDescription
taskIdUUIDYesTask ID.

Example request

Terminal window
curl -X DELETE https://api.runnit.io/api/v1/tasks/<task-id> \
-H 'Authorization: Bearer rnk_your_key'

Response

{ "success": true, "message": "Task deleted successfully" }

Errors

  • 404 if the task does not exist, is already deleted, or is in another organisation.
  • 403 if you are neither the task’s assignee nor the project owner (“Only the task assignee or project owner can delete tasks”).

A typical task lifecycle, end to end. Replace the placeholders with real IDs.

  1. Create the task in its project (tasks always belong to a project):
Terminal window
curl -X POST https://api.runnit.io/api/v1/projects/<project-id>/tasks \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "name": "Draft homepage copy", "priority": "high", "estimatedHours": 6 }'
  1. Assign it (use the assignee options endpoint to find valid assignees first):
Terminal window
curl -X PATCH https://api.runnit.io/api/v1/projects/<project-id>/tasks/<task-id>/assignee \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "assignedToId": "<user-uuid>" }'
  1. Move its dates when the plan changes (this rebuilds the working-day schedule):
Terminal window
curl -X PATCH https://api.runnit.io/api/v1/projects/<project-id>/tasks/<task-id>/dates \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "plannedStartDate": "2026-07-20" }'
  1. Mark it complete with actual hours (as the assignee):
Terminal window
curl -X PATCH https://api.runnit.io/api/v1/tasks/<task-id>/status \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "status": "completed", "actualHours": 5.5 }'
  1. Comment on the outcome:
Terminal window
curl -X POST https://api.runnit.io/api/v1/tasks/<task-id>/comments \
-H 'Authorization: Bearer rnk_your_key' \
-H 'Content-Type: application/json' \
-d '{ "commentText": "Done. Final copy is in the shared collection." }'

Create and schedule tasks through the Projects API, or read team schedules through the Scheduling API.