---
updatedAt: 2026-04-28T00:16:41.000Z
---

Fetch the complete documentation index at: https://docs.gusto.com/embedded-payroll/llms.txt. Use this file to discover all available pages before exploring further. Append .md to any documentation page URL to get its markdown version.

# Time off requests

Submit time off requests, manage admin approvals, and apply time off automatically to payroll

This guide covers implementing time off requests and approvals using the Gusto Embedded Payroll time off request APIs. It covers the full request lifecycle — from balance checking and submission through admin approval — and payroll integration.

For managing time off policies (accrual rules, policy creation, assigning employees), see [Time Off Policies](https://docs.gusto.com/embedded-payroll/docs/time-off-policies).

<Callout icon="📘" theme="info">
  #### Prerequisites

  Employees must be assigned to a time off policy before requests can be submitted. See [Manage time off policies](https://docs.gusto.com/embedded-payroll/docs/manage-time-off-policies) to set up policies and enroll employees.
</Callout>

## Integration patterns

How you use these APIs depends on whether you have your own time tracking system.

<Tabs>
  <Tab title="No native time suite">
    Use the full request lifecycle: check balances, preview impact, create requests in `pending` status, then approve or decline.

    Employees submit requests through your UI; Gusto handles balance tracking and payroll integration. Use the `time_off_request_management` flow to give admins an embedded approval interface, or call the approve/decline endpoints directly from your own UI.

    **Typical flow:**

    ```
    GET  /v1/companies/{company_uuid}/time_off/balances
    POST /v1/companies/{company_uuid}/time_off/requests/preview
    POST /v1/companies/{company_uuid}/time_off/requests
    PUT  /v1/time_off/requests/{time_off_request_uuid}/approve
    ```
  </Tab>

  <Tab title="Native time suite">
    Partners with their own time off system can record approved time off in Gusto without re-implementing the approval workflow. Use [POST /v1/companies/\{company\_uuid}/time\_off/admin\_approved\_requests](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_uuid-time_off-admin_approved_requests) to create requests that are immediately approved and applied to payroll. Requires `time_off_requests:manage` scope.

    Gusto becomes the system of record for payroll purposes while your platform remains the source of truth for approvals.
  </Tab>
</Tabs>

## Required scopes

| Scope                      | Required for                                                                                      |
| -------------------------- | ------------------------------------------------------------------------------------------------- |
| `time_off_requests:read`   | Listing and retrieving requests; checking balances; previewing balance impact                     |
| `time_off_requests:write`  | Creating and canceling employee-initiated requests                                                |
| `time_off_requests:manage` | Approving and declining requests; creating admin-initiated requests via `admin_approved_requests` |

Partners building a complete integration need all three scopes. Read-only integrations (e.g. syncing request status into your platform) only need `time_off_requests:read`.

## Request statuses

| Status     | Description                                                    |
| ---------- | -------------------------------------------------------------- |
| `pending`  | Submitted by an employee, awaiting admin review                |
| `approved` | Approved by an admin; will be applied to the next payroll      |
| `declined` | Declined by an admin                                           |
| `consumed` | Applied to a completed payroll; cannot be modified or canceled |

## Step 1: Check time off balances

Before displaying a request form, fetch the employee's current balances to show available hours per policy.

Call [GET /v1/companies/\{company\_uuid}/time\_off/balances](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_uuid-time_off-balances).

**Scope required:** `time_off_requests:read`

**Query parameters**

| Parameter        | Type    | Description                                      |
| ---------------- | ------- | ------------------------------------------------ |
| `employee_uuids` | string  | Comma-separated employee UUIDs to filter results |
| `policy_uuids`   | string  | Comma-separated policy UUIDs to filter results   |
| `page`           | integer | Page number                                      |
| `per`            | integer | Results per page                                 |

**Response**

```json
[
  {
    "employee_uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "balances": [
      {
        "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
        "balance_hours": "32.0",
        "accrued_hours": "40.0",
        "used_hours": "8.0",
        "pending_hours": "0.0"
      }
    ]
  }
]
```

Each entry in the response contains one object per employee, with a nested `balances` array containing one entry per policy. All hour values are string decimals. For unlimited policies, `balance_hours` is `null`.

## Step 2: Preview balance impact

Show the employee how a request would affect their remaining balance before they submit.

Call [POST /v1/companies/\{company\_uuid}/time\_off/requests/preview](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_uuid-time_off-requests-preview).

**Scope required:** `time_off_requests:read`

**Request**

```json
POST /v1/companies/a4d13b1e-2f89-4c3b-a5d8-7e6c94f21a3d/time_off/requests/preview

{
  "employee_uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
  "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
  "start_date": "2026-05-26",
  "end_date": "2026-05-27",
  "days": {
    "2026-05-26": "8.000",
    "2026-05-27": "8.000"
  }
}
```

The `days` field is an object mapping dates (`YYYY-MM-DD`) to hours as string decimals. Every date in the `start_date`/`end_date` range must be included as a key — see [the `days` field](#the-days-field) below.

To preview changes to an existing request, pass the existing `request_uuid` in the body; the existing request's values are used as defaults for any fields you omit.

**Response**

```json
{
  "balance_hours": "64.0",
  "this_request_hours": "16.0",
  "other_requested_hours": "0.0",
  "remaining_balance_hours": "48.0",
  "allow_negative_balance": false,
  "unlimited": false
}
```

`remaining_balance_hours` = `balance_hours` − `this_request_hours` − `other_requested_hours`. If this is negative and `allow_negative_balance` is `false`, the submission will be rejected. If `unlimited` is `true`, all hour fields will be `null`.

## Step 3: Create a time off request

Call [POST /v1/companies/\{company\_uuid}/time\_off/requests](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_uuid-time_off-requests) to submit the request. All requests created via this endpoint start in `pending` status.

**Scope required:** `time_off_requests:write`

**Request**

```json
POST /v1/companies/a4d13b1e-2f89-4c3b-a5d8-7e6c94f21a3d/time_off/requests

{
  "employee_uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
  "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
  "start_date": "2026-05-26",
  "end_date": "2026-05-27",
  "days": {
    "2026-05-26": "8.000",
    "2026-05-27": "8.000"
  },
  "employee_note": "Family vacation"
}
```

**Response**

```json
{
  "uuid": "ad158cfb-99e4-4741-9db3-0bd3a267f222",
  "status": "pending",
  "policy_type": "vacation",
  "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
  "days": {
    "2026-05-26": "8.000",
    "2026-05-27": "8.000"
  },
  "employee_note": "Family vacation",
  "employer_note": null,
  "employee": {
    "uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "full_name": "Alex Johnson"
  },
  "initiator": {
    "uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "full_name": "Alex Johnson"
  },
  "approver": null
}
```

### The `days` field

The `days` field is required on all create and preview endpoints. It must be a JSON object where:

* Keys are dates in `YYYY-MM-DD` format
* Values are hours as strings or numbers, between `0` and `24`
* **Every date from `start_date` through `end_date` inclusive must appear as a key** — partial ranges are not accepted

For example, a request from May 26–28 must include all three dates:

```json
"days": {
  "2026-05-26": "8.000",
  "2026-05-27": "8.000",
  "2026-05-28": "4.000"
}
```

## Step 4: Approve or decline a request

### Approve

Call [PUT /v1/time\_off/requests/\{time\_off\_request\_uuid}/approve](https://docs.gusto.com/embedded-payroll/reference/put-v1-time_off-requests-time_off_request_uuid-approve). Only `pending` requests can be approved.

**Scope required:** `time_off_requests:manage`

The request body is optional. Omit `days` to approve the request as submitted. Include `days` to override the hours at approval time.

**Request**

```json
PUT /v1/time_off/requests/ad158cfb-99e4-4741-9db3-0bd3a267f222/approve

{
  "employer_note": "Approved — enjoy your vacation!",
  "days": {
    "2026-05-26": "8.000",
    "2026-05-27": "8.000"
  }
}
```

**Response**

```json
{
  "uuid": "ad158cfb-99e4-4741-9db3-0bd3a267f222",
  "status": "approved",
  "policy_type": "vacation",
  "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
  "days": {
    "2026-05-26": "8.000",
    "2026-05-27": "8.000"
  },
  "employee_note": "Family vacation",
  "employer_note": "Approved — enjoy your vacation!",
  "employee": {
    "uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "full_name": "Alex Johnson"
  },
  "initiator": {
    "uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "full_name": "Alex Johnson"
  },
  "approver": {
    "uuid": "21d8dff4-ce09-4120-a274-3a5628bf6769",
    "full_name": "Morgan Chen"
  }
}
```

The `approver_uuid` field defaults to the company's primary payroll admin. Pass a specific `approver_uuid` to attribute the approval to a different admin. Must be a Gusto payroll admin UUID — retrieve valid values from [GET /v1/companies/\{company\_id}/admins](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-admins).

### Decline

Call [PUT /v1/time\_off/requests/\{time\_off\_request\_uuid}/decline](https://docs.gusto.com/embedded-payroll/reference/put-v1-time_off-requests-time_off_request_uuid-decline). Both `pending` and `approved` requests can be declined. An `employer_note` is required.

**Scope required:** `time_off_requests:manage`

**Request**

```json
PUT /v1/time_off/requests/ad158cfb-99e4-4741-9db3-0bd3a267f222/decline

{
  "employer_note": "Coverage needed this week — please resubmit for a different date."
}
```

**Response**

```json
{
  "uuid": "ad158cfb-99e4-4741-9db3-0bd3a267f222",
  "status": "declined",
  "policy_type": "vacation",
  "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
  "days": {
    "2026-05-26": "8.000",
    "2026-05-27": "8.000"
  },
  "employee_note": "Family vacation",
  "employer_note": "Coverage needed this week — please resubmit for a different date.",
  "employee": {
    "uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "full_name": "Alex Johnson"
  },
  "initiator": {
    "uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
    "full_name": "Alex Johnson"
  },
  "approver": null
}
```

<Callout icon="📘" theme="info">
  #### Admin approval flow

  Rather than calling the approve/decline endpoints directly, you can embed the `time_off_request_management` flow to give admins a full approval interface — including a pending request queue, balance summaries, and the ability to edit days on approval. Create the flow using [POST /v1/companies/\{company_uuid}/flows](https://docs.gusto.com/embedded-payroll/reference/post-v1-company-flows) with `flow_type: "time_off_request_management"`.
</Callout>

## Admin-initiated requests

Use [POST /v1/companies/\{company\_uuid}/time\_off/admin\_approved\_requests](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_uuid-time_off-admin_approved_requests) when an admin records time off on behalf of an employee — for example, logging a sick day after the fact, or syncing an approval from your own time off system. These requests are always created in `approved` status and immediately applied to payroll.

**Scope required:** `time_off_requests:manage`

**Request**

```json
POST /v1/companies/a4d13b1e-2f89-4c3b-a5d8-7e6c94f21a3d/time_off/admin_approved_requests

{
  "employee_uuid": "51924fa0-26c6-4d4c-8832-3ef0b422c67e",
  "policy_uuid": "c2d9b1bd-3f36-4c2d-a727-b2af057d6a7f",
  "start_date": "2026-04-14",
  "end_date": "2026-04-14",
  "days": {
    "2026-04-14": "8.000"
  },
  "employer_note": "Employee called in sick"
}
```

The response is an `Embedded-Time-Off-Request` object with `"status": "approved"` and `initiator` reflecting the admin rather than the employee.

<Callout icon="🚧" theme="warn">
  `employee_note` is not accepted on admin-initiated requests and will return a 422 if included. Similarly, `employer_note` is not accepted on employee-initiated requests (`POST /requests`).
</Callout>

## Canceling a request

Call [DELETE /v1/time\_off/requests/\{time\_off\_request\_uuid}](https://docs.gusto.com/embedded-payroll/reference/delete-v1-time_off-requests-time_off_request_uuid) to cancel a request. Returns `204 No Content` on success.

**Scope required:** `time_off_requests:write`

Both `pending` and `approved` requests can be canceled. `declined` and `consumed` requests cannot be deleted and will return a 422.

Canceling an `approved` request reverses its payroll impact if the associated pay period has not yet been processed.

## Listing and retrieving requests

### List requests

[GET /v1/companies/\{company\_uuid}/time\_off/requests](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_uuid-time_off-requests) — returns an array of `Embedded-Time-Off-Request` objects.

**Scope required:** `time_off_requests:read`

**Query parameters**

| Parameter        | Type    | Description                                                             |
| ---------------- | ------- | ----------------------------------------------------------------------- |
| `employee_uuids` | string  | Comma-separated employee UUIDs                                          |
| `status`         | string  | Comma-separated statuses: `pending`, `approved`, `declined`, `consumed` |
| `start_date`     | date    | Include requests that overlap with this start date                      |
| `end_date`       | date    | Include requests that overlap with this end date                        |
| `sort_order`     | string  | Sort by `start_date`: `asc` or `desc` (default: `desc`)                 |
| `page`           | integer | Page number                                                             |
| `per`            | integer | Results per page                                                        |

### Get a single request

[GET /v1/time\_off/requests/\{time\_off\_request\_uuid}](https://docs.gusto.com/embedded-payroll/reference/get-v1-time_off-requests-time_off_request_uuid) — returns a single `Embedded-Time-Off-Request` object.

**Scope required:** `time_off_requests:read`

Note that this endpoint is not company-scoped — the request UUID alone is sufficient.

## Error handling

<Accordion title="Common errors and how to handle them" icon="fa-triangle-exclamation">
  | Error                              | HTTP status | Description                                                                                                                                   | Resolution                                                                                                        |
  | ---------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
  | Overlapping request                | 422         | A request already exists for one or more of the same dates for this employee (checked against `pending`, `approved`, and `consumed` requests) | List existing requests for the employee and cancel or adjust the conflicting one before resubmitting              |
  | Missing dates in `days`            | 422         | Not all dates between `start_date` and `end_date` are present as keys in `days`                                                               | Provide an entry in `days` for every date in the range, including weekends                                        |
  | Hours out of range                 | 422         | A value in `days` is less than 0 or greater than 24                                                                                           | Correct the hours value for the flagged date                                                                      |
  | Negative balance                   | 422         | The request exceeds the employee's available hours and `allow_negative_balance` is `false` for this policy                                    | Reduce the requested hours, or verify the policy's negative balance setting                                       |
  | Employee not enrolled in policy    | 422         | The employee is not assigned to the specified time off policy                                                                                 | Assign the employee to the policy first — see [Manage time off policies](https://docs.gusto.com/embedded-payroll/docs/manage-time-off-policies)            |
  | Employee not eligible              | 422         | The employee is terminated, inactive, or has not completed onboarding                                                                         | Verify the employee's status before submitting a request                                                          |
  | Cannot delete request              | 422         | Attempted to delete a `declined` or `consumed` request                                                                                        | Only `pending` and `approved` requests can be deleted                                                             |
  | Cannot approve request             | 422         | Attempted to approve a request that is not in `pending` status (`approved`, `declined`, and `consumed` requests cannot be approved)           | Check the current request status before calling the approve endpoint                                              |
  | Cannot decline request             | 422         | Attempted to decline a `consumed` or `declined` request                                                                                       | Only `pending` and `approved` requests can be declined                                                            |
  | `employer_note` missing on decline | 422         | The decline endpoint requires an `employer_note`                                                                                              | Include a non-empty `employer_note` in the request body                                                           |
  | Invalid `approver_uuid`            | 422         | The UUID is not a payroll admin for this company                                                                                              | Retrieve valid admin UUIDs from [GET /v1/companies/\{company\_id}/admins](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-admins) |
</Accordion>

## Webhooks and notifications

Subscribe to [webhooks](https://docs.gusto.com/embedded-payroll/docs/webhooks) to track time off request lifecycle events without polling. The following events are available:

`time_off_request.created`, `time_off_request.updated`, `time_off_request.deleted`, `time_off_request.approved`, `time_off_request.declined`, `pending_time_off_requests`

The last two are employee- and admin-targeted notifications respectively; `pending_time_off_requests` is useful for prompting admins to open your approval UI or the `time_off_request_management` flow.

## FAQ

**Can an employee edit a submitted request?**

No. Requests cannot be modified after submission. The employee must cancel the existing request (via `DELETE`) and submit a new one.

**Can `approver_uuid` be an external user ID from my platform?**

No. The `approver_uuid` field on the approve and decline endpoints — and when generating the `time_off_request_management` flow — must be a Gusto payroll admin UUID for the company. Retrieve valid UUIDs from [GET /v1/companies/\{company\_id}/admins](https://docs.gusto.com/embedded-payroll/reference/get-v1-companies-company_id-admins).

**What happens to approved time off when payroll is processed?**

Approved time off is automatically reflected in payroll calculations. Once a request is `consumed` (applied to a completed payroll), it can no longer be modified or canceled. Canceling an `approved` request before payroll is processed reverses its impact.

**How do unlimited policies behave with balance checks?**

For unlimited policies, `balance_hours` in the balance endpoint is `null`, and the preview endpoint returns `"unlimited": true` with all hour fields as `null`. Negative balance validation is not applied.

***

## Quick reference

<Accordion title="All time off request endpoints" icon="fa-code">
  **Balances and preview**

  ```
  GET  /v1/companies/{company_uuid}/time_off/balances
  POST /v1/companies/{company_uuid}/time_off/requests/preview
  ```

  **Employee-initiated requests**

  ```
  GET    /v1/companies/{company_uuid}/time_off/requests
  POST   /v1/companies/{company_uuid}/time_off/requests
  GET    /v1/time_off/requests/{time_off_request_uuid}
  DELETE /v1/time_off/requests/{time_off_request_uuid}
  ```

  **Admin actions**

  ```
  POST /v1/companies/{company_uuid}/time_off/admin_approved_requests
  PUT  /v1/time_off/requests/{time_off_request_uuid}/approve
  PUT  /v1/time_off/requests/{time_off_request_uuid}/decline
  ```
</Accordion>

***

## Related guides

<Cards>
  <Card title="Time Off Policies" href="doc:time-off-policies" icon="fa-calendar-days">
    Create and configure accrual policies
  </Card>

  <Card title="Manage Time Off Policies" href="doc:manage-time-off-policies" icon="fa-users">
    Assign employees, update balances, and deactivate policies
  </Card>

  <Card title="Webhooks" href="doc:webhooks" icon="fa-bell">
    Subscribe to time off lifecycle events
  </Card>
</Cards>