---
title: "Create a project"
method: POST
path: "/public-api/v1/projects"
tags: ["Projects"]
---

# Create a project

`POST /public-api/v1/projects`

## Request

- Base URL: `https://app.hellobonsai.com`
- URL: `https://app.hellobonsai.com/public-api/v1/projects`
- 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 project for a client you already have. `title`, `company_id`
and `billing_type` are required; find the company id with
`GET /public-api/v1/companies`.

`billing_fee` and `billing_cycle` have to agree with `billing_type`, and
a mismatch is rejected rather than ignored:

| `billing_type` | `billing_fee` | `billing_cycle` |
| --- | --- | --- |
| `fixed_fee` | required | must be omitted |
| `retainer` | required | required |
| `time` | must be omitted | must be omitted |
| `not_billable` | must be omitted | must be omitted |

`finish_date` is optional and has to be on or after `start_date`.

Bonsai fills in the rest: the project number, its client-facing URL
token, its color, and its starting members. `currency` follows the
client's currency and `start_date` defaults to today.

## Request body

- object
  - `project` object, required
    - `title` string, required: Project title. Required.
    - `company_id` integer, required: Id of the client company the project is for. Required.
    - `currency` string, nullable: Three-letter ISO 4217 currency code the project bills in. Defaults to the client's currency.
    - `start_date` string, date, nullable: Date work starts. Defaults to today.
    - `finish_date` string, date, nullable: Date work ends. Left open when omitted.
    - `billing_type` 'time' | 'fixed_fee' | 'retainer' | 'not_billable', required: How the project bills. Required. See the table above for which fee fields each type takes.
    - `billing_fee` string, nullable: The agreed fee, as a decimal string. Required for `fixed_fee` and `retainer`, rejected for the other types.
    - `billing_cycle` 'weekly' | 'monthly' | 'quarterly' | 'biannually' | 'yearly' | 'null', nullable: How often a retainer bills. Required for `retainer`, rejected for the other types.

## Response `201`

The project was created.

- object
  - `data` Project, required: An engagement you deliver for a client. Tasks, logged time and invoices all hang off a project.
    - `id` integer, required: Unique identifier for the project.
    - `title` string, nullable, required: Project title.
    - `public_url_token` string, nullable, required: Token in the project's client-facing URL. The list endpoint accepts it as `filter[public_url_token]`.
    - `currency` string, required: Three-letter ISO 4217 currency code the project bills in.
    - `start_date` string, date, nullable, required: Date work on the project starts.
    - `finish_date` string, date, nullable, required: Date work on the project ends, or `null` when it is open-ended.
    - `sequence` integer, nullable, required: Counter behind `number`, incrementing per client. `null` until a number has been assigned.
    - `number` string, nullable, required: Human-readable project reference. `null` until one has been assigned.
    - `board_group_id` string, uuid, nullable, required: Id of the pipeline stage the project's board card sits in, or `null` when the project is not on a board. Send it to `PATCH /public-api/v1/projects/{id}` to move the project to another stage.
    - `company_name` string, nullable, required: Name of the client the project is for, or `null`.
    - `client_or_company_name` string, required: Deprecated — read `company_name` instead, which carries the same value. This field will be removed in a future release.
    - `billing_type` 'time' | 'fixed_fee' | 'retainer' | 'not_billable' | 'null', nullable: How the project bills: `time` (hourly), `fixed_fee` (a single agreed fee), `retainer` (a recurring fee) or `not_billable`. Absent unless the token is allowed to see project finances.
    - `billing_cycle` 'weekly' | 'monthly' | 'quarterly' | 'biannually' | 'yearly' | 'null', nullable: How often a retainer bills. `null` for every other billing type. Absent unless the token is allowed to see project finances.
    - `billing_fee` string, nullable: The agreed fee as a decimal string, in `currency`. Set on `fixed_fee` and `retainer` projects, `null` otherwise. Absent unless the token is allowed to see project finances.
    - `company_id` integer, nullable, required: Id of the client company the project is for, or `null` when the client is not a company record.
    - `url` string, required: Absolute link to the project in the Bonsai app. Share it to send someone straight to the record.
    - `budget` ProjectBudget: A ceiling on what a project may consume — money or hours — and how often it resets.
      - `id` integer, required: Unique identifier for the budget.
      - `amount` string, required: The budget ceiling as a decimal string — an amount in the project currency when `calculation_mode` is `fee`, a number of hours when it is `time`.
      - `over_budget_notification_threshold` string, required: Percentage of the budget that triggers the alert, as a decimal string.
      - `calculation_mode` 'fee' | 'time', required: What the budget is measured in: `fee` for money, `time` for hours.
      - `calculation_base` 'billable_time' | 'non_billable_time' | 'billable_and_non_billable_time' | 'billable_time_and_expenses' | 'expenses', required: What counts against the budget: logged time (`billable_time`, `non_billable_time`, `billable_and_non_billable_time`), billable time plus expenses (`billable_time_and_expenses`), or expenses alone (`expenses`).
      - `expenses_calculation_base` 'billable' | 'non_billable' | 'all', required: Which expenses count, when `calculation_base` includes them: `billable`, `non_billable` or `all`.
      - `reset_frequency` 'never' | 'weekly' | 'monthly' | 'quarterly', required: How often the budget starts over. `never` runs one cycle for the life of the project; the rest open a fresh cycle every `weekly`, `monthly` or `quarterly` period from the project start date.
      - `over_budget_notification` 'enabled' | 'disabled', required: Whether Bonsai alerts the project team when spending passes `over_budget_notification_threshold`.
      - `current_cycle` ProjectBudgetCycle, required: One run of a budget: the window it covers and how much of the budget it has used.
        - `opening_date` string, date, required: First day the cycle counts.
        - `closing_date` string, date, nullable, required: Last day the cycle counts, or `null` when the budget never resets and the project is open-ended.
        - `consumed_amount` string, required: How much of the budget this cycle has used, as a decimal string, in the same unit as the budget `amount`.
        - `consumed_percentage` integer, required: How much of the budget this cycle has used, as a whole percentage. Exceeds 100 once the budget is over.
  - `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 `project` wrapper.
- `401`: The access token is missing, expired or invalid.
- `403`: This token is not allowed to read or create projects.
- `422`: The project could not be saved. `blank` or `invalid_value` means a required field was empty, `finish_date` falls before `start_date`, or the billing fields disagree with `billing_type`; `not_accessible` means `company_id` is not a company in your account.
- `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)
