HRM — Attendance & Shifts

When people work, and the schedule that says when they should

These two modules are documented together because they are tightly linked: a shift says when an employee is supposed to work, and attendance records when they actually did — the gap between the two is what tells the system if someone was late, absent, or eligible for overtime.

Part 1 — Attendance

What it does

Attendance records every clock event — check-in, check-out, break start, break end — as a permanent, immutable entry. From those raw events the system derives a daily status (present, late, absent, on leave, half-day) that payroll later reads. Employees who forget to punch can file a correction (regularization) request, which a manager approves or rejects.

Capture methods

A punch can be captured several ways. The server validates the method on every punch — it never trusts what the client claims.

MethodHow it's verifiedTypical use
WEBAllowed if the store permits web check-inDesk/back-office staff clicking a button
MOBILE_APPSame, from a mobile clientStaff on the move
GEOFENCEPhone GPS must fall within the store's radiusField staff who must be physically present
IP_RESTRICTEDRequest IP must match the store's whitelist (CIDR)On-premise only clock-in
QR_CODEScan of a short-lived, one-time tokenA QR poster at the entrance
BIOMETRICFingerprint/face device punchHardware time clocks
MANUALForced when one person punches for another (needs the manual permission)HR fixing a missed punch
Geofencing & IP need store setup first

GEOFENCE and IP_RESTRICTED only work once the store has a geofence or IP whitelist configured. Set those with PATCH /api/v2/stores/:id/geolocation (geoLat, geoLng, geoRadiusM 1–50000) and PATCH /api/v2/stores/:id/ip-whitelist. See the v2 API Reference.

The punch lifecycle

text

Every event is stored with no updatedAt and no delete — attendance is a truthful event log. If something is wrong, you don't edit it; you add a correction that creates a new event.

Clocking in (API)

Dev Only Self: ess.attendance.check-in · For others: hr.attendance.check-in.manual

http
json

Omit employeeId to punch yourself. Supplying an employeeId forces method: MANUAL and requires the manual permission. The same shape applies to check-out, break-start, and break-end.

Derived daily status

The system computes each day's status on read (and caches it). The logic, in plain terms:

1

Is it a holiday?

If the date is on the holiday calendar → HOLIDAY.

2

On approved leave?

If an approved leave request covers the date → ON_LEAVE (or HALF_DAY).

3

No punches on a working day?

ABSENT. (No punches on a rostered off-day or weekend → not absent.)

4

Punches exist?

Pair check-ins with check-outs, subtract breaks, compare against the shift's start/end + grace period to flag LATE, compute overtime, and decide PRESENT vs HALF_DAY.

Derived statuses are: PRESENT, LATE, ABSENT, HALF_DAY, WEEKEND, HOLIDAY, ON_LEAVE, with extra flags like MISSING_CHECKOUT.

Corrections (regularization)

text
http
json
Correction time window

Regularization is time-boxed (default ~7 days, set by the tenant's HR settings). Requests older than the window can only be entered by HR via the manual path, and are audited.

In the app

PageRouteWhat you do there
Attendance board/hr/attendanceSummary tiles, today's punches, the event list (scoped to your permission).
Corrections/hr/attendance/correctionsReview, approve, or reject correction requests.
New correction/hr/attendance/corrections/newFile a correction request.

Attendance permissions

CapabilityADMINHR_MANAGERMANAGEREMPLOYEE
Own check-in/outYesYesYesYes
Read team attendanceYesYesTeamNo
Read all attendanceYesYesNoNo
Manual punch for othersYesYesTeamNo
Approve/reject correctionsYesYesTeamNo

Part 2 — Shifts & Scheduling

What it does

Shifts manage work schedules (this is unrelated to v1 cash-drawer sessions). You build reusable shift templates, publish a roster (assign templates to employees on dates), and let employees swap shifts with a colleague — subject to manager approval.

Template vs instance — the key idea

ModelWhat it isMutability
WorkShift (template)A reusable definition: name, start/end time, break minutes, grace minutes, night-shift premium %.Edited rarely; long-lived.
ShiftSchedule (instance)One employee, one date — created from a template.Snapshots the template's times at creation.
Why the snapshot matters

When you roster a shift, its times are copied (snapshotted) into the schedule row. So editing a template later does not rewrite schedules that are already published — past and future stay correct. Payroll always reads the snapshot, never a live template join.

A WorkShift whose endTime is earlier than its startTime is a crosses-midnight shift (e.g. 22:00 → 06:00) and is handled correctly.

Shift statuses

EnumValues
ShiftScheduleStatusSCHEDULED · COMPLETED · ABSENT · ON_LEAVE · CANCELLED · SWAPPED
ShiftSwapStatusPENDING_PEER · PENDING_MANAGER · APPROVED · REJECTED · CANCELLED · EXPIRED

Publishing a roster (bulk)

Dev Only POST /api/v2/hr/shifts/schedule · permission hr.shifts.schedule.create

Send 1–500 entries. Each row is checked independently; the response separates what was created from any conflicts (e.g. a day that's already completed, or an inactive employee). When isOffDay is true, workShiftId is optional.

json
Off-day vs no row

An explicit isOffDay row is a rostered rest day — it is not counted as absent. "Absent" only happens when a real working schedule had no attendance and no leave.

Shift swaps — a three-step approval

text
http
json

Setting counterpartScheduleId: null makes it a give-away (the counterpart takes the shift; the requester is unrostered that day). Swaps expire after a configurable window (default ~48 hours). Each transition notifies the relevant people.

In the app

PageRouteWhat you do there
Templates/hr/shiftsCreate & manage shift templates.
Roster/hr/shifts/scheduleView the roster grid; edit/cancel individual cells.
New roster/hr/shifts/schedule/newBulk-assign shifts.
Swaps/hr/shifts/swapsAccept/reject, approve, or cancel swap requests.
New swap/hr/shifts/swaps/newRequest a swap.

Shift permissions

CapabilityADMINHR_MANAGERMANAGEREMPLOYEE
Read templatesYesYesYesNo
Manage templatesYesYesNoNo
Read rosterYesYesTeamOwn (via ESS)
Create/edit rosterYesYesTeamNo
Request / respond to a swapYesYesYes (via ESS)
Approve a swapYesYesTeamNo

How They Connect

When someone clocks in, attendance asks the shifts module "what was this person scheduled to work today?" and uses that window to judge lateness and overtime. If the shifts module isn't in use, attendance falls back to the tenant's default work-week settings — everything keeps working, just without per-day rosters.

Next step

Next, set up Leave & Holidays so approved time off shows up correctly on the attendance board instead of as "absent".