Data Model Reference
This page documents the shape of every public resource: field names, types, nullability, and the relationships between resources. All field names are camelCase on the wire. Dates are ISO 8601.
For request-body shapes and inline examples per endpoint, see the interactive API reference. For end-to-end code samples, see the Code Examples guide.
Relationships at a Glance
Account
└── Employee ─┬─ Location, DepartmentCode (JobCode), Position, Group
├─ Geofence
├─ TimeOffAccrualBalance ─── TimeOffAccrualEntry
├─ Shift (scheduled future work; optionally assigned)
└─ TimeCard (one per PayPeriod)
├─ Punch ─── Break
├─ TimeEntry (duration-based time)
└─ TimeOff (paid / unpaid time off)
PayPeriod ─── TimeCard
WebhookEndpoint ─── WebhookEvent
- An Employee belongs to exactly one account. They can be assigned to many Locations, DepartmentCodes, Positions, and Groups.
- A TimeCard aggregates all entries (punches, time entries, time off) for one Employee within one PayPeriod. Retrieve the unified list with
GET /timeCard/{id}/timesor get full details withGET /timeCard/{id}/details. On the detail response, the entries live under thetimesarray and each carries atypediscriminator ("punch" | "time_entry" | "time_off"). - A Punch belongs to a TimeCard. Breaks nest inside a Punch.
- Time Entries are duration-based time (no punch-in / punch-out clock), useful for salaried or remote work logging.
- Time Off covers paid and unpaid leave. Balances and accrual transactions are tracked separately via the Time Off Accrual resources.
- A Shift is a scheduled future work block — independent of TimeCards (which are actuals). Shifts can optionally be assigned to an Employee, Location, JobCode, and Position. Use
GET /scheduleto retrieve a date-range view of shifts with optional filters. - Webhooks deliver real-time events. Each event references the resource it describes in its
datafield. See the Webhooks guide.
Employee
Endpoint family: /employee.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
firstName |
string | No | Given name |
lastName |
string | No | Family name |
email |
string | No | Contact email |
username |
string | Yes | Login username |
employeeId |
string | Yes | Customer-chosen external employee code |
isActive |
boolean | No | false = deactivated |
gpsPermissionId |
integer | Yes | Punch-GPS policy id (see account settings) |
webcamPermissionId |
integer | Yes | Punch-photo policy id |
phoneNumber |
string | Yes | E.164 or free-form |
profileMiniImageUrl |
string | Yes | CDN URL |
isManager |
boolean | No | Whether the employee has manager privileges |
Location
Endpoint family: /location.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
name |
string | No | Display name (max 200 chars) |
enabled |
boolean | No | Whether employees may punch at this location |
billable |
boolean | No | Whether time here is billable |
payrollCode |
string | Yes | Customer payroll export code |
jobCodeIds |
array of integer | Yes | Department codes attached to this location |
Employees are assigned to locations via PUT /location/{id}/employees.
Department Code (Job Code)
Endpoint family: /departmentCode. Represented as JobCodeResource in the OpenAPI schema.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
name |
string | No | Display name (max 200 chars) |
enabled |
boolean | No | Whether employees may select this code |
billable |
boolean | No | Whether time against this code is billable |
payrollCode |
string | Yes | Customer payroll export code |
Position
Endpoint family: /position.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
name |
string | No | Display name (max 200 chars) |
enabled |
boolean | No | Whether employees may be assigned to this position |
Group
Endpoint family: /group.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
name |
string | No | Display name |
Geofence
Endpoint family: /geofence.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
name |
string | No | Display name (max 200 chars) |
latitude |
decimal | No | WGS84 latitude (−90 to 90) |
longitude |
decimal | No | WGS84 longitude (−180 to 180) |
radius |
integer | No | Radius in feet |
radiusInMeters |
integer | No | Radius in meters |
active |
boolean | No | Whether the fence is enforced |
autoAssignEnabled |
boolean | No | Auto-assign new employees in range |
locationId |
integer | Yes | Linked location, if any |
jobCodeId |
integer | Yes | Linked department code, if any |
Pay Period
Endpoint family: /payPeriod.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
startDate |
datetime | No | Start (local time) |
endDate |
datetime | No | End (local time) |
lockedForEmployees |
boolean | No | Employees cannot edit their own entries |
lockedForEveryone |
boolean | No | No one can edit (even admins) |
closed |
boolean | No | Payroll has been exported / finalized |
Update status flags via PUT /payPeriod/{id} using PayPeriodEditRequest (merge-patch — only supplied fields change).
Time Card
Endpoint family: /timeCard. One per Employee per PayPeriod.
TimeCardResource (list item, lightweight)
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
payPeriod |
PayPeriodResource | Yes | Nested pay period |
employee |
EmployeeResource | Yes | Nested employee |
TimeCardDetailResource (from `GET /timeCard/
Adds hour totals, approval state, and the full list of time entries:
| Field | Type | Nullable | Description |
|---|---|---|---|
totalHours |
double | Yes | Grand total across all time |
totalRegularHours |
double | Yes | Regular hours (no OT multiplier) |
totalOvertimeHours |
double | Yes | 1.5× hours |
totalDoubleTimeHours |
double | Yes | 2× hours |
totalTimeOffHours |
double | Yes | Paid and unpaid time off |
totalPaidBreakHours |
double | Yes | Breaks that count toward paid time |
totalUnpaidBreakHours |
double | Yes | Breaks deducted from paid time |
approvalStatus |
string | Yes | PendingApproval, Approved, Rejected |
isLocked |
boolean | No | Whether edits are blocked |
hasPendingTimes |
boolean | No | Any entry still awaiting approval, regardless of subtype |
times |
array of TimeDetailResource | No | All time entries on this time card — punches, manually-entered time entries, and time off, each carrying a type discriminator |
The sibling GET /timeCard/{id}/times endpoint returns the same mixed list as a paginated top-level response — but uses the lighter PunchResource list shape (each item tagged with the same type discriminator of punch, time_entry, or time_off). It supports filtering via ?type=. Use /times when you want a paginated list and don't need the heavier detail fields (breaks, approval splits, paid/unpaid break hours); use /details when you want the full detail shape plus the time-card-level hour totals.
Punch
Endpoint family: /punch.
PunchResource (list item)
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
type |
string | No | Always "punch" (the discriminator for shared /times responses) |
employeeId |
integer | Yes | — |
employeeName |
string | Yes | Snapshot at punch time |
locationId |
integer | Yes | — |
locationName |
string | Yes | Snapshot at punch time |
jobCodeId |
integer | Yes | Department code |
jobCodeName |
string | Yes | Snapshot |
punchInDatetime |
datetime | No | Start time |
punchOutDatetime |
datetime | Yes | End time (null = still punched in) |
punchInApprovalStatus |
string | Yes | PendingApproval, Approved, etc. |
punchOutApprovalStatus |
string | Yes | Same vocabulary |
hours |
double | Yes | Total hours including OT |
regularHours |
double | Yes | |
overtimeHours |
double | Yes | |
doubleTimeHours |
double | Yes | |
timeOffHours |
double | Yes | Non-zero only if this row is a time-off punch |
timeOffEarningCodeId |
integer | Yes | |
timeOffEarningCode |
string | Yes | |
durationHours |
double | Yes | Calendar span (end − start) |
breakMinutes |
integer | No | Sum of paid + unpaid breaks |
punchInNotes |
string | Yes | |
punchOutNotes |
string | Yes | |
punchInLatitude |
decimal | Yes | GPS capture at punch-in |
punchInLongitude |
decimal | Yes | |
punchOutLatitude |
decimal | Yes | GPS capture at punch-out |
punchOutLongitude |
decimal | Yes |
TimeDetailResource (from `GET /punch/
The umbrella detail shape used wherever an individual time-card entry is returned at full fidelity. Every entry carries a type discriminator ("punch" | "time_entry" | "time_off"); fields that don't apply to a given subtype are left null. (Renamed from PunchDetailResource in 2026 — /punch/{id} filters server-side so its response is always type: "punch", but the shape is the same one used for the other two subtypes when they appear in the TimeCardDetailResource.times array.)
The sibling GET /timeCard/{id}/times paginated endpoint uses the lighter PunchResource list shape, not this one.
Adds position/shift info, paid/unpaid break splits, and the nested break list on top of PunchResource. Key additions:
| Field | Type | Nullable | Description |
|---|---|---|---|
positionId |
integer | Yes | — |
positionName |
string | Yes | — |
shiftId |
integer | Yes | Scheduled shift this punch matched |
shiftName |
string | Yes | — |
duration |
long | Yes | Duration in ticks |
paidBreakHours |
double | Yes | |
unpaidBreakHours |
double | Yes | |
isTimeEntry |
boolean | No | true only for duration-based rows surfaced via /timeCard/{id}/times |
isTimeOffPunch |
boolean | No | true only for time-off rows |
createdAt |
datetime | No | When the punch was recorded |
breaks |
array of BreakResource | No | Nested break list |
Type contract:
/punch/{id}and/punch/{punchId}/break/*return404for time-entry and time-off ids. Use/timeEntry/{id}and/timeOff/{id}for those resource types.
Break
Endpoint family: /punch/{punchId}/break.
| Field | Type | Nullable | Description |
|---|---|---|---|
breakId |
integer | No | Stable numeric identifier |
breakRuleId |
integer | No | Links to the account's break rule |
breakRuleName |
string | Yes | Display name of the rule |
startDatetime |
datetime | No | Start (local) |
endDatetime |
datetime | Yes | End (null = open/real-time break) |
minutes |
double | Yes | Computed duration |
breakPaidType |
string | Yes | Paid or Unpaid |
approvalStatusId |
integer | Yes | — |
approvalStatusName |
string | Yes | |
notes |
string | Yes |
Real-time break start/end uses POST /break/start and POST /break/end — these act on the employee's currently-open punch, not on a specific punchId.
Time Entry
Endpoint family: /timeEntry. Duration-based time logging (no clock punch).
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
locationId |
integer | Yes | — |
departmentId |
integer | Yes | Department code |
positionId |
integer | Yes | — |
date |
datetime | Yes | Work date |
durationHours |
double | Yes | Hours worked |
notes |
string | Yes | |
breakMinutes |
integer | No | Break deducted |
breakIsUnpaid |
boolean | No | Whether the break is unpaid |
Time Off Type
Endpoint family: /timeOffType.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
name |
string | No | Display name (Vacation, Sick, etc.) |
active |
boolean | No | Whether this type accepts new requests |
Time Off
Endpoint family: /timeOff. The list endpoint returns time-off requests (single id-space) and accepts employeeId, startDate, endDate, and includeAllStaff filters.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
employeeId |
integer | Yes | — |
employeeName |
string | Yes | Snapshot |
date |
datetime | No | Day of the time off |
hours |
double | No | Hours requested |
earningCodeId |
integer | No | Time off type id |
earningCodeName |
string | Yes | |
code |
string | Yes | Abbreviation (e.g., VAC) |
notes |
string | Yes | |
status |
string | Yes | Pending, Approved, Rejected |
statusId |
integer | No | Numeric status |
timeOffType |
string | Yes | Pto or PtoRequest discriminator |
canDelete |
boolean | No | Whether the caller may delete |
isUnpaid |
boolean | No | Whether this type is unpaid |
includeAllStaff=trueis only honored when the account-level Time Off visible to all staff setting is on. Otherwise the result set is scoped to the caller (or toemployeeIdwhen supplied).
Time Off Accrual Balance
Endpoint family: /employee/{employeeId}/timeOffAccrualBalances.
| Field | Type | Nullable | Description |
|---|---|---|---|
timeOffTypeId |
integer | No | Time off type this balance tracks |
timeOffTypeName |
string | No | |
hoursAccrued |
double | No | Total accrued to date |
hoursUsed |
double | No | Already consumed |
balance |
double | No | hoursAccrued − hoursUsed |
hoursUsedWithFutureTimeOff |
double | No | Used + pending future requests |
balanceWithFutureTimeOff |
double | No | Balance after pending requests are subtracted |
Time Off Accrual Entry
Endpoint family: /employee/{employeeId}/timeOffAccrualEntries. A ledger row adding or subtracting hours.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
timeOffTypeId |
integer | No | — |
timeOffTypeName |
string | No | |
hours |
double | No | Positive = credit, negative = debit |
entryDate |
datetime | No | Effective date |
comment |
string | Yes | Reason |
authorName |
string | Yes | Who recorded the entry |
carryoverTransaction |
boolean | No | true = year-end carryover row |
Shift
Endpoint family: /shift plus the date-range view at /schedule. A shift is a scheduled future work block — independent of TimeCards (which record actual time worked). Shifts can be unassigned (open shifts) or attached to an employee, and can carry optional location/job-code/position context.
The published flag controls whether the shift is visible to employees in the mobile/web apps.
GET /schedule returns shifts in a date range with optional filters: start, end, locationIds, jobCodeIds, positionIds, employeeIds. The repeated-value filters accept multiple values, e.g. ?locationIds=1&locationIds=2.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
employeeId |
integer | Yes | — |
employeeName |
string | Yes | |
locationId |
integer | Yes | |
locationName |
string | Yes | |
jobCodeId |
integer | Yes | |
jobCodeName |
string | Yes | |
positionId |
integer | Yes | |
positionName |
string | Yes | |
startTimeUtc |
datetime | No | UTC start |
endTimeUtc |
datetime | No | UTC end |
startDateTime |
datetime | No | Local start |
endDateTime |
datetime | No | Local end |
hours |
double | No | Scheduled hours |
notes |
string | Yes | |
published |
boolean | No | Whether employees can see it |
createdAtUtc |
datetime | No | — |
updatedAtUtc |
datetime | No | — |
Webhook Endpoint
Endpoint family: /webhookEndpoint. See the Webhooks guide for delivery, retry, and signature verification.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
integer | No | Stable numeric identifier |
object |
string | No | Always "webhook_endpoint" |
url |
string | No | HTTPS target URL |
description |
string | Yes | Free-form label |
status |
string | No | enabled or disabled (from WebhookConstants.EndpointStatus) |
enabledEvents |
array of string | No | Subscribed event types (or "*") |
apiVersion |
string | No | The API version this endpoint was created against |
metadata |
object | Yes | Free-form key/value pairs |
secret |
string | Yes | HMAC signing secret. Returned only on create; omitted from list/get/update responses (nulls are globally suppressed), so store it securely when first received |
createdAt |
datetime | No | UTC |
updatedAt |
datetime | No | UTC |
Webhook Event
Endpoint family: /event.
| Field | Type | Nullable | Description |
|---|---|---|---|
id |
string | No | Starts with evt_ |
object |
string | No | Always "event" |
type |
string | No | Event type (e.g. punch.created) |
apiVersion |
string | No | API version this event was emitted against |
data |
object | No | The resource this event describes |
pendingWebhooks |
integer | No | Endpoints still pending delivery for this event |
createdAt |
datetime | No | UTC |
Related Guides
- Getting Started — auth, first request, pagination, envelope anatomy
- Errors — full error code catalog and retry behavior
- Idempotency — safe retries for write requests
- Code Examples — end-to-end samples in curl / Node.js / Python / C#
- Webhooks — real-time event notifications
- Migration Guide — moving from the legacy API