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

FieldTypeDescription
idID!Unique identifier (cuid)
userUser!The team member the entry belongs to
userIdInt!Internal numeric user id — prefer user { id }, which is the cuid used everywhere else in the API
inTimestampDate(nullable)When the user clocked in, truncated to the minute
inNotesString(nullable)Note the user left when clocking in
inLatitudeFloat(nullable)Latitude recorded at clock-in
inLongitudeFloat(nullable)Longitude recorded at clock-in
outTimestampDate(nullable)When the user clocked out, truncated to the minute. Null while the user is still on the clock
outNotesString(nullable)Note the user left when clocking out
outLatitudeFloat(nullable)Latitude recorded at clock-out
outLongitudeFloat(nullable)Longitude recorded at clock-out
hoursWorkedFloat(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
createdAtDate!When the entry was created

ClockingsSelector

The selector wraps all query parameters for infiniteClockings.

FieldTypeDescription
filtersClockingsFiltersInput(nullable)Field-level filters applied to the entries
clockedInBoolean(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.

FieldTypeDescription
idIdFilter(nullable)Filter by entry id
userIdFilter(nullable)Filter by user id — the cuid from User.id
inTimestampDateTimeFilter(nullable)Filter by clock-in time
outTimestampDateTimeFilter(nullable)Filter by clock-out time
hoursWorkedNumberFilter(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.

FieldTypeDescription
idID!Unique identifier (cuid)
timestampDateTime!When the edit was made
newHoursWorkedFloat(nullable)Value hoursWorked was changed to
userIdInt!Internal numeric id of the administrator who made the edit