Tasks API

Manage tasks (also called "steps") within projects and phases. Tasks represent individual work items that can be assigned, tracked, and completed.

The Task Object

{
  "id": 123,
  "title": "Design homepage wireframe",
  "completed": false,
  "published": true,
  "is_approval": false,
  "approval_status": null,
  "due_date": "2023-02-15T00:00:00.000000Z",
  "created_at": "2023-01-01T12:00:00.000000Z",
  "updated_at": "2023-01-01T12:00:00.000000Z",
  "phase": { "id": 456, "title": "Design Phase", "is_internal": false },
  "project": { "id": 789, "title": "Website Redesign" },
  "client": { "id": 101, "title": "Acme Corporation" },
  "company": { "id": 202, "title": "Design Studio Inc" },
  "tags": [ { "id": 12, "name": "Round 1 of 2", "color": "mint" } ],
  "assignees": [ { "id": 3, "name": "Dave Prince" } ]
}

due_date is returned as an empty string ("") when the task has no due date. assignees is included in list responses; single-task responses (get / create / update) omit it — read or change assignees via the Task Assignees endpoints.

A task's audience comes from its phase. A task has no visibility flag of its own — it is internal (team-only) or client-facing purely according to its phase's is_internal value (surfaced on the task as phase.is_internal). To change a task's audience, move it to a phase on the other side. Separately, published controls whether a client-facing task is visible to the client yet or still a draft.

Attributes

Attribute Type Description
id integer Unique identifier for the task
title string The task's name
completed boolean Whether the task has been completed
due_date string Task due date (ISO 8601), or "" when not set
published boolean Whether the task is published (visible) within its phase
is_approval boolean Whether the task is an approval (sign-off) gate
approval_status string or null Verdict recorded when an approval task is completed: approved or not_approved. null while the task is open, or for non-approval tasks
content string Task body as Markdown. Only returned when requested via ?include=content (see below)
tags object[] Tags applied to the task (id, name, color). Only returned when requested via ?include=tags (see below); an empty array when the task has no tags. Change them via the Task Tags endpoints below — tags is read-only on create and update
phase object The phase the task belongs to (id, title, is_internal)
project object The project the task belongs to (id, title)
client object The client the task belongs to (id, title)
company object The agency company that owns the task (id, title)
assignees object[] Users assigned to the task (id, name). Managed via the Task Assignees endpoints

Including task content: The Markdown content field is opt-in for performance. Append ?include=content to a list or single-task request to have it returned. Without it, content is omitted from the response.

Including tags: Tags are opt-in in the same way — append ?include=tags to a list or single-task request. Combine includes with a comma, e.g. ?include=content,tags. Each tag is an object with an id, a name, and a color (one of mandarin, coral, pink, orchid, mint, aqua, mustard, steel). Tasks with no tags return [].

List Tasks

Retrieves a list of tasks the authenticated user has access to. Tasks belonging to template projects are always excluded.

GET /api/v1/steps

Query Parameters

Parameter Type Description
company_id integer Filter tasks by specific company ID
completed boolean Filter by completion status
has_due_date boolean Filter tasks that have or don't have due dates
exclude_templates boolean Deprecated and no longer necessary — template tasks are always excluded. Accepted but has no effect
include string Comma-separated extra fields to include. Use content to return each task's Markdown body, and tags to return each task's tags.
per_page integer Number of results per page (max 1000)

Example Request

GET /api/v1/steps?completed=false&company_id=202&include=content&per_page=25
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json

Example Response

[
  {
    "id": 123,
    "title": "Design homepage wireframe",
    "completed": false,
    "published": true,
    "due_date": "2023-02-15T00:00:00.000000Z",
    "created_at": "2023-01-01T12:00:00.000000Z",
    "updated_at": "2023-01-01T12:00:00.000000Z",
    "phase": { "id": 456, "title": "Design Phase", "is_internal": false },
    "project": { "id": 789, "title": "Website Redesign" },
    "client": { "id": 101, "title": "Acme Corporation" },
    "company": { "id": 202, "title": "Design Studio Inc" },
    "assignees": [ { "id": 3, "name": "Dave Prince" } ]
  }
]

