---
title: "Create a task"
method: POST
path: "/public-api/v1/tasks"
tags: ["Tasks"]
---

# Create a task

`POST /public-api/v1/tasks`

## Request

- Base URL: `https://app.hellobonsai.com`
- URL: `https://app.hellobonsai.com/public-api/v1/tasks`
- Auth: one of:
  - OAuth 2
    - Authorization code: `https://app.hellobonsai.com/oauth/authorize`
    - Token URL: `https://app.hellobonsai.com/oauth/token`
  - HTTP bearer

Creates a task. Only `title` is required — a task does not need a project,
an assignee or a date.

Assign the task with `assignee_member_id`: a team member id from
`GET /public-api/v1/team_members`, or `me` for whoever the token belongs
to. Responses report the assignee twice, as `assignee_member_id` and as
the user's `assignee_id`, but only `assignee_member_id` is writable.

## Subtasks

Send `parent_task_uuid` to create the task underneath an existing one.
A subtask takes its project and billable setting from its parent, so
`project_id` cannot be sent alongside `parent_task_uuid`. `billable` can
still be set explicitly.

Tasks nest two levels deep at most — a top-level task, a subtask, and a
subtask of that. Pointing at a parent that is already at the bottom
fails with `422 invalid_value`. Read a task's children with
`GET /public-api/v1/tasks/{uuid}/subtasks`.

## Request body

- object
  - `task` object, required
    - `title` string, required: Task title. Required.
    - `project_id` integer, nullable: Id of the project the task belongs to. Leave it out for a task that stands on its own. Cannot be combined with `parent_task_uuid` — a subtask takes its project from its parent. Find one with `GET /public-api/v1/projects`.
    - `deal_id` integer, nullable: Id of the deal to put the task on. Independent of `project_id` — a task can sit on a deal, a project, both or neither. Needs permission to create deals; without it the request fails with `422 not_accessible`. A deal that is not in your account fails the same way. Find one with `GET /public-api/v1/deals`.
    - `parent_task_uuid` string, nullable: `uuid` of the task to nest this one under. The subtask takes its project and billable setting from the parent, so `project_id` cannot be sent with it. A parent that is not in your account fails with `422 not_accessible`; a parent already two levels deep fails with `422 invalid_value`.
    - `assignee_member_id` union: Who the task is for: a team member id, or `me` for whoever the token belongs to. Send `null` or leave it out for an unassigned task. Find ids with `GET /public-api/v1/team_members` — use the `company_member_id` field.
      - integer, nullable: Team member id of the assignee.
      - 'me': Assigns the task to whoever the token belongs to.
    - `priority` 'urgent' | 'high' | 'medium' | 'low' | 'null', nullable: How urgent the task is.
    - `due_date` string, date, nullable: Date the task is due. Leave it out for an unscheduled task. Cannot be earlier than `start_date` when you send both.
    - `start_date` string, date, nullable: Date work on the task starts. Cannot be later than `due_date` when you send both.
    - `description` string, nullable: What the task involves. Accepts an HTML fragment for formatting — `<p>`, `<strong>`, `<ul>`/`<li>` and `<a>` among others. Read it back as `description_html` (sanitized) or `description_plain_text` (tags removed) on single-task responses; neither appears in a list.
    - `time_estimate_in_minutes` integer, nullable: Estimated effort in whole minutes — 90 for an hour and a half. Must be positive.
    - `task_status_id` string, nullable: Id of the board column to put the task in. Defaults to your `To Do` column. Find one with `GET /public-api/v1/task_statuses`.
    - `billable` boolean: Whether time tracked on the task is billable. Left out, it defaults the way the app does: a subtask inherits its parent, a task on a not-billable project is not billable, and everything else is billable. Only honoured for a token allowed to set billing, on a plan that includes task billing — otherwise the value is ignored and the default applies. `permissions.tasks.billing_update` from `GET /public-api/v1/permissions/me` tells you which you have; note that `permissions.tasks.billing` only covers reading it back.
    - `tag_ids` integer[]: Tags to put on the task. Must be `task` tags from your account — find them with `GET /public-api/v1/company_tags`. Read them back under `company_tags`.

## Response `201`

The task was created.

