---
updatedAt: 2026-06-17T07:33:37.000Z
---

Fetch the complete documentation index at: https://developer.connecteam.com/llms.txt. Use this file to discover all available pages before exploring further.

# Get Time Off Requests

Retrieve time-off requests for your company within a date range. Use this endpoint to sync approved leave into payroll systems, surface pending approvals in your HRIS, or audit denied requests — without workarounds through other APIs.

## Endpoint

| Method | Endpoint              | Description                               |
| :----- | :-------------------- | :---------------------------------------- |
| GET    | /time-off/v1/requests | Get a paginated list of time-off requests |

***

## Overview

Returns every time-off request whose date range **overlaps** the window you pass in `startDate` and `endDate` (both inclusive). For example, a request from June 10–12 is returned when you query June 1–30, and also when you query June 11–11 alone.

* Results are **paginated** with `limit` (1–100, default 10) and `offset`
* Filter by **employee** with `userIds`
* Filter by **status** with `statuses` (`approved`, `pending`, `denied`)
* When `statuses` is omitted, only **`approved`** requests are returned
* Approved requests include a `duration` field with the amount deducted from the employee's balance

> 👍 duration field for payroll
>
> **Approved requests include a `duration` object** (`units` + `amount`) reflecting exactly how much balance was deducted when the request was approved — in the policy's native unit (hours or days). This value is frozen at approval time, so it remains accurate even if the policy schedule changes later. It is **omitted** for `pending` and `denied` requests.

> 📘 Date range limits
>
> `startDate` and `endDate` are required. `endDate` must be on or after `startDate`. The range may not exceed **365 days**.

***

## Authentication

* **API Key** (`X-API-KEY` header), or
* **OAuth 2.0** with scope `time_off.read`

***

## Query Parameters

| Parameter | Type                | Required | Default        | Description                                                                                       |
| :-------- | :------------------ | :------- | :------------- | :------------------------------------------------------------------------------------------------ |
| startDate | string (YYYY-MM-DD) | Yes      | —              | Start of the date range, inclusive. Any request overlapping \[startDate, endDate] is returned.    |
| endDate   | string (YYYY-MM-DD) | Yes      | —              | End of the date range, inclusive. Must be on or after startDate. Range may not exceed 365 days.   |
| userIds   | array of integers   | No       | all users      | Filter by one or more employee IDs. Omit to include all employees.                                |
| statuses  | array of enum       | No       | `["approved"]` | Filter by status. Allowed: `approved`, `pending`, `denied`. Repeat the param for multiple values. |
| limit     | integer             | No       | 10             | Max results to return. Range 1–100.                                                               |
| offset    | integer             | No       | 0              | Number of results to skip for pagination. Min 0.                                                  |

***

## Example Request — Approved requests for a pay period

```bash
curl --request GET \
  --url 'https://api.connecteam.com/time-off/v1/requests?startDate=2026-06-01&endDate=2026-06-30&limit=25&offset=0' \
  --header 'X-API-KEY: YOUR_API_KEY'
```

## Example Request — Pending requests for specific employees

```bash
curl --request GET \
  --url 'https://api.connecteam.com/time-off/v1/requests?startDate=2026-06-01&endDate=2026-06-30&userIds=12345&userIds=67890&statuses=pending&statuses=approved' \
  --header 'X-API-KEY: YOUR_API_KEY'
```

***

## Response Structure

```json
{
  "requestId": "0b1c2d3e-4f56-7890-abcd-ef0123456789",
  "data": {
    "requests": [
      {
        "id": "665f1a2b3c4d5e6f7a8b9c0d",
        "userId": 12345,
        "policyTypeId": "63a1b2c3d4e5f60718293a4b",
        "status": "approved",
        "isAllDay": true,
        "startDate": "2026-06-10",
        "endDate": "2026-06-12",
        "startTime": "00:00:00",
        "endTime": "23:59:59",
        "timezone": "America/New_York",
        "duration": {
          "units": "hours",
          "amount": 22.0
        },
        "employeeNote": "Family trip",
        "managerNote": "Approved, enjoy!",
        "timeClockId": 4815162342
      },
      {
        "id": "665f1a2b3c4d5e6f7a8b9c0e",
        "userId": 67890,
        "policyTypeId": "63a1b2c3d4e5f60718293a4b",
        "status": "pending",
        "isAllDay": false,
        "startDate": "2026-06-15",
        "endDate": "2026-06-15",
        "startTime": "09:00:00",
        "endTime": "13:00:00",
        "timezone": "America/New_York",
        "employeeNote": "Doctor appointment",
        "managerNote": ""
      }
    ]
  },
  "paging": {
    "offset": 2,
    "total": 2
  }
}
```

`duration` is present only on `approved` requests (see the first item above). `timeClockId` is omitted when the request is not linked to a time clock (see the second item above).

***

## Response Fields