Get a Task

Retrieves a specific task by ID.

GET /api/v1/steps/{id}

Example Request

GET /api/v1/steps/123
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json

Example Response

{
  "id": 123,
  "title": "Design homepage wireframe",
  "completed": false,
  "published": true,
  "due_date": "2023-02-15T00:00:00.000000Z",
  "created_at": "2023-01-01T12:00:00.000000Z",
  "updated_at": "2023-01-01T12:00:00.000000Z",
  "phase": { "id": 456, "title": "Design Phase", "is_internal": false },
  "project": { "id": 789, "title": "Website Redesign" },
  "client": { "id": 101, "title": "Acme Corporation" },
  "company": { "id": 202, "title": "Design Studio Inc" }
}

Create a Task

Creates a new task within a phase.

POST /api/v1/steps

Request Body

Parameter Type Required Description
title string Yes The task's name
phase_id integer Yes ID of the phase this task belongs to
content string No Task content that will appear in the task details. Plain text is automatically converted to rich text format.
due_date string No Task due date (YYYY-MM-DD)
completed boolean No Whether the task is completed (defaults to false)
published boolean No Whether the task is published (visible) within its phase
is_approval boolean No Create the task as an approval (sign-off) gate (defaults to false)

Example Request

POST /api/v1/steps
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Accept: application/json

{
  "title": "Create user flow diagram",
  "phase_id": 456,
  "content": "Design user flow for the new checkout process.\n\nInclude all edge cases and error states.",
  "due_date": "2023-02-20"
}

Example Response

{
  "id": 124,
  "title": "Create user flow diagram",
  "completed": false,
  "published": true,
  "due_date": "2023-02-20T00:00:00.000000Z",
  "created_at": "2023-01-15T10:00:00.000000Z",
  "updated_at": "2023-01-15T10:00:00.000000Z",
  "phase": { "id": 456, "title": "Design Phase", "is_internal": false },
  "project": { "id": 789, "title": "Website Redesign" },
  "client": { "id": 101, "title": "Acme Corporation" },
  "company": { "id": 202, "title": "Design Studio Inc" }
}

Update a Task

Updates an existing task's information, including marking it as completed.

Attachments, form fields, and embeds are preserved on content updates. Markdown cannot express these elements, so when content replaces the body, any such elements in the existing content are kept in place even if your markdown omits them (elements retained as plain links are upgraded back to their original form). To remove them deliberately, pass allow_removing_attachments: true.

PUT /api/v1/steps/{id}

Request Body

Parameter Type Description
title string The task's name
content string Task content/description. Plain text is automatically converted to rich text format.
completed boolean Whether the task is completed
published boolean Whether the task is published (visible) within its phase
is_approval boolean Turn the approval (sign-off) requirement on or off for the task
approval_status string Verdict for an approval task: approved or not_approved. Only valid together with completed: true (or on an already-completed approval task). Completing an approval task without it records approved; reopening the task clears the verdict
due_date string|null Task due date (YYYY-MM-DD). Send null to clear it
phase_id integer Move the task to a different phase. The phase must belong to a project in one of your companies — it can be in another project, and it can be an internal phase

Moving a task between phases: Setting phase_id moves the task, which also changes its visibility — moving a task into an internal phase hides it from the client, and moving it into a client-facing phase exposes it. Check the target phase's is_internal flag before you move.

Example Request

PUT /api/v1/steps/123
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Accept: application/json

{
  "title": "Design homepage wireframe (Updated)",
  "content": "Updated requirements based on client feedback.",
  "completed": true,
  "due_date": "2023-02-18"
}

Example Response

