Timeclock
Read who is on the clock and how many hours your team logged
Overview
A timeclock entry is opened when a team member clocks in from the mobile app and closed when they clock out. An open entry has a inTimestamp and a null outTimestamp; closing it fills in the clock-out fields and hoursWorked. Both clock-in and clock-out capture the device location when the user has granted it.
Entries are read-only through the API and cover the whole organization. Every query below requires the read:timeclock scope.
List Timeclock Entries
Retrieve a cursor-based paginated list of entries using infiniteClockings. Filtering is passed via the selector argument; entries come back oldest-first by id unless you pass sort.
query InfiniteClockings(
$selector: ClockingsSelector
$sort: [ClockingSort!]
$first: Int
$after: String
) {
infiniteClockings(
selector: $selector
sort: $sort
first: $first
after: $after
) {
edges {
node {
id
inTimestamp
outTimestamp
hoursWorked
inNotes
outNotes
user {
id
firstName
lastName
}
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
# Variables
{
"first": 50,
"sort": [{ "field": "inTimestamp", "order": "DESC" }],
"selector": {
"filters": {
"inTimestamp": {
"greaterThanOrEquals": "2024-01-01T00:00:00Z",
"lessThanOrEquals": "2024-01-08T00:00:00Z"
}
}
}
}Response:
{
"data": {
"infiniteClockings": {
"edges": [
{
"node": {
"id": "clk_001",
"inTimestamp": "2024-01-05T14:02:00Z",
"outTimestamp": "2024-01-05T22:31:00Z",
"hoursWorked": 8.48,
"inNotes": "Starting the route",
"outNotes": null,
"user": {
"id": "usr_123",
"firstName": "Dana",
"lastName": "Rivera"
}
},
"cursor": "eyJpZCI6ImNsa18wMDEifQ=="
}
],
"pageInfo": {
"hasNextPage": true,
"endCursor": "eyJpZCI6ImNsa18wMDEifQ=="
}
}
}
}Who Is Clocked In Right Now
Pass clockedIn: true to get only the entries that are still open — one per team member currently on the clock.
query ClockedIn {
infiniteClockings(selector: { clockedIn: true }, first: 100) {
edges {
node {
id
inTimestamp
inLatitude
inLongitude
user {
id
firstName
lastName
}
}
}
}
}Response:
{
"data": {
"infiniteClockings": {
"edges": [
{
"node": {
"id": "clk_014",
"inTimestamp": "2024-01-08T13:58:00Z",
"inLatitude": 34.05,
"inLongitude": -118.24,
"user": {
"id": "usr_123",
"firstName": "Dana",
"lastName": "Rivera"
}
}
}
]
}
}
}Hours For One Team Member
Combine the user filter with a clock-in window to total a single team member's hours for a payroll period. Filter by the user's id as returned by the Users resource.
query UserHours($userId: ID!, $from: String!, $to: String!) {
infiniteClockings(
selector: {
clockedIn: false
filters: {
user: { equals: $userId }
inTimestamp: { greaterThanOrEquals: $from, lessThanOrEquals: $to }
}
}
first: 100
) {
edges {
node {
id
inTimestamp
outTimestamp
hoursWorked
updates {
timestamp
newHoursWorked
}
}
}
pageInfo {
hasNextPage
endCursor
totalEdges
}
}
}Response:
{
"data": {
"infiniteClockings": {
"edges": [
{
"node": {
"id": "clk_001",
"inTimestamp": "2024-01-05T14:02:00Z",
"outTimestamp": "2024-01-05T22:31:00Z",
"hoursWorked": 8.5,
"updates": [
{
"timestamp": "2024-01-06T09:12:00Z",
"newHoursWorked": 8.5
}
]
}
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "eyJpZCI6ImNsa18wMDEifQ==",
"totalEdges": 1
}
}
}
}Bulk & Export Operations
Exporting a payroll period as a file is handled asynchronously through the Bulk Operations API. See the Bulk Operations guide for the full workflow.
Field Reference
| Field | Type | Description |
|---|---|---|
id | ID! | Unique identifier (cuid) |
user | User! | The team member the entry belongs to |
userId | Int! | Internal numeric user id — prefer user { id }, which is the cuid used everywhere else in the API |
inTimestamp | Date(nullable) | When the user clocked in, truncated to the minute |
inNotes | String(nullable) | Note the user left when clocking in |
inLatitude | Float(nullable) | Latitude recorded at clock-in |
inLongitude | Float(nullable) | Longitude recorded at clock-in |
outTimestamp | Date(nullable) | When the user clocked out, truncated to the minute. Null while the user is still on the clock |
outNotes | String(nullable) | Note the user left when clocking out |
outLatitude | Float(nullable) | Latitude recorded at clock-out |
outLongitude | Float(nullable) | Longitude recorded at clock-out |
hoursWorked | Float(nullable) | Hours between clock-in and clock-out, rounded to two decimals. Set on clock-out and overwritten by administrator edits |
updates | [ClockingUpdate!](nullable) | Audit trail of administrator edits to hoursWorked |
createdAt | Date! | When the entry was created |
ClockingsSelector
The selector wraps all query parameters for infiniteClockings.
| Field | Type | Description |
|---|---|---|
filters | ClockingsFiltersInput(nullable) | Field-level filters applied to the entries |
clockedIn | Boolean(nullable) | true returns only open entries (still on the clock), false only closed ones. Omit for both |
ClockingsFiltersInput
Available filter fields within ClockingsSelector.filters. Id filters support equals, in and notIn; DateTime and number filters support equals, greaterThan, greaterThanOrEquals, lessThan and lessThanOrEquals.
| Field | Type | Description |
|---|---|---|
id | IdFilter(nullable) | Filter by entry id |
user | IdFilter(nullable) | Filter by user id — the cuid from User.id |
inTimestamp | DateTimeFilter(nullable) | Filter by clock-in time |
outTimestamp | DateTimeFilter(nullable) | Filter by clock-out time |
hoursWorked | NumberFilter(nullable) | Filter by recorded hours |
Sorting
sort takes up to two ClockingSort entries, each a field of id, inTimestamp, outTimestamp, hoursWorked or createdAt with an order of ASC or DESC.
ClockingUpdate
Administrators can correct the hours on a closed entry. Each correction is recorded and exposed on Clocking.updates.
| Field | Type | Description |
|---|---|---|
id | ID! | Unique identifier (cuid) |
timestamp | DateTime! | When the edit was made |
newHoursWorked | Float(nullable) | Value hoursWorked was changed to |
userId | Int! | Internal numeric id of the administrator who made the edit |