---
title: How to Use the Timecloud Public API
description: The Timecloud Public API lets you connect external systems — payroll tools, HRIS platforms, scheduling engines, or custom dashboards — directly to your Timecloud data. Use it to automate employee management, roster scheduling, attendance tracking, and more.
---

[Skip to content](https://help.jointimecloud.com/how-to-use-the-timecloud-public-api#main-content)

[Contact us](https://help.jointimecloud.com/kb-tickets/new?hsLang=en)

[![Timecloud-Logo-600-2](https://help.jointimecloud.com/hs-fs/hubfs/Timecloud-Logo-600-2.png?width=200&height=40&name=Timecloud-Logo-600-2.png)](https://help.jointimecloud.com/?hsLang=en)

Open main navigation

Close main navigation

- [Contact us](https://help.jointimecloud.com/kb-tickets/new)
- [Go to app.jointimecloud.com](https://app.jointimecloud.com/)

[Go to app.jointimecloud.com](https://app.jointimecloud.com/)

 Got questions? Ask away

- There are no suggestions because the search field is empty.

1. [Service Portal](https://help.jointimecloud.com/?hsLang=en)
2. [Integrations](https://help.jointimecloud.com/integrations?hsLang=en)

# How to Use the Timecloud Public API

## The Timecloud Public API lets you connect external systems — payroll tools, HRIS platforms, scheduling engines, or custom dashboards — directly to your Timecloud data. Use it to automate employee management, roster scheduling, attendance tracking, and more.

### Getting Started

- **Company admins** can create and manage API keys directly from the Timecloud web app (see **Managing Your API Keys** below).
- You will need a **dedicated API user account** - a separate employee record created specifically for your integration. This account authenticates API requests and **cannot sign in to the web app, mobile app, or kiosk**. See **Setting Up a Dedicated API User** below.
- All API communication happens over HTTPS.

### Authentication

1. Call the **/oauth/token** endpoint with your API user's Client ID and Client Secret (provided by your Timecloud account manager).
2. You'll receive a Bearer token.
3. Include this token in the **Authorization** header of all subsequent requests:

`Authorization: Bearer <your-token>` 4. Include your API key in the **X-Timecloud-Integrator-Key** header:

`X-Timecloud-Integrator-Key: <your-api-key>`

### Managing Your API Keys

Company admins can create, view, and revoke API keys directly from the web app.

### Where to find it

- Go to **Settings** \> **API Integration**.

### Creating a key

1. Click **Create New Key**.
2. A dialog displays the new key. **Copy it immediately** - the key is shown only once and cannot be retrieved later.
3. Store the key securely (e.g. in a secrets manager or password vault).

### Viewing your keys

- The **API keys** table shows every key with its **Created** date and **Status** (Active or Revoked).

### Revoking a key

1. Click **Revoke** next to the key you want to disable.
2. Confirm in the dialog. **This cannot be undone** - any integration using the revoked key will stop working immediately.

**Tip:** You can have up to 100 active keys at a time. If you need a new key, revoke an unused one first.

### Setting Up a Dedicated API User

API authentication requires a dedicated employee account that exists solely for your integration. **This account cannot sign in to the Timecloud web app, mobile app, or kiosk** - it is restricted to API access only.

### Why a dedicated account?

- API user accounts are **blocked from all interactive sign-in** (web app, mobile app, kiosk). You cannot use a regular admin's credentials for both the web app and the API.
- Using a dedicated account keeps your integration's access separate from any individual person's login, which makes it easier to manage permissions and audit API activity.
- If someone leaves the company, your integration keeps working because it does not depend on a personal account.

### Recommended email format

Create the API user with a clearly identifiable, non-personal email address. For example:

- `api-user@yourdomain.com`
- `timecloud-api@yourdomain.com`
- `integrations@yourdomain.com`

Avoid using a real person's email. A shared or service-account email makes it clear the account is for system use and prevents disruption if a team member's email is deactivated.

### Step-by-step setup

1. Go to **Employees** and click **Add Employee**.
2. Enter the API user's details (e.g. first name "API", last name "User", email `api-user@yourdomain.com`).
3. After the employee record is created, open their profile.
4. Navigate to the **User Access** tab.
5. Enable **Admin Access** and set a password.
6. Toggle **API User** on.

**Important:** Once **API User** is enabled, the account is locked to API-only access. If someone attempts to sign in with this account via the web app, mobile app, or kiosk, they will see: *"This account type can't sign in here. Please contact Timecloud support if you need access."*

- This applies to password sign-in, PIN sign-in, and Microsoft sign-in.
- API user accounts are automatically exempt from two-step verification requirements.
- Turning off the **API User** toggle removes the integration's ability to authenticate as that employee. A confirmation dialog warns you before saving.

### Controlling access to API Integration settings

- **Company admins** have access by default.
- **Sub-admins** need the **API Integration Screen** permission enabled in **Feature Access** (under System Administration & Security).

### Date & Time Format

- **Request date fields:** `YYYY-MM-DD` (e.g. `2024-01-15`)
- **Response date-time fields:** ISO 8601 UTC (e.g. `2024-01-15T09:30:00.000Z`)
- All times are returned in UTC.

### Available Endpoints

Below is an overview of what you can manage through the API. Full endpoint details (request/response schemas, query parameters, and error codes) are available in the interactive Swagger documentation provided with your API credentials.

### Employees

 

 

| Action | Method & Path |
| --- | --- |
| List all employees | `GET /employees` |
| Get a single employee | `GET /employees/{employeeId}` |
| Create an employee | `POST /employees` |
| Update an employee | `PATCH /employees/{employeeId}` |
| Archive an employee | `PATCH /employees/{employeeId}` with `{"active": false}` |

 

 

 

**Field visibility:**

The employee response includes a wide range of fields - personal details, contact information, roles, departments, overtime settings, job defaults, and more. Some fields are conditionally visible based on the API user's permissions:

- **Financial fields** - `hourlyRate`, `chargeoutRate`, `dayRate`, and rate-related award engine data are returned as empty values unless the API user has **Financial Details** visibility enabled in **Feature Access**.
- **Sensitive fields** - any employee property your company has marked as **sensitive** in the employee profile template may be **omitted entirely** from the response. To receive these fields, ensure the API user has permission to view sensitive properties.
- **Departments** - employee responses include `decoratedUserGroups` (department names and IDs) alongside the existing `userGroups` ID array.
- **Award engine metadata** - when the Pay Interpretation Engine is enabled, employees include an `awardEngineMetadata` object with assigned award, employee type, and (if financially authorised) rate information.

**Contact & personal detail fields:**

Employee responses include the following contact and personal detail fields when populated on the employee profile:

- `dateOfBirth` - date of birth (ISO 8601 date-time).
- `mobile` - mobile phone number (plain string, e.g. `"021 123 4567"`).
- `address` - home address with `addressLine1`, `addressLine2`, `city`, `region`, `postCode`, and `country`.
- `postalAddress` - postal address (same structure as `address`).
- `emergencyContact` - primary emergency contact with `fullName`, `relationship`, `phoneNumber` (structured phone number object with `e164Number`, `internationalNumber`, `nationalNumber`, `number`, `countryCode`, and `dialCode`), `email`, and optionally an `address`.
- `emergencyContact2` - secondary emergency contact (same structure as `emergencyContact`).

These fields can be set when creating an employee (`POST`) and updated individually via `PATCH`. When updating composite fields (`address`, `postalAddress`, `emergencyContact`, `emergencyContact2`) via **PATCH**, send only the sub-fields you want to change - omitted sub-fields are left unchanged on the existing record.

**Tips:**

- Assign roles, departments, or default job items by passing arrays of IDs in `companyRoles`, `userGroups`, or `defaultJobItems`.
- When HR onboarding is enabled, `GET /employees` and `GET /employees/{employeeId}` include `curriculumVitae`, `coverLetter`, and `employeeDocuments` fields. See **Employee Recruitment Documents** below to upload and manage these.
- If a field you expect is missing from the response, check that the API user has the relevant permission - financial or sensitive property access - enabled in the Timecloud web app under **Feature Access**.

### Employee Recruitment Documents

Upload CVs, cover letters, and supporting documents to employee profiles via the API. Requires **HR onboarding** to be enabled for your company.

**Document types:**

- `curriculumVitae` - single file (replaces any existing CV)
- `coverLetter` - single file (replaces any existing cover letter)
- `employeeDocuments` - up to 10 files per employee

#### Upload workflow (two steps)

1. **Request an upload URL** - call `POST /employees/{employeeId}/recruitment-documents/upload-requests` with a JSON body containing `property` (one of the document types above) and `filename` (including extension, e.g. `jane-doe-cv.pdf`). The response includes a temporary `uploadUrl` and an `uploadRequestId`.
2. **Upload the file** - send the file contents as a `PUT` request directly to the `uploadUrl`. This is a direct-to-storage upload (no Timecloud auth needed for this step).
3. **Confirm the upload** - call `POST /employees/{employeeId}/recruitment-documents/upload-requests/{uploadRequestId}/confirm`. Timecloud validates the file (type, size, malware scan) and links it to the employee. The response includes the `attachmentId` and the updated property value.

 

 

| Action | Method & Path |
| --- | --- |
| Request an upload URL | `POST /employees/{employeeId}/recruitment-documents/upload-requests` |
| Confirm an upload | `POST /employees/{employeeId}/recruitment-documents/upload-requests/{uploadRequestId}/confirm` |
| Clear the CV | `DELETE /employees/{employeeId}/recruitment-documents/curriculumVitae` |
| Clear the cover letter | `DELETE /employees/{employeeId}/recruitment-documents/coverLetter` |
| Remove one employee document | `DELETE /employees/{employeeId}/recruitment-documents/employeeDocuments/{attachmentId}` |

 

 

 

**Good to know:**

- Maximum file size is **25 MB**.
- Allowed file types follow the same allowlist as document uploads in the Timecloud web app (PDF, Word, images, etc.).
- Upload URLs expire after **5 minutes**. The upload request token expires after **20 minutes**.
- For `curriculumVitae` and `coverLetter`, uploading a new file automatically replaces the previous one.
- For `employeeDocuments`, the maximum is **10 files** per employee. Use the `DELETE` endpoint to remove individual documents.
- These endpoints are **rate limited**. The response headers (`X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`) indicate your current usage.

### Company Roles

 

 

| Action | Method & Path |
| --- | --- |
| List roles | `GET /company-roles` |
| Create a role | `POST /company-roles` |
| Update a role | `PATCH /company-roles/{roleId}` |
| Delete a role | `DELETE /company-roles/{roleId}` |

 

 

 

**Note:** You cannot delete a role while active employees are still assigned to it. Unassign employees first.

### Departments (User Groups)

 

 

| Action | Method & Path |
| --- | --- |
| List departments | `GET /company/groups` |
| Create a department | `POST /company/groups` |
| Update a department | `PATCH /company/groups/{groupId}` |
| Delete a department | `DELETE /company/groups/{groupId}` |
| List employees in a department | `GET /company/groups/{groupId}/users` |

 

 

 

**Notes:**

- Departments can be nested. Pass `parentGroupId` when creating to nest under a parent.
- Deleting a department also removes its sub-departments. Employees are automatically unassigned.
- Deletion is blocked if active job items reference the department.

### Roster - Employee View

 

 

| Action | Method & Path |
| --- | --- |
| Get roster assignments | `GET /rosters/employee` |
| Create or update shifts | `POST /rosters/employee` |
| Publish draft shifts | `POST /rosters/employee/publish` |
| Clear draft shifts | `POST /rosters/employee/clear` |
| Delete a shift assignment | `DELETE /rosters/employee/shifts/{shiftId}/{employeeId}` |
| Batch delete shift assignments | `POST /rosters/employee/shifts/delete` |

 

 

 

**Tips:**

- Set `isPublished: true` on a shift to publish it immediately. Otherwise, it stays as a draft until you call **/publish**.
- Use `conflictAuthorised: true` to bypass overlap checks when you know a double-booking is intentional.
- Filter publish/clear actions by `employeeIds` or `userGroupIds` query parameters.

### Roster - Shift View

 

 

| Action | Method & Path |
| --- | --- |
| Get shift roster grid | `GET /rosters/shift` |
| Create or update shifts | `POST /rosters/shift` |
| Publish draft shifts | `POST /rosters/shift/publish` |
| Clear draft shifts | `POST /rosters/shift/clear` |
| Delete a shift | `DELETE /rosters/shift/{shiftId}` |
| List invitations | `GET /rosters/shift/invitations` |
| Send invitations | `POST /rosters/shift/invitations` |
| Update draft invitations | `PATCH /rosters/shift/invitations` |

 

 

 

**Tips:**

- After creating shifts, the response includes `shiftMappings` so you can map your payload to the created shift IDs.
- Send invitations with `draft=true` to save without notifying employees.

### Attendance & Checkin Pairs

 

 

| Action | Method & Path |
| --- | --- |
| List attendance days | `GET /attendances` |
| Create or update a checkin pair | `POST /attendances/{attendanceId}/checkin-pairs` |
| Delete checkins | `POST /attendances/checkins/delete` |

 

 

 

**Notes:**

- Checkin pairs use **upsert via POST**: include the checkin `_id` to update an existing checkin, or omit it to create a new one.
- Writes and deletes are **blocked** when the attendance day has been manager-approved (signed off).
- Each response returns the fully recalculated attendance record, so you always have up-to-date totals.

### Job Items

 

 

| Action | Method & Path |
| --- | --- |
| List job items | `GET /job-items` |
| Search job items | `GET /job-items/search` |
| Create a job item | `POST /job-items` |
| Update a job item | `PATCH /job-items/{jobItemId}` |
| Deactivate a job item | `PATCH /job-items/{jobItemId}` with `{"isActive": false}` |

 

 

 

### Competencies

Manage competency groups, templates, and employee records via the API. In the Timecloud web app these appear under **Competencies**; the API paths use `/compliance` and `/compliance-groups`.

#### Competency Groups

 

 

| Action | Method & Path |
| --- | --- |
| List all groups | `GET /compliance-groups` |
| Get a group by ID | `GET /compliance-groups/{groupId}` |
| Create a group | `POST /compliance-groups` |
| Update a group | `PATCH /compliance-groups/{groupId}` |
| Delete a group | `DELETE /compliance-groups/{groupId}` |

 

 

 

#### Competency Templates & Employee Items

 

 

| Action | Method & Path |
| --- | --- |
| List all (templates or items) | `GET /compliance` |
| Get by ID | `GET /compliance/{id}` |
| Create a template or item | `POST /compliance` |
| Update a template or item | `PATCH /compliance/{id}` |
| Delete a template or item | `DELETE /compliance/{id}` |
| Bulk assign from a template | `POST /compliance/bulk` |

 

 

 

**Tips:**

- Use `?isTemplate=true` to list or create **templates** (the reusable definitions). Use `?isTemplate=false` for **employee items** (actual records assigned to a person).
- Filtering is available by `groupId`, `employeeId`, `templateId`, `expiryDate`, `issueDate`, and `alerts`.
- Results are paginated - use `page` and `limit` query parameters.

**Bulk assign:**

- `POST /compliance/bulk` lets you create up to **100 employee records** in a single request.
- Provide `templateId`, `groupId`, and a `rows` array. Each row requires an `employeeId` and can optionally include `issueDate`, `expiryDate`, `alertsEnabled`, and `customProperties`.
- The response reports each row's outcome (`created` or `failed`) with a message.

#### Employee Competency Dashboard

 

 

| Action | Method & Path |
| --- | --- |
| Get employee competency view | `GET /compliance/employees` |
| Get totals only | `GET /compliance/employees/totals` |
| Get status for all items | `POST /compliance/status/query` |
| Get status for one item | `GET /compliance/{complianceId}/status` |

 

 

 

**Notes:**

- `/compliance/employees` returns a flattened list of employee competency records with calculated statuses (`valid`, `warning`, `expired`, `draft`), days remaining, and employee details.
- `/compliance/employees/totals` returns only the summary counts - more efficient when you just need an overview.
- Filter by `status`, `groupId`, `employeeId`, `userGroupId`, `expiryDate`, `daysRemaining`, or use `search` with `searchFields`.
- Sort with `sortBy` and `sortDirection` query parameters.

**Custom properties:**

- Competency records support custom properties (e.g. certificate numbers, notes).
- **File-type properties are read-only** via the API. Use the Timecloud web app to upload documents.

### Company & Shift Templates

 

 

| Action | Method & Path |
| --- | --- |
| Get company details | `GET /company` |
| List shift templates | `GET /shift-templates` |

 

 

 

### Payroll Report

 

 

| Action | Method & Path |
| --- | --- |
| Generate a custom payroll report | `POST /payroll/providers/{payrollProviderId}/report-builder/generate` |

 

 

 

**How it works:**

- Provide a date range (`start-date`, `end-date`), optional employee IDs, and optional department filters.
- Results are **paginated by employee**. Use the optional `page` and `pageSize` fields to control which slice of employees is returned.
- The response returns **data** (report rows), **errors** (employees that could not be calculated), and **pagination metadata** (`total`, `page`, `pageSize`, `totalPages`).
- Successfully processed employees appear in **data**. Employees that encountered a processing issue are omitted from **data** and reported in **errors** instead.

**Pagination:**

- **page** - The page number to retrieve (default: `1`).
- **pageSize** - Number of employees per page (default: `50`, maximum: `50`).
- Employees are returned in a consistent order. To retrieve all employees, increment `page` until `page` exceeds `totalPages`.
- If `page` is beyond the last page of results, **data** returns an empty array with no error.

**Response structure:**

- **data** - A two-dimensional array of strings. When data rows exist, the first row contains column headers; subsequent rows contain the timesheet data for each successfully processed employee. When the requested page has no matching data, **data** is an empty array.
- **errors** - An array of objects, each describing an employee whose timesheet could not be generated. Each error includes: 
    - **employeeId** - The ID of the affected employee.
    - **employeeName** - The employee's full name.
    - **date** - The date (in your company timezone, `YYYY-MM-DD`) of the shift that caused the issue, or `null` if not shift-specific.
    - **message** - A human-readable description of what went wrong.
- **total** - Total number of employees matching your filters.
- **page** - The current page number.
- **pageSize** - The number of employees per page.
- **totalPages** - The total number of pages available.

**Tips:**

- Always check the **errors** array after receiving a response. An empty **errors** array means all employees on that page were processed successfully.
- If an employee appears in **errors**, their timesheet lines are excluded from **data**. Review the error message and correct the underlying issue before re-generating.
- The maximum date range is governed by your company's pay period.
- To fetch a complete report for all employees, loop through pages starting at `page=1` and increment until `page` exceeds `totalPages`.

### Common Integration Patterns

- **Sync employees from your HRIS:** Use `GET /employees` to compare, then `POST` to create or `PATCH` to update.
- **Build a roster:** List shift templates, then `POST /rosters/employee` or `POST /rosters/shift` to assign shifts. Call **/publish** when ready.
- **Push timesheet data:** Use `POST /attendances/{id}/checkin-pairs` to write clock-in/out records from an external system.
- **Archive leavers:** `PATCH /employees/{id}` with `{"active": false}`.
- **Set up your org structure:** Create departments via `POST /company/groups` (nest with `parentGroupId`), then assign employees.
- **Sync contact details:** Use `PATCH /employees/{id}` to push addresses, emergency contacts, date of birth, and mobile numbers from your HRIS. Send only the sub-fields that changed - the API merges them with existing data.
- **Generate payroll reports:** Call `POST /payroll/providers/{payrollProviderId}/report-builder/generate` with your date range. Use `page` and `pageSize` to paginate through employees. Process the **data** rows from each page and handle any entries in **errors** for employees that could not be calculated.
- **Manage competencies:** Create groups via `POST /compliance-groups`, add templates with `POST /compliance` (`isTemplate: true`), then bulk-assign to employees with `POST /compliance/bulk`. Monitor expiry via `GET /compliance/employees/totals`.
- **Upload recruitment documents:** Request an upload URL via `POST /employees/{employeeId}/recruitment-documents/upload-requests`, upload the file to the returned URL with a `PUT`, then confirm via `POST .../upload-requests/{uploadRequestId}/confirm`. Use `DELETE` endpoints to clear or remove documents.
- **Rotate API keys:** Create a new key in **Settings** \> **API Integration**, update your integration to use the new key, then revoke the old one.

### Error Handling

- **400** - Bad request (missing or invalid fields). Check the response body for details.
- **401** - Unauthorised. Your token may have expired - request a new one.
- **403** - Forbidden. The API user may not have the required permissions, or the API User toggle may be off.
- **404** - Resource not found. Verify the ID exists.
- **409** - Conflict (e.g. overlapping roster shifts or concurrent document update). Use `conflictAuthorised: true` to override where appropriate, or retry with a fresh upload request for documents.
- **422** - Unprocessable (e.g. writing to a manager-approved attendance day).
- **429** - Rate limit exceeded. Wait and retry. Check `X-RateLimit-Reset` header for when your limit resets.

### Need Help?

Reach out to your Timecloud account manager or contact [support@jointimecloud.com](mailto:support@jointimecloud.com) for API access, troubleshooting, or integration guidance.

- [Account & Security](https://help.jointimecloud.com/account-security?hsLang=en)
- [Attendance & Timesheets](https://help.jointimecloud.com/attendance-timesheets?hsLang=en)
- [Award Interpretation](https://help.jointimecloud.com/award-interpretation?hsLang=en)
- [Biometric Scanners](https://help.jointimecloud.com/biometric-scanners?hsLang=en)
- [Employees](https://help.jointimecloud.com/employees?hsLang=en)
- [Forms & Checklists](https://help.jointimecloud.com/forms-checklists?hsLang=en)
- [Geofencing](https://help.jointimecloud.com/geofencing?hsLang=en)
- [Human Resources](https://help.jointimecloud.com/human-resources?hsLang=en#main-content)

    - [Organisation View](https://help.jointimecloud.com/human-resources?hsLang=en#organisation-view)
- [Integrations](https://help.jointimecloud.com/integrations?hsLang=en)
- [Job Tracking](https://help.jointimecloud.com/job-tracking?hsLang=en)
- [Leave Management](https://help.jointimecloud.com/leave-management?hsLang=en)
- [Mobile App](https://help.jointimecloud.com/mobile-app?hsLang=en#main-content)

    - [Kiosk](https://help.jointimecloud.com/mobile-app?hsLang=en#kiosk)
    - [Mobile App](https://help.jointimecloud.com/mobile-app?hsLang=en#mobile-app)
- [Payroll](https://help.jointimecloud.com/payroll?hsLang=en#main-content)

    - [Xero](https://help.jointimecloud.com/payroll?hsLang=en#xero)
    - [iPayroll](https://help.jointimecloud.com/payroll?hsLang=en#ipayroll)
    - [MYOB](https://help.jointimecloud.com/payroll?hsLang=en#myob)
    - [Smartly](https://help.jointimecloud.com/payroll?hsLang=en#smartly)
- [Reporting](https://help.jointimecloud.com/reporting?hsLang=en)
- [Roster](https://help.jointimecloud.com/roster?hsLang=en)
- [Settings](https://help.jointimecloud.com/settings?hsLang=en)
- [Shifts](https://help.jointimecloud.com/shifts?hsLang=en)
- [Time Clock](https://help.jointimecloud.com/time-clock?hsLang=en)
- [Dashboard](https://help.jointimecloud.com/dashboard?hsLang=en)

Service Desk

Copyright © 2025, Timecloud Ltd