- object
  - `data` object, required: The description fields returned when you retrieve a single task, but never in a list.
    - `uuid` string, uuid, nullable, required: Unique identifier for the task. This is the id every task endpoint takes in its path.
    - `title` string, nullable, required: Task title.
    - `number` string, nullable, required: Human-readable task reference. `null` until one has been assigned.
    - `due_date` string, date, nullable, required: Date the task is due, or `null` when it is unscheduled.
    - `start_date` string, date, nullable, required: Date work on the task starts, or `null` when unset.
    - `time_estimate_in_minutes` integer, nullable, required: Estimated effort in whole minutes, or `null` when no estimate is set.
    - `priority` 'urgent' | 'high' | 'medium' | 'low' | 'null', nullable, required: Priority bucket, or `null` when the task has no priority.
    - `completed_at` string, date-time, nullable, required: When the task was marked complete, or `null` while it is still open.
    - `archived_at` string, date-time, nullable, required: When the task was archived, or `null` while it is active.
    - `assignee_id` integer, nullable, required: User id of the assignee, or `null` when unassigned. Read-only — the create and update endpoints take `assignee_member_id` instead.
    - `assignee_member_id` integer, nullable, required: Team member id of the assignee, or `null` when unassigned. This is the value the create and update endpoints accept.
    - `creator_member_id` integer, nullable, required: Team member id of whoever created the task.
    - `project_id` integer, nullable, required: Id of the project the task belongs to, or `null` for a task that stands on its own.
    - `billable` boolean, nullable: Whether time logged against this task can be billed to the client. Absent unless the token is allowed to see billing.
    - `deal_id` integer, nullable: Id of the deal the task belongs to, or `null` when it is not attached to a deal. Absent unless the token is allowed to see deals.
    - `parent_task_uuid` string, nullable, required: `uuid` of this task's parent when it is a subtask, `null` for a top-level task.
    - `project_title` string, nullable, required: Title of the project the task belongs to, or `null`.
    - `assignee_member_name` string, nullable, required: Name of the assignee, or `null` when the task is unassigned.
    - `url` string, required: Absolute link to the task in the Bonsai app. Resolves to the task on its project board, or to the standalone task list when it belongs to no project.
    - `task_status` TaskStatus, required: A column of your task board. Moving a task between statuses is how you track its progress.
      - `id` string, uuid, required: Unique identifier for the status. Pass this value as `task_status_id` when creating or updating a task.
      - `status` string, required: Status name as it appears on the board.
      - `state` 'active' | 'complete', required: Whether tasks in this status count as open (`active`) or finished (`complete`).
      - `color` string, nullable, required: Hex color the status is drawn in, or `null` when it has none.
      - `position` integer, required: Position of the status on the board, ordered left to right.
    - `company_tags` CompanyTag[], required: Tags applied to the task. Only `id` and `name` are returned here — list the tags endpoint for a tag's type and color.
      - `id` integer, required: Unique identifier for the tag. Pass this value in `tag_ids` when tagging a task.
      - `name` string, required: Tag name as it appears in Bonsai.
    - `description_html` string, nullable, required: Task description as an HTML fragment, sanitized to a safe set of tags. Returned on single-task responses only, never in a list.
    - `description_plain_text` string, nullable, required: Task description with all HTML removed. Returned on single-task responses only, never in a list.
  - `meta` Meta, required: Metadata returned alongside every single-resource response.
    - `request_id` string, required: Identifier for this request. Quote it when contacting support about a specific call.

## Other responses

- `400`: The request body is missing its `task` wrapper.
- `401`: The access token is missing, expired or invalid.
- `403`: This token is not allowed to create tasks.
- `422`: The task could not be saved. `blank` or `invalid_value` means a field was empty or the wrong shape; `not_accessible` means a referenced record is not in your account, or that this token is not allowed to set that particular field — `priority`, `due_date`, `start_date`, `time_estimate_in_minutes` and `assignee_member_id` all need permission to edit task details, and `deal_id` needs permission to create deals on top of that.
- `429`: Rate limit exceeded. Wait at least `Retry-After` seconds before trying again.

---

[API](https://skmtc.dev/hellobonsai/apis/bonsai-api.md) - [All operations](https://skmtc.dev/hellobonsai/apis/bonsai-api/llms.txt) - [OpenAPI document](https://skmtc.dev/hellobonsai/apis/bonsai-api/revisions/abf12ed6a8d3?raw)
