Time Off Policies
The time off policy object
| Attribute | Type | Description |
|---|---|---|
id |
integer | Unique ID for the time off policy. |
name |
string | The name of the time off policy (e.g. “Vacation”, “Sick Leave”). |
color |
string | Color assigned to the policy in the UI. |
icon |
string | Icon slug assigned to the policy. |
accrual_type |
string | Accrual mode for the policy: fixed (front-loaded allowance), accrued (earned over time), or unlimited. |
accrual_schedule |
string | Frequency for policy accruals: monthly, biweekly, semimonthly, or hourly. Required and meaningful when accrual_type is accrued. |
accrual_first_payday |
date | Anchor date for biweekly accruals. |
accrual_leave_hours |
decimal | Leave hours earned per worked hour base (for hourly accruals). |
accrual_worked_hours |
decimal | Worked hours base (for hourly accruals). |
accrual_max_hours_per_year |
decimal | Maximum accrued hours cap per year (for hourly accruals). |
default_days_per_year |
decimal | Default days per year credited to teammates. |
max_carryover_days |
decimal | Maximum days allowed to carry over between years. |
requires_approval |
boolean | Whether requests booked under this policy require manager or admin review. |
visible_to_all |
boolean | Whether this policy is visible to all teammates for self-booking. |
is_active |
boolean | Whether the policy is active or deactivated. |
created_at |
datetime | Date and time the policy was created. Use the ISO 8601 Format. |
updated_at |
datetime | Date and time the policy was last updated. Use the ISO 8601 Format. |
Required permissions
The PTO API is currently being rolled out gradually. Requests from unavailable accounts return 403 Forbidden.
Administrators can list, create, update, deactivate, and permanently delete time off policies.
Non-administrators can list and view active policies that are configured as visible to all teammates. Listing policies will omit hidden or deactivated policies for non-administrators, and attempting to view a policy that is not visible will result in a 404 Not Found response code.
List all time off policies
Returns a list of time off policies.
The response contains an object with a pto_types property that contains an array of up to per_page time off policies. Each entry in the array is a separate time off policy object. If no more policies are available, the resulting array will be empty. Several additional pagination properties are included in the response to simplify paginating your policies.
GET /v2/pto/types
| Parameter | Type | Description |
|---|---|---|
is_active |
boolean | Pass true to return active policies and false to return deactivated policies. (Default: true) |
updated_since |
datetime | Only return policies updated since this timestamp. |
page |
integer | The page number to use in pagination. (Default: 1) |
per_page |
integer | The number of records to return per page. Can range between 1 and 2000. (Default: 2000) |
Example Request:
curl "https://api.harvestapp.com/v2/pto/types" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "User-Agent: MyApp ([email protected])"
Example Response:
{
"pto_types": [
{
"id": 101,
"name": "Vacation",
"color": "blue",
"icon": "vacation",
"accrual_type": "fixed",
"accrual_schedule": "monthly",
"default_days_per_year": 25.0,
"max_carryover_days": 5.0,
"requires_approval": true,
"visible_to_all": true,
"is_active": true,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}
],
"per_page": 2000,
"total_pages": 1,
"total_entries": 1,
"next_page": null,
"previous_page": null,
"page": 1,
"links": {
"first": "https://api.harvestapp.com/v2/pto/types?page=1&per_page=2000",
"next": null,
"previous": null,
"last": "https://api.harvestapp.com/v2/pto/types?page=1&per_page=2000"
}
}Retrieve a time off policy
Retrieves the details of an existing time off policy. Returns a time off policy object and a 200 OK response code.
GET /v2/pto/types/{PTO_TYPE_ID}
Example Request:
curl "https://api.harvestapp.com/v2/pto/types/101" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "User-Agent: MyApp ([email protected])"
Example Response:
{
"id": 101,
"name": "Vacation",
"color": "blue",
"icon": "vacation",
"accrual_type": "fixed",
"accrual_schedule": "monthly",
"default_days_per_year": 25.0,
"max_carryover_days": 5.0,
"requires_approval": true,
"visible_to_all": true,
"is_active": true,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}Create a time off policy
Creates a new time off policy. Returns a time off policy object and a 201 Created response code if the call succeeded. Only administrators can perform this action.
POST /v2/pto/types
| Parameter | Type | Description |
|---|---|---|
name |
string | Required. The policy name. |
color |
string | Optional color code. |
icon |
string | Optional icon name. |
accrual_type |
string | Accrual mode: fixed, accrued, or unlimited. (Default: fixed) |
accrual_schedule |
string | Accrual interval: monthly, biweekly, semimonthly, or hourly. Required when accrual_type is accrued. |
accrual_first_payday |
date | Anchor date required when accrual_schedule is biweekly. |
accrual_leave_hours |
decimal | Hours of leave earned per worked interval when accrual_schedule is hourly. |
accrual_worked_hours |
decimal | Base worked hours required to earn leave when accrual_schedule is hourly. |
accrual_max_hours_per_year |
decimal | Annual cap on accrued leave hours when accrual_schedule is hourly. |
default_days_per_year |
decimal | Default days per year. |
max_carryover_days |
decimal | Maximum carryover days allowed. |
requires_approval |
boolean | Whether requests require approval. |
visible_to_all |
boolean | Whether visible to all users. |
Example Request:
curl -X POST "https://api.harvestapp.com/v2/pto/types" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "Content-Type: application/json" \
-H "User-Agent: MyApp ([email protected])" \
-d '{"name": "Floating Holiday", "default_days_per_year": 2.0, "requires_approval": false}'
Example Response:
{
"id": 102,
"name": "Floating Holiday",
"color": "orange",
"icon": "calendar",
"accrual_type": "fixed",
"accrual_schedule": "monthly",
"default_days_per_year": 2.0,
"max_carryover_days": 0.0,
"requires_approval": false,
"visible_to_all": true,
"is_active": true,
"created_at": "2026-09-03T12:00:00Z",
"updated_at": "2026-09-03T12:00:00Z"
}Update a time off policy
Updates an existing time off policy. Returns a time off policy object and a 200 OK response code if the call succeeded. Only administrators can perform this action.
PATCH /v2/pto/types/{PTO_TYPE_ID}
| Parameter | Type | Description |
|---|---|---|
name |
string | The updated policy name. |
color |
string | The updated color. |
icon |
string | The updated icon. |
accrual_type |
string | The updated accrual mode (fixed, accrued, unlimited). |
accrual_schedule |
string | The updated accrual interval (monthly, biweekly, semimonthly, hourly). |
accrual_first_payday |
date | The updated first payday for biweekly accruals. |
accrual_leave_hours |
decimal | The updated leave hours earned per period for hourly accruals. |
accrual_worked_hours |
decimal | The updated base worked hours for hourly accruals. |
accrual_max_hours_per_year |
decimal | The updated maximum accruable hours for hourly accruals. |
default_days_per_year |
decimal | The updated default days per year. |
max_carryover_days |
decimal | The updated maximum carryover days. |
requires_approval |
boolean | Update approval requirement. |
visible_to_all |
boolean | Update visibility. |
deactivated |
boolean | Set to false to reactivate a deactivated policy. |
Example Request:
curl -X PATCH "https://api.harvestapp.com/v2/pto/types/101" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "Content-Type: application/json" \
-H "User-Agent: MyApp ([email protected])" \
-d '{"default_days_per_year": 28.0}'
Example Response:
{
"id": 101,
"name": "Vacation",
"color": "blue",
"icon": "vacation",
"accrual_type": "fixed",
"accrual_schedule": "monthly",
"default_days_per_year": 28.0,
"max_carryover_days": 5.0,
"requires_approval": true,
"visible_to_all": true,
"is_active": true,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-09-03T12:05:00Z"
}Delete a time off policy
Deletes or deactivates an existing time off policy. By default, time off policies are deactivated rather than permanently deleted so historical requests and allocations remain preserved. Returns a 200 OK response code and the deactivated time off policy object with is_active set to false.
To permanently delete a policy along with all of its associated requests and historical data, pass keep_history=false and confirm_delete_history=1. A successful permanent deletion returns a 204 No Content response code. A policy cannot be permanently deleted if it is the only remaining policy in the company or if it has requests included in locked payroll. Only administrators can perform this action.
DELETE /v2/pto/types/{PTO_TYPE_ID}
| Parameter | Type | Description |
|---|---|---|
keep_history |
boolean | Pass false to permanently delete the policy and its requests instead of deactivating it. (Default: true) |
confirm_delete_history |
integer | Must be passed as 1 when keep_history is false to confirm deletion of all historical requests. |
Example Request:
curl -X DELETE "https://api.harvestapp.com/v2/pto/types/101" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Harvest-Account-Id: $ACCOUNT_ID" \
-H "User-Agent: MyApp ([email protected])"
Example Response:
{
"id": 101,
"name": "Vacation",
"color": "blue",
"icon": "vacation",
"accrual_type": "fixed",
"accrual_schedule": "monthly",
"default_days_per_year": 28.0,
"max_carryover_days": 5.0,
"requires_approval": true,
"visible_to_all": true,
"is_active": false,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-09-03T12:10:00Z"
}