---
title: "Approve Timesheet"
method: POST
path: "/api/v1/time-tracking/timesheet-approvals"
tags: ["Time Tracking", "Public API"]
---

# Approve Timesheet

`POST /api/v1/time-tracking/timesheet-approvals`

## Request

- Base URL: `https://companySubDomain.bamboohr.com`
- URL: `https://companySubDomain.bamboohr.com/api/v1/time-tracking/timesheet-approvals`
- Auth: one of:
  - HTTP basic
  - OAuth 2
    - Authorization code: `/authorize.php`
    - Token URL: `/token.php` scopes: `time_tracking:timesheets.write`
- TypeScript: <https://skmtc.dev/bamboohr/apis/bamboohr-api/docs/api/v1/time-tracking/timesheet-approvals/post.ts> (a function with typed inputs; its response is checked against the schema)

Approves a timesheet (process resource). Only a timesheet whose derived `status` is `PENDING_APPROVAL` can be approved; approving an already-approved or not-yet-open timesheet returns 409. Returns the updated timesheet with `status` `APPROVED`.

OAuth Scopes: time_tracking:timesheets.write

## Request body

- object
  - `timesheetId` integer, required: ID of the timesheet to approve.
  - `lastChangedAt` string, date-time, required: The timesheet's `hoursLastChangedAt` value as last fetched by the caller, in ISO 8601 UTC. This is specifically `hoursLastChangedAt`, not `updatedAt`: hours are stored separately, so the timesheet row's `updatedAt` may not move when hours change (and vice versa). The approval is rejected with 409 if the timesheet's hours changed after this instant, so callers never approve a version they have not seen.

## Response `200`

Successfully approved the timesheet.

- TimeTrackingTimesheetV1: A pay period's time data for an employee.
  - `id` integer: Identifier for the timesheet.
  - `employeeId` integer: The employee this timesheet belongs to.
  - `type` 'SINGLE' | 'CLOCK' | 'MULTIPLE' | 'HOUR': Tracking method snapshotted from the configuration at period start.
  - `startDate` string, date: First date of the pay period (inclusive).
  - `endDate` string, date: Last date of the pay period (inclusive).
  - `status` 'OPEN' | 'PENDING_APPROVAL' | 'APPROVED': Derived approval state.
  - `totalHours` number, float: Sum of all hours across regular, overtime, holiday, and approved PTO.
  - `overtimeHours` number, float: Subset of totalHours that falls into the overtime rate bucket.
  - `approvedBy` integer, nullable: The user who approved the timesheet. Null until approved.
  - `approvedAt` string, date-time, nullable: When the timesheet was approved. Null until approved.
  - `createdAt` string, date-time: When the timesheet record was created.
  - `updatedAt` string, date-time: When the timesheet was last modified.
  - `hoursLastChangedAt` string, date-time: When the timesheet's hours were last changed. Send this value back as the approval request's `lastChangedAt`. Distinct from `updatedAt` because hours are stored separately from the timesheet row.

## Other responses

- `400`: Malformed request body (e.g. missing timesheetId or lastChangedAt).
- `401`: Unauthorized. Missing or invalid authentication.
- `403`: Forbidden. Insufficient permissions.
- `404`: Timesheet not found.
- `409`: Timesheet is already approved, its approval window has not opened (status is not PENDING_APPROVAL), or it changed after the provided lastChangedAt.
- `422`: The provided timesheetId is not a valid positive integer, or lastChangedAt is not a valid ISO 8601 UTC timestamp.

## Changes

- **2026-11-03** `922fc15f43a7`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/bamboohr/apis/bamboohr-api/changes/api/v1/time-tracking/timesheet-approvals/post.md)

---

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