---
title: "Update time off request"
method: PUT
path: "/v2/time_off_requests/{time_off_request_id}"
tags: ["time_off_requests"]
---

# Update time off request

`PUT /v2/time_off_requests/{time_off_request_id}`

## Request

- Base URL: `https://api.hubstaff.com`
- URL: `https://api.hubstaff.com/v2/time_off_requests/{time_off_request_id}`
- Auth: OAuth 2
  - Authorization code: `https://account.hubstaff.com/authorizations/new`
  - Token URL: `https://account.hubstaff.com/access_tokens` scopes: `hubstaff:read`, `hubstaff:write`
- TypeScript: <https://skmtc.dev/hubstaff/apis/hubstaff-v2-api/docs/v2/time_off_requests/:time_off_request_id/put.ts> (a function with typed inputs; its response is checked against the schema)

Updates a time off request's details (dates, message, days, policy).

This is a full replacement — all fields must be provided, including time_off_request_days with one entry per date (amount_used in seconds, typically 28800 for an 8-hour day).

Approved, paid, or partially paid requests cannot be edited.

If the request was denied, updating it automatically resubmits it (status → submitted).

If the policy does not require approval, the request is auto-approved on update.

Set require_no_shift_overlap to true to reject the update if it overlaps with scheduled attendance shifts.

remove_shifts deletes overlapping attendance shifts only when the policy does not require approval (the request is auto-approved on update). When the policy requires approval, this field is ignored — use the status endpoint to remove shifts at approval time instead.

Note: starts_at and stops_at are interpreted as wall-clock times in the user's configured timezone (any timezone offset in the value is ignored). When all_day is true, the response covers the whole local day, 00:00:00.000–23:59:59.999 in the timezone saved with the request when it was created.

## Path parameters

- `time_off_request_id` integer, required

## Request body

- PutV2TimeOffRequestsTimeOffRequestId: Update time off request
  - `time_off_policy_id` integer, required: Time off policy ID
  - `starts_at` string, date-time, required: Start time (ISO 8601)
  - `stops_at` string, date-time, required: Stop time (ISO 8601)
  - `message` string, required: Reason for time off
  - `all_day` boolean: Full day request
  - `exclude_weekends` boolean
  - `exclude_holidays` boolean
  - `require_no_shift_overlap` boolean: Reject if overlapping shifts exist
  - `remove_shifts` boolean: Remove overlapping attendance shifts. Only honored when the policy does not require approval (auto-approved requests). For policies that require approval, use the status endpoint to remove shifts upon approval.
  - `time_off_request_days` object[], required: Day allocations
    - `date` string, date, required
    - `amount_used` integer, required: Seconds

## Response `200`

The updated time off request with its balance preview

- TimeOffRequestWithBalancePreview: TimeOffRequestWithBalancePreview model
  - `time_off_request` TimeOffRequest, required: TimeOffRequest model
    - `id` integer, required: Time edit log ID
    - `user_id` integer, required: User ID
    - `time_off_policy_id` integer, required: Time off request ID
    - `status` string, required: Status
    - `all_day` boolean, required: Time off request for all day (User's time zone)
    - `starts_at` string, date-time, required: Time off request start time
    - `stops_at` string, date-time, required: Time off request stop time
    - `submitted_at` string, date-time: Time off request submission time
    - `approved_at` string, date-time: Time off request approving time
    - `denied_at` string, date-time: Time off request denial time
    - `paid` boolean, required: If the time off request has been paid
    - `amount_used` integer, required: Time off request amount used
    - `message` string: message
    - `response` string: response
    - `created_by_id` integer, required: User ID from creator
    - `approved_by_id` integer: Approving User ID
    - `denied_by_id` integer: Denying User ID
    - `team_payment_detail_id` integer: Team payment detail ID
    - `team_payment_id` integer: Team payment ID
    - `time_off_request_days` TimeOffRequestDay[], required: Individual work days covered by this time off request
      - `date` string, date, required: Date of the time off day
      - `amount_used` integer, required: Amount of time used in seconds for this day
      - `starts_at` string, date-time, required: Start time for this specific day
      - `stops_at` string, date-time, required: Stop time for this specific day
      - `holiday` boolean, required: Whether this day is a holiday
      - `paid` boolean, required: Whether this day has been paid
    - `attachment_original_filename` string: Original filename of the attachment, present only with an attachment
    - `attachment_url` string, uri: Attachment download URL, expires in 2 hours, present only with an attachment
    - `created_at` string, date-time, required: When the record was created
    - `updated_at` string, date-time, required: When the record was last updated
  - `balance_preview` TimeOffBalancePreview, required
    - `starting_balance` TimeOffBalanceAmount, required
      - `current` integer, required: Value for the year the request starts in
      - `next` integer: Value for the next year, only for two-year requests
    - `pending_approval` TimeOffBalanceAmount, required
      - `current` integer, required: Value for the year the request starts in
      - `next` integer: Value for the next year, only for two-year requests
    - `amount_left` TimeOffBalanceAmount, required
      - `current` integer, required: Value for the year the request starts in
      - `next` integer: Value for the next year, only for two-year requests
    - `amount_used` TimeOffBalanceAmount, required
      - `current` integer, required: Value for the year the request starts in
      - `next` integer: Value for the next year, only for two-year requests
    - `holiday_hours` TimeOffBalanceAmount, required
      - `current` integer, required: Value for the year the request starts in
      - `next` integer: Value for the next year, only for two-year requests

## Other responses

- `400`: Invalid parameters
- `401`: Unauthorized
- `403`: API access is only for organizations on an active plan
- `404`: Could not find record
- `429`: Rate limit exceeded

---

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