Working Hours Policies
List shared working hours policies, read an employee's expected week, assign users to a policy, and set or remove custom hours.
A working hours policy is the expected week: which days are work days, the allowed time windows, the expected daily duration, and the timezone those windows are evaluated in. Create and edit shared policy contents in the Connecteam dashboard; this API is the read, assign, and custom-hours surface. Integrators and the Connecteam agent use the same endpoints. The agent relies on them to help admins set expected hours during setup.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /company-policies/v1/working-hours-policies | List shared policies, including disabled ones |
| GET | /company-policies/v1/users/{userId}/working-hours | Get one employee's working hours |
| PUT | /company-policies/v1/users/{userId}/working-hours | Create or replace custom hours for one employee |
| DELETE | /company-policies/v1/users/{userId}/working-hours | Remove custom hours. A shared assignment is kept |
| PUT | /company-policies/v1/working-hours-policies/{workingHoursPolicyId}/assignments | Assign one or more employees to a shared policy |
| DELETE | /company-policies/v1/working-hours-policies/{workingHoursPolicyId}/assignments/{userId} | Unassign an employee from a shared policy |
Overview
- A shared policy is a named weekly schedule. List these with the collection GET. Per-user custom hours are not included there.
- A user has at most one working hours configuration at a time: a shared policy or custom hours on their profile.
- Assigning a shared policy replaces that user's custom hours. Setting custom hours replaces a shared assignment.
- Deleting custom hours keeps a shared assignment. Unassigning from a shared policy keeps custom hours.
- Assignments take effect immediately. There is no
effectiveDate(unlike pay rule policies). - Disabled policies (
isEnabled: false) appear in the company list but are never enforced. You cannot assign employees to a disabled policy. isDefaultForNewUsersis returned for completeness. Working hours policies are not automatically assigned to new users.- Create and edit shared policy contents in the dashboard. Creating, updating, and deleting shared policies are not part of this public surface.
- The Connecteam agent uses these endpoints to help admins set expected hours during account and employee setup.
Good to knowA user has one working hours configuration. Use the user GET to see whether it is a shared policy (
isCustomPolicy: false), custom hours (isCustomPolicy: true), or nothing (emptydata).
Did you know?Each day can have more than one time window. Iterate
timeRanges. Do not read only the first range. Overnight work is two days: the first ends at86400and the next starts at0.
Authentication
- API Key (
X-API-KEYheader), or - OAuth 2.0
| Scope | Operations |
|---|---|
company_policies.read | GET company policies, GET user working hours |
company_policies.write | PUT custom hours, PUT assignments |
company_policies.delete | DELETE custom hours, DELETE assignment |
These endpoints require the Schedule API plan limitation (schedulerApi) and Regular Working Hours to be enabled on the account.
Regular Working Hours must be onOtherwise every call returns
403. Enable the feature on the account before integrating.
Admin permissionsFor non-owner admins, writing or deleting hours also requires permission to add and edit users.
workSchedule
Used the same way on every request and response. All seven days are required.
Times are seconds from local midnight (0–86400) and must land on a whole minute. 0 is the start of the day. 86400 is the end of the day. A single range never wraps past midnight.
| Field | Type | Required | Description |
|---|---|---|---|
timezone | string | No | IANA timezone. Defaults to the account timezone when omitted |
workSchedule.{day}.isWorkDay | boolean | Yes | Whether the day is a work day |
workSchedule.{day}.timeRanges | array | Yes | Allowed windows. Empty means a work day with no window restriction |
workSchedule.{day}.timeRanges[].startTimeSecs | integer | Yes | Window start, seconds from local midnight |
workSchedule.{day}.timeRanges[].endTimeSecs | integer | Yes | Window end. Must be greater than startTimeSecs |
workSchedule.{day}.standardWorkHoursSecs | integer | No | Expected daily duration in seconds (60–86400). Must not exceed the combined duration of that day's ranges. Omitted when unset |
Optional fields with no value are omitted from responses rather than returned as null.
Night shifts
A shift that continues past midnight is two days, not one wrapping range:
{
"monday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 64800, "endTimeSecs": 86400 }], "standardWorkHoursSecs": 21600 },
"tuesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 0, "endTimeSecs": 10800 }], "standardWorkHoursSecs": 10800 }
}Get working hours policies
Retrieves all shared working hours policies in the account, including disabled ones. Custom per-user hours are not included. Use the returned id when assigning employees.
Example Request
curl --request GET \
--url https://api.connecteam.com/company-policies/v1/working-hours-policies \
--header 'X-API-KEY: YOUR_API_KEY'Response
{
"requestId": "b3f1c2d4-5e6a-4b7c-8d9e-0f1a2b3c4d5e",
"data": {
"workingHoursPolicies": [
{
"id": 84213,
"name": "Full-time office",
"isEnabled": true,
"isDefaultForNewUsers": false,
"timezone": "America/New_York",
"workSchedule": {
"sunday": { "isWorkDay": false, "timeRanges": [] },
"monday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 32400, "endTimeSecs": 61200 }], "standardWorkHoursSecs": 28800 },
"tuesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 32400, "endTimeSecs": 61200 }], "standardWorkHoursSecs": 28800 },
"wednesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 32400, "endTimeSecs": 61200 }], "standardWorkHoursSecs": 28800 },
"thursday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 32400, "endTimeSecs": 61200 }], "standardWorkHoursSecs": 28800 },
"friday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 32400, "endTimeSecs": 50400 }], "standardWorkHoursSecs": 18000 },
"saturday": { "isWorkDay": false, "timeRanges": [] }
}
}
]
}
}Get user working hours
Returns the working hours currently governing one employee. There are three outcomes:
- Custom hours (
isCustomPolicy: true).workingHoursPolicyIdandnameare absent. - Shared policy (
isCustomPolicy: false).workingHoursPolicyIdandnameare present. - No working hours.
200with emptydata.404is only when the user does not exist.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
userId | integer | Yes | The unique identifier of the user |
Example Request
curl --request GET \
--url https://api.connecteam.com/company-policies/v1/users/3067712/working-hours \
--header 'X-API-KEY: YOUR_API_KEY'Response — custom hours
{
"requestId": "b9d7c8e0-1f2a-4b3c-4d5e-6f7a8b9c0d1e",
"data": {
"userId": 3067712,
"isCustomPolicy": true,
"timezone": "Europe/Berlin",
"workSchedule": {
"sunday": { "isWorkDay": false, "timeRanges": [] },
"monday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"tuesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"wednesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"thursday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"friday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 46800 }], "standardWorkHoursSecs": 21600 },
"saturday": { "isWorkDay": false, "timeRanges": [] }
}
}
}Response — no working hours
{
"requestId": "d1f9e0a2-3b4c-4d5e-6f7a-8b9c0d1e2f3a",
"data": {}
}Set user custom working hours
Creates or replaces custom hours for this user only. This path never assigns a shared policy. If the user was on a shared policy, that assignment is replaced.
Replaces a shared assignmentA user can have one working hours configuration. Setting custom hours takes them off the shared policy.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
workSchedule | object | Yes | Custom weekly schedule. See workSchedule |
timezone | string | No | IANA timezone. Defaults to the account timezone |
Example Request
curl --request PUT \
--url https://api.connecteam.com/company-policies/v1/users/3067712/working-hours \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: YOUR_API_KEY' \
--data '{
"timezone": "Europe/Berlin",
"workSchedule": {
"sunday": { "isWorkDay": false, "timeRanges": [] },
"monday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"tuesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"wednesday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"thursday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 54000 }], "standardWorkHoursSecs": 28800 },
"friday": { "isWorkDay": true, "timeRanges": [{ "startTimeSecs": 25200, "endTimeSecs": 46800 }], "standardWorkHoursSecs": 21600 },
"saturday": { "isWorkDay": false, "timeRanges": [] }
}
}'The 200 response matches the custom-hours shape of the user GET.
Delete user custom working hours
Removes this user's custom hours. A shared policy assignment is not affected. After a successful delete, the user GET returns empty data unless a shared assignment remains.
curl --request DELETE \
--url https://api.connecteam.com/company-policies/v1/users/3067712/working-hours \
--header 'X-API-KEY: YOUR_API_KEY'Assign users to a working hours policy
Assigns one or more employees to the shared policy. Pass them in userIds (1–100). Assignments take effect immediately. Custom hours for those people are replaced. Assigning a user who is already on this policy, with no custom hours, leaves the existing assignment in place.
The call is all or nothing: if any user ID does not exist, nothing is assigned.
Replaces custom hoursAssigning a shared policy drops that user's custom hours. Unassign later does not restore them.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
workingHoursPolicyId | integer | Yes | The unique identifier of the shared policy |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
userIds | array of integers | Yes | 1–100 unique user IDs |
Example Request
curl --request PUT \
--url https://api.connecteam.com/company-policies/v1/working-hours-policies/84213/assignments \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: YOUR_API_KEY' \
--data '{
"userIds": [3067712, 3067713, 3067714]
}'Response
{
"requestId": "f3b1a2c4-5d6e-4f7a-8b9c-0d1e2f3a4b5c",
"data": {
"assignments": [
{ "assignmentId": 90233, "userId": 3067712 },
{ "assignmentId": 90234, "userId": 3067713 },
{ "assignmentId": 90235, "userId": 3067714 }
]
}
}Unassign user from a working hours policy
Removes this employee's assignment to the shared policy. Custom hours are not affected. Returns 404 if the user is not assigned to this policy.
curl --request DELETE \
--url https://api.connecteam.com/company-policies/v1/working-hours-policies/84213/assignments/3067712 \
--header 'X-API-KEY: YOUR_API_KEY'{
"requestId": "a4c2b3d5-6e7f-4a8b-9c0d-1e2f3a4b5c6d",
"data": { "success": true }
}Error Codes
| HTTP Status | Description |
|---|---|
400 | Invalid workSchedule, empty or duplicate userIds, more than 100 IDs, or an attempt to assign users to a disabled policy |
401 | Missing or invalid authentication |
403 | Missing company_policies scope, missing admin permission, the plan does not include the Schedule API, or Regular Working Hours is not enabled |
404 | User or policy not found, or (unassign) the user is not assigned to this policy |
429 | Rate limit exceeded |
The user GET returns 200 with empty data when no working hours are set.
Integration Example — Assign new hires, or let the agent do it
async function assignUsersToWorkingHoursPolicy(policyId, userIds) {
const res = await fetch(
`https://api.connecteam.com/company-policies/v1/working-hours-policies/${policyId}/assignments`,
{
method: 'PUT',
headers: {
'X-API-KEY': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ userIds })
}
);
if (!res.ok) {
throw new Error(`Assign failed: ${JSON.stringify(await res.json())}`);
}
return (await res.json()).data.assignments;
}
const policiesRes = await fetch(
'https://api.connecteam.com/company-policies/v1/working-hours-policies',
{ headers: { 'X-API-KEY': 'YOUR_API_KEY' } }
);
const policies = (await policiesRes.json()).data.workingHoursPolicies;
const fullTime = policies.find((p) => p.name === 'Full-time office');
await assignUsersToWorkingHoursPolicy(fullTime.id, [3067712, 3067713]);The Connecteam agent follows the same flow during setup: list policies, pick the matching one, and assign the new people.
Notes
Important Considerations
- Create and edit the contents of a shared policy in the Connecteam dashboard. This API lists those policies and manages who they apply to, plus per-user custom hours.
- A user can be governed by one working hours configuration at a time. Assigning a shared policy replaces custom hours, and setting custom hours replaces a shared assignment.
- Iterate
timeRanges. Do not treat the first range as the whole day.- Overnight windows are two days (
86400then0), not one wrapping range.- Regular Working Hours must be enabled on the account. Otherwise the API returns
403.- Pay rule assignments are a different family, with effective dates. See Pay Rule Policies.
- Scheduling rule policies are a different family. See Scheduling Rule Policies.
Updated about 11 hours ago
