---
title: "Log a time entry"
method: POST
path: "/public-api/v1/time_entries"
tags: ["Time Entries"]
---

# Log a time entry

`POST /public-api/v1/time_entries`

## Request

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

Logs time. Only `seconds` and `date` are required: the account comes from
the token, and the client is taken from the project, so neither is
something you send.

Attach the entry to work with `project_id` or `task_uuid`. Sending
`task_uuid` also settles the project — it is taken from the task, and any
`project_id` you send is ignored.

Two fields depend on permissions rather than on what you send. `rate` and
`non_billable` are only honoured for a token allowed to set billing; for
anyone else Bonsai derives them from the project or member rate and the
project's billing type. Logging time against someone else's name with
`owner_member_id` needs permission to manage the whole team's time; it
defaults to whoever the token belongs to.

## Request body

- object
  - `time_entry` object, required
    - `seconds` integer, required: How long the work took, in seconds. Required.
    - `date` string, date, required: The day the work was done. Required.
    - `project_id` integer, nullable: Id of the project to log against. Ignored when you also send `task_uuid`. Sample projects are not accepted. Find one with `GET /public-api/v1/projects`.
    - `task_uuid` string, uuid, nullable: `uuid` of the task to log against. The project is taken from the task. Tasks on sample projects, and template tasks, are not accepted. Find one with `GET /public-api/v1/tasks`.
    - `notes` string, nullable: What the time was spent on.
    - `rate` string, nullable: Hourly rate to bill at, as a decimal string. Must be zero or greater. Only honoured for a token allowed to set billing; otherwise it comes from the project or member rate.
    - `non_billable` boolean, nullable: Whether to exclude the entry from billing. Only honoured for a token allowed to set billing; otherwise it comes from the task or project's billing type.
    - `owner_member_id` union: Who the time is for: a team member id, or `me` for whoever the token belongs to. Defaults to the token's own member. Logging for someone else needs permission to manage the whole team's time. Find ids with `GET /public-api/v1/team_members`.
      - integer, nullable: Team member id of the person the time is for.
      - 'me': Logs the time for whoever the token belongs to.

## Response `201`

The time entry was logged.

- object
  - `data` TimeEntry, required: Time logged against a project or task, and the basis for billing hourly work.
    - `key` string, required: Unique identifier for the time entry. This is the id the update endpoint takes in its path.
    - `seconds` integer, required: Duration of the entry in seconds.
    - `date` string, date, required: Date the work was done.
    - `notes` string, nullable, required: What the time was spent on, or `null`.
    - `rate` string, nullable: Hourly rate applied to the entry, as a decimal string in `currency`. `null` when no rate applies. Absent unless the token is allowed to see billing.
    - `non_billable` boolean: Whether the entry is excluded from billing. Absent unless the token is allowed to see billing.
    - `billable_amount` string: What the entry bills for, as a decimal string in `currency`. Absent unless the token is allowed to see billing.
    - `status` 'unbilled' | 'billed', required: Whether the entry has been placed on an invoice. `billing_status` is the fuller picture, and is what the list filter matches on.
    - `project_id` integer, nullable, required: Id of the project the time is logged against, or `null` when the entry is not attached to one.
    - `owner_member_id` integer, nullable, required: Team member id of whoever the time is logged for, or `null`.
    - `created_at` string, date-time, required: When the entry was logged.
    - `billing_status` 'non_billable' | 'unbilled' | 'billed': Effective billing state: `non_billable`, `unbilled` (billable, not on an invoice yet) or `billed` (on an invoice that has been sent, is overdue, is awaiting payment or has been paid, or marked billed by hand). Accepted by `filter[billing_status]` on the list endpoint, and writable as `billed` or `unbilled` on the update endpoint. Absent unless the token is allowed to see billing.
    - `currency` string, required: Three-letter ISO 4217 currency code for `rate` and `billable_amount`.
    - `formatted_time` string, required: `seconds` rendered as `HH:MM:SS`.
    - `task_uuid` string, nullable, required: `uuid` of the task the entry is linked to, or `null` when it is logged against a project only.
  - `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 `time_entry` wrapper.
- `401`: The access token is missing, expired or invalid.
- `403`: This token is not allowed to log time.
- `422`: The entry could not be saved. `blank` or `invalid_value` means a required field was empty or the wrong shape; `not_accessible` means `project_id`, `task_uuid` or `owner_member_id` names something this token cannot use.
- `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)
