GuidesAPI ReferenceChangelogAPI StatusAPI PolicyGusto Security
Guides

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.

πŸ“˜

Prerequisites

Employees must be assigned to a time off policy before requests can be submitted. See Manage time off policies to set up policies and enroll employees.

Integration patterns

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

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

Required scopes

ScopeRequired for
time_off_requests:readListing and retrieving requests; checking balances; previewing balance impact
time_off_requests:writeCreating and canceling employee-initiated requests
time_off_requests:manageApproving 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

StatusDescription
pendingSubmitted by an employee, awaiting admin review
approvedApproved by an admin; will be applied to the next payroll
declinedDeclined by an admin
consumedApplied 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.

Scope required: time_off_requests:read

Query parameters

ParameterTypeDescription
employee_uuidsstringComma-separated employee UUIDs to filter results
policy_uuidsstringComma-separated policy UUIDs to filter results
pageintegerPage number
perintegerResults per page

Response

[
  {
    "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.

Scope required: time_off_requests:read

Request

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 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

{
  "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 to submit the request. All requests created via this endpoint start in pending status.

Scope required: time_off_requests:write

Request

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

{
  "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:

"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. 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

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

{
  "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.

Decline

Call 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

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

{
  "employer_note": "Coverage needed this week β€” please resubmit for a different date."
}

Response

{
  "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
}
πŸ“˜

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 with flow_type: "time_off_request_management".

Admin-initiated requests

Use 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

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.

🚧

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).

Canceling a request

Call 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 β€” returns an array of Embedded-Time-Off-Request objects.

Scope required: time_off_requests:read

Query parameters

ParameterTypeDescription
employee_uuidsstringComma-separated employee UUIDs
statusstringComma-separated statuses: pending, approved, declined, consumed
start_datedateInclude requests that overlap with this start date
end_datedateInclude requests that overlap with this end date
sort_orderstringSort by start_date: asc or desc (default: desc)
pageintegerPage number
perintegerResults per page

Get a single request

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

Common errors and how to handle them
ErrorHTTP statusDescriptionResolution
Overlapping request422A 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 days422Not all dates between start_date and end_date are present as keys in daysProvide an entry in days for every date in the range, including weekends
Hours out of range422A value in days is less than 0 or greater than 24Correct the hours value for the flagged date
Negative balance422The request exceeds the employee's available hours and allow_negative_balance is false for this policyReduce the requested hours, or verify the policy's negative balance setting
Employee not enrolled in policy422The employee is not assigned to the specified time off policyAssign the employee to the policy first β€” see Manage time off policies
Employee not eligible422The employee is terminated, inactive, or has not completed onboardingVerify the employee's status before submitting a request
Cannot delete request422Attempted to delete a declined or consumed requestOnly pending and approved requests can be deleted
Cannot approve request422Attempted 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 request422Attempted to decline a consumed or declined requestOnly pending and approved requests can be declined
employer_note missing on decline422The decline endpoint requires an employer_noteInclude a non-empty employer_note in the request body
Invalid approver_uuid422The UUID is not a payroll admin for this companyRetrieve valid admin UUIDs from GET /v1/companies/{company_id}/admins

Webhooks and notifications

Subscribe to 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.

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

All time off request endpoints

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

Related guides