| Field                            | Type    | Description                                                                                                                                                  |
| :------------------------------- | :------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| requestId                        | string  | Unique identifier for this API request.                                                                                                                      |
| data.requests                    | array   | List of time-off requests matching the filters.                                                                                                              |
| data.requests\[].id              | string  | Unique identifier of the time-off request.                                                                                                                   |
| data.requests\[].userId          | integer | ID of the employee the request belongs to.                                                                                                                   |
| data.requests\[].policyTypeId    | string  | ID of the time-off policy type.                                                                                                                              |
| data.requests\[].status          | enum    | Request status: `approved`, `pending`, or `denied`.                                                                                                          |
| data.requests\[].isAllDay        | boolean | `true` if the request covers full days; `false` if it uses specific times.                                                                                   |
| data.requests\[].startDate       | string  | Start date of the time off (YYYY-MM-DD).                                                                                                                     |
| data.requests\[].endDate         | string  | End date of the time off (YYYY-MM-DD).                                                                                                                       |
| data.requests\[].startTime       | string  | Start time of the time off (HH:MM:SS).                                                                                                                       |
| data.requests\[].endTime         | string  | End time of the time off (HH:MM:SS).                                                                                                                         |
| data.requests\[].timezone        | string  | Timezone of the request, e.g. `America/New_York`.                                                                                                            |
| data.requests\[].duration        | object  | Amount deducted from the employee's balance when the request was approved. **Present only for `approved` requests; omitted otherwise.**                      |
| data.requests\[].duration.units  | enum    | Unit the amount is expressed in: `hours` or `days`, matching the policy type.                                                                                |
| data.requests\[].duration.amount | number  | Amount of time deducted. For all-day requests this reflects the policy work schedule per calendar day, not the start/end time span. Frozen at approval time. |
| data.requests\[].employeeNote    | string  | Note added by the employee. Empty string when none.                                                                                                          |
| data.requests\[].managerNote     | string  | Note added by the manager. Empty string when none.                                                                                                           |
| data.requests\[].timeClockId     | integer | ID of the time clock where the time off appears on the timesheet. Omitted when not linked.                                                                   |
| paging.offset                    | integer | Position after the last returned record; pass as `offset` to fetch the next page.                                                                            |
| paging.total                     | integer | Total number of requests matching the filters, ignoring pagination.                                                                                          |

***

## Pagination

Use `limit` and `offset` to walk through large result sets:

1. Call with `offset=0` and your chosen `limit`.
2. Read `paging.total` to know how many matching requests exist.
3. If more results remain, set `offset` to the `paging.offset` value from the previous response and call again.

```javascript
async function fetchAllApprovedTimeOff(startDate, endDate) {
  const all = [];
  let offset = 0;
  const limit = 100;

  while (true) {
    const params = new URLSearchParams({
      startDate,
      endDate,
      limit: String(limit),
      offset: String(offset),
    });

    const res = await fetch(
      `https://api.connecteam.com/time-off/v1/requests?${params}`,
      { headers: { 'X-API-KEY': 'YOUR_API_KEY' } }
    );
    if (!res.ok) throw new Error(await res.text());

    const body = await res.json();
    all.push(...body.data.requests);

    if (body.paging.offset >= body.paging.total) break;
    offset = body.paging.offset;
  }

  return all;
}
```

***

## Error Codes

| HTTP Status | Description                                                                                    |
| :---------- | :--------------------------------------------------------------------------------------------- |
| `400`       | `endDate` earlier than `startDate`, date range exceeds 365 days, or a `userId` does not exist. |
| `401`       | Missing or invalid authentication token.                                                       |
| `403`       | Token lacks the `time_off.read` scope, or the plan does not include the Time Off API.          |
| `429`       | Rate limit exceeded.                                                                           |

***

## Integration Example — Sync approved leave to payroll

```javascript
async function syncApprovedLeaveForPeriod(startDate, endDate) {
  const params = new URLSearchParams({
    startDate,
    endDate,
    statuses: 'approved',
    limit: '100',
    offset: '0',
  });

  const res = await fetch(
    `https://api.connecteam.com/time-off/v1/requests?${params}`,
    { headers: { 'X-API-KEY': 'YOUR_API_KEY' } }
  );
  if (!res.ok) throw new Error(await res.text());

  const { data, paging } = await res.json();

  for (const request of data.requests) {
    await pushToPayroll({
      employeeId: request.userId,
      startDate: request.startDate,
      endDate: request.endDate,
      isAllDay: request.isAllDay,
      startTime: request.startTime,
      endTime: request.endTime,
      policyTypeId: request.policyTypeId,
      // duration is present for all approved requests
      durationAmount: request.duration.amount,
      durationUnits: request.duration.units,
      note: request.employeeNote,
    });
  }

  return paging.total;
}
```

***

## Notes

> 📝 Important Considerations
>
> * **Overlap, not containment:** A request is returned if *any part* of its date range falls inside your query window — not only when it is fully contained.
> * **Default status filter:** Omitting `statuses` returns **approved** requests only. Pass `statuses=pending` (or repeat the param for multiple values) to include other statuses.
> * **`duration` is frozen at approval:** The amount and units reflect the policy schedule at the moment the request was approved. Policy schedule changes after approval do not affect the stored value.
> * **`duration` absent for non-approved:** `pending` and `denied` requests do not include `duration`. Check `status === "approved"` before reading it.
> * **Permissions:** Results respect the authenticated user's Time Off permissions. Users without broad visibility may see a subset of company requests.
> * **Related endpoints:** Use [Create and update time off requests](https://developer.connecteam.com/docs/time-off-requests) (POST/PUT) to write requests, and [Policy Types & Balances](https://developer.connecteam.com/docs/time-off-policies-balances) to manage balances.

***

[API Reference](https://developer.connecteam.com/reference/list_time_off_requests_time_off_v1_requests_get)