Endpoint Reference
Complete reference for all TempClock API v1 endpoints. All endpoints require Bearer token authentication and return JSON responses.
New in v1.2, backwards compatible
- New /payroll.php endpoint: approved, priced hours per worker per pay week. It pays exactly the shifts the Sage 50 Payroll export pays, with the same totals.
- Approval status and paid_minutes on /timesheets.php, from the same pricing engine as payroll.
- Scopes per resource (workers:read, payroll:read, shifts:write and so on). A call without its scope gets 403 insufficient_scope.
- Clock-outs in the repeated hour when the clocks go back keep the real time worked. A clock into a closed and locked pay week is recorded and flagged for payroll, never refused.
- Workers created or changed with a key are written to the audit log under that key, including pay and charge rate changes with before and after values.
The full, machine-readable reference is the OpenAPI 3.0.3 file. Where this page and the OpenAPI file differ, the OpenAPI file is right.
New in v1.1, backwards compatible
- GPS & geofence telemetry on /clock.php and /timesheets.php (latitude, longitude, gps_accuracy, within_geofence, distance_meters, low_gps_confidence).
- Pre-clock-in surveys on /clock.php: supply survey_id and survey_answers, or get a 403 blocked_by_survey.
- New /on-site-now.php endpoint, live snapshot of clocked-in workers grouped by site with geofence rollups.
- preferred_language on workers (en, pl, ro, lt); geofence_mode, kiosk_language and gps_accuracy_threshold on locations.
- entry_filter query param on /timesheets.php (shifts, active, breaks, all); default is shifts: matches previous behaviour.
- Four new webhook events: clock.blocked_by_survey, clock.geofence_breach, clock.geofence_refused, clock.low_gps_confidence: opt in per subscription.
Base URL
Endpoints
/workers.php
Retrieve a paginated list of workers, or a single worker by ID. Returns worker names, contact details, locations, and status.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | integer | No | Return a single worker by ID. Overrides other filters. |
| location_id | integer | No | Filter workers by their assigned location. |
| active | boolean | No | Filter by active status. Use 1 for active, 0 for inactive. |
| search | string | No | Search by first name, last name, or employee reference. |
| limit | integer | No | Number of results per page. Default: 50, max: 100. |
| offset | integer | No | Number of results to skip for pagination. Default: 0. |
Example Request, List Workers
Example Response
Example Request, Single Worker
Example Response
/timesheets.php
Retrieve a paginated list of time entries (clock-in/clock-out records). Filter by date range, worker, or location. Ideal for payroll integrations and reporting.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| date_from | string | No | Start date filter in YYYY-MM-DD format. |
| date_to | string | No | End date filter in YYYY-MM-DD format. |
| worker_id | integer | No | Filter entries for a specific worker. |
| location_id | integer | No | Filter entries by location. |
| entry_filter v1.1 |
string | No | One of shifts (default, completed clock-in/out shifts only), active (currently clocked-in entries within the last 14h), breaks (break entries only), or all (no filter). |
| limit | integer | No | Results per page. Default: 50, max: 100. |
| offset | integer | No | Number of results to skip. Default: 0. |
v1.1 response fields
Time entries now also include GPS / geofence telemetry when the clock-in supplied a location: within_geofence (0 / 1 / null when geofencing is off), distance_meters, gps_accuracy, and low_gps_confidence.Example Request
Example Response
/payroll.php
One line per worker per pay week, with paid hours and pay split into elements (regular, overtime, weekend, bank holiday, night). The lines hold exactly the shifts the Sage 50 Payroll export pays for the same pay week, priced by the same engine, so for each pay week the gross_pay of the lines adds up to the Sage file's total pay.
- Which shifts belong to your key: a shift belongs to the client that owns the site it was worked at, or to the worker's home client when it has no site. A pooled worker from another client who worked at your site is included; your worker who worked at another client's site is not.
- Which shifts are paid: completed, approved by the agency, not rejected by the client, not disputed, with no open query, approved by the client too when the client requires approval before payroll, and with a pay rate. A shift the client rejected is never paid here, even if the agency approved it.
- Not complete yet: meta.shifts_not_approved counts the completed shifts the approval gate leaves out. Above 0 means the period is not ready for payroll.
- Closed weeks: shifts in a closed and locked pay week return their frozen figures (source is locked). A shift clocked into a locked week and paid as an adjustment in a later week is left out of its own week, so it is never paid twice.
- Check before paying: flags on a line names shifts that passed approval but were not paid, for example no_pay_rate.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| week | string | No | Any date (YYYY-MM-DD) inside the pay week you want. |
| date_from | string | No | Start of a range (YYYY-MM-DD). Widened to the start of its pay week. Use with date_to, not with week. |
| date_to | string | No | End of a range. Widened to the end of its pay week. At most 26 pay weeks per request. With no week or range you get the last complete pay week. |
| worker_id | integer | No | Only this worker. |
| location_id | integer | No | Only shifts worked at this site. |
| include_entries | boolean | No | 1 lists the time entry ids behind each line in entry_ids. |
| limit | integer | No | Worker-week lines per page. Default: 50, max: 200. |
| offset | integer | No | Number of lines to skip. Default: 0. |
Example Request
Example Response
/locations.php
Retrieve a list of locations (work sites), or a single location by ID. Includes address, capacity, and active status.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | integer | No | Return a single location by ID. |
| active | boolean | No | Filter by active status. 1 for active, 0 for inactive. |
| limit | integer | No | Results per page. Default: 50, max: 100. |
| offset | integer | No | Number of results to skip. Default: 0. |
Example Request
Example Response
/clock.php
Clock a worker in or out. This creates a real time entry in the system, identical to a kiosk clock-in. Use with care in production environments.
Request Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
| worker_id | integer | Yes | The ID of the worker to clock in or out. |
| action | string | Yes | Either "in" or "out". |
| location_id | integer | No | Location to clock in at. Defaults to the worker's assigned location. |
| notes | string | No | Optional note attached to the time entry. |
| latitude v1.1 |
number | Conditional | GPS latitude (WGS84). Required when the location is configured with geofence_mode = strict. The response will include within_geofence and distance_meters when this is supplied. |
| longitude v1.1 |
number | Conditional | GPS longitude (WGS84). Paired with latitude. |
| gps_accuracy v1.1 |
integer | No | Horizontal accuracy of the GPS fix in metres. Compared against the location's gps_accuracy_threshold; fixes worse than the threshold set low_gps_confidence: true in the response. |
| survey_id v1.1 |
integer | Conditional | ID of the pre-clock-in survey being responded to. Required when the location has an active blocking survey, otherwise the call returns 403 blocked_by_survey. |
| survey_answers v1.1 |
array | Conditional | Array of answer objects: { question_id, answer_text?, answer_bool?, answer_choice? }. Required alongside survey_id. |
Example Request, Clock In
Example Response (201 Created)
Error Responses
409 Conflict - Returned if the worker is already clocked in and you attempt another clock-in, or if the worker has no open clock-in and you attempt a clock-out.
400 Bad Request - Returned if required fields are missing or the action value is not “in” or “out”.
404 Not Found - Returned if the worker_id does not exist or belongs to another client.
403 Forbidden, blocked_by_survey (new in v1.1) - The location has a blocking pre-clock-in survey that has not been satisfied. Submit a fresh survey_id + survey_answers in a follow-up request.
403 Forbidden, outside_geofence (new in v1.1) - The location has geofence_mode = strict and the supplied GPS coordinates were outside the radius.
/on-site-now.php
new in v1.1Live snapshot of currently-clocked-in workers, grouped by location, with GPS / geofence rollups. Mirrors the “Site occupancy” panel on the dashboard. A worker counts as live when clock_out IS NULL and clock_in is within the last 14 hours, forgotten clock-outs are excluded so the totals match reality.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| location_id | integer | No | Return only the slice for a single location. |
| include_workers | integer | No | Default 1. Set to 0 for an aggregate-only payload (no per-worker arrays). Use this for lightweight dashboards. |
Example Request
Example Response
Note: within_geofence is null for any location where geofencing has not been configured, those workers count towards on_site and are surfaced in the geofence_unknown tally so dashboards can distinguish “inside the fence” from “no fence”.
/shifts.php
List scheduled shifts or create new ones. GET retrieves existing shifts with filtering; POST creates a new shift assignment for a worker.
GET Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| date_from | string | No | Start date filter (YYYY-MM-DD). |
| date_to | string | No | End date filter (YYYY-MM-DD). |
| worker_id | integer | No | Filter shifts for a specific worker. |
| location_id | integer | No | Filter shifts by location. |
| limit | integer | No | Results per page. Default: 50, max: 100. |
| offset | integer | No | Number of results to skip. Default: 0. |
GET Example Request
GET Example Response
POST Request Body (JSON)
| Field | Type | Required | Description |
|---|---|---|---|
| worker_id | integer | Yes | The worker to assign the shift to. |
| shift_date | string | Yes | Date of the shift (YYYY-MM-DD). |
| start_time | string | Yes | Shift start time in HH:MM 24-hour format. |
| end_time | string | Yes | Shift end time in HH:MM 24-hour format. |
| location_id | integer | No | Location for the shift. Defaults to the worker's assigned location. |
| notes | string | No | Optional note for the shift. |
POST Example Request
POST Example Response (201 Created)
/departments.php
Retrieve a list of departments configured for your account. Useful for mapping workers to organisational units.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| active | boolean | No | Filter by active status. 1 for active, 0 for inactive. |
| limit | integer | No | Results per page. Default: 50, max: 100. |
| offset | integer | No | Number of results to skip. Default: 0. |
Example Request
Example Response
/cost-codes.php
Retrieve a list of cost codes used for project tracking and financial reporting. Cost codes allow you to allocate time entries to specific projects or budgets.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| active | boolean | No | Filter by active status. |
| limit | integer | No | Results per page. Default: 50, max: 100. |
| offset | integer | No | Number of results to skip. Default: 0. |
Example Request
Example Response
Changelog
API version history and notable changes.
- /payroll.php pays exactly the shifts the Sage 50 Payroll export pays: same approval gate (client-rejected, disputed and queried shifts left out), same site-client rule, same totals
- /clock.php: clock-outs in the repeated hour when the clocks go back keep the real time worked; clocks into a locked pay week are recorded and flagged for payroll
- /shifts.php: dormant (off-season) workers cannot be booked
- Workers created or changed with a key are written to the audit log under that key, including pay and charge rate changes with before and after values
- New /payroll.php endpoint
- Approval status and paid minutes on /timesheets.php
- Scopes per resource, read only or read and write
- GPS and geofencing on /clock.php, pre-clock-in surveys, /on-site-now.php, kiosk language, four new webhook events
- Initial public API release
- 7 endpoints: workers, timesheets, locations, clock, shifts, departments, cost-codes
- Bearer token authentication with scoped API keys
- Rate limiting at 60 requests/minute per key
- Paginated list responses with consistent format