{
  "id": 123,
  "title": "Design homepage wireframe (Updated)",
  "completed": true,
  "published": true,
  "due_date": "2023-02-18T00:00:00.000000Z",
  "created_at": "2023-01-01T12:00:00.000000Z",
  "updated_at": "2023-01-15T14:30:00.000000Z",
  "phase": { "id": 456, "title": "Design Phase", "is_internal": false },
  "project": { "id": 789, "title": "Website Redesign" },
  "client": { "id": 101, "title": "Acme Corporation" },
  "company": { "id": 202, "title": "Design Studio Inc" }
}

Task Tags

Read and change the tags on a task. Tags are flat objects — an id, a name, and a color — and every one of these endpoints returns the task's complete tag list after the change, so you never have to re-read the task.

GET /api/v1/steps/{id}/tags — list the task's tags
POST /api/v1/steps/{id}/tags — add tags, keeping the existing ones
PUT /api/v1/steps/{id}/tags — replace the task's tags
DELETE /api/v1/steps/{id}/tags/{tag_id} — remove one tag

Request Body (POST and PUT)

Parameter Type Required Description
tags array Yes Tag references. Each entry is either a tag id (a number, e.g. 12) or a tag name (a string, e.g. "Round 2 of 2"). Max 100 per request. On PUT, send [] to clear the task's tags
create_missing boolean No Whether a name that matches no existing tag creates a new one. Defaults to true; pass false to get a 422 for unknown names instead

Names are matched case-insensitively. "round 1 of 2" finds an existing Round 1 of 2 rather than creating a second tag. The JSON type is what tells a name from an id: 12 means “tag 12”, while "12" means “the tag named 12”. Names only ever match tags in your own company — a tag belonging to another company can never be applied, and applying your tag to another company's task is rejected too.

Example Request

PUT /api/v1/steps/123/tags
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json
Accept: application/json

{
  "tags": [12, "Ready for QA"]
}

Example Response

{
  "data": [
    { "id": 12, "name": "Round 1 of 2", "color": "mint" },
    { "id": 31, "name": "Ready for QA", "color": "coral" }
  ],
  "added": [ { "id": 31, "name": "Ready for QA", "color": "coral" } ],
  "removed": [],
  "created": [ { "id": 31, "name": "Ready for QA", "color": "coral" } ]
}

Response Fields

Field Description
data The task's complete tag list after the change
added Tags this request put on the task. Empty when the task already had them
removed Tags this request took off the task
created Tags that did not exist in your workspace before this request and were created by it. Worth surfacing to a human — a mistyped name becomes a permanent tag

GET and PUT return 200; POST returns 201; DELETE returns 200 with the remaining tags. Adding a tag the task already has, or removing one it does not have, is a no-op rather than an error. Tagging is a team action: client-side users cannot change a task's tags.

A few tags are read-only. Tags belonging to a retired set are still shown on tasks that carry them, but cannot be added or removed through the API — naming one returns 422, and replacing a task's tags with PUT leaves any such tag exactly where it is. Everything else behaves normally.

Changing a task's tags fires the task.tags_updated webhook, which carries the added and removed tags alongside the task.

Reorder a Task

Repositions a task within its phase. Pass either position ("first" or "last") or after_step_id to place the task directly after another task in the same phase — the same result as drag-and-drop in the app.

POST /api/v1/steps/{id}/reorder

Parameters

Parameter Type Description
position string "first" or "last". Required unless after_step_id is given.
after_step_id integer Place the task directly after this task. Must be a task in the same phase; returns 422 otherwise.

Example Request

POST /api/v1/steps/123/reorder
Authorization: Bearer YOUR_ACCESS_TOKEN
Content-Type: application/json

{
  "position": "first"
}

Returns the updated task object, including its new order.

Delete a Task

Permanently deletes a task. Only company members can delete tasks.

DELETE /api/v1/steps/{id}

Warning: Deleting a task will permanently remove it and cannot be undone. Consider marking tasks as completed instead of deleting them to maintain project history.

Example Request

DELETE /api/v1/steps/123
Authorization: Bearer YOUR_ACCESS_TOKEN
Accept: application/json

Example Response

204 No Content