Requests, responses and time
The rules every route follows: the format of requests and answers, how lists are paged, and how time is written.
Requests and responses#
- JSON in and out. Send bodies as
Content-Type: application/json; anything else on a body is 415, and a body that is not JSON is 400. Strings are UTF-8. - Absent means null. Null fields are left out of answers (
endedAtof an open shift,expiresAtof a key that does not expire). Treat a missing field as null. - Ignore what you don't know. New fields may appear in any answer, and new strings in any enumerated field (
status,source,anomalies,eventCode, an interval'skind). A client must not fail on them. - Request bodies bind only the documented fields; anything else is ignored. An event a key writes is always
source: "api", whatever the body says. - Money and rates are JSON numbers with at most two decimals (
"hourlyRate": 12.5). Durations are integer seconds.
Lists and paging#
List routes take page (1-based, default 1) and pageSize (default 50, 1 to 200) and answer:
{"list": [ … ], "count": 137, "page": 1, "pageSize": 50, "totalPages": 3}
count is the total number of rows. The order is fixed, so paging is deterministic: employees and cards by id, events by eventTime then id, sessions by businessDate, startedAt, id. A page past the end is an empty list.
Time and dates#
- Instants are integer epoch seconds, UTC:
eventTime,startedAt,endedAt,createdAt,updatedAt,expiresAt,computedAt. - Business dates are ISO dates (
2026-11-03) at the institution: its local time (timezone, an IANA zone) minus its day boundary (dayBoundaryMinutesafter local midnight). Docs Example School's boundary is 240 (04:00), so a clock-out at 03:30 on 4 November belongs to 3 November:
curl -s -X POST "$MASK/integration/events" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-H 'Idempotency-Key: erp-clock-88160' \
-d '{"employeeId":24,"institutionId":1,"eventCode":"clock_out","eventTime":1793759400}'
{
"id": 7613,
"employeeId": 24,
"institutionId": 1,
"businessDate": "2026-11-03",
"eventCode": "clock_out",
"eventTime": 1793759400,
"source": "api",
"status": "active",
"anomalies": ["no_open_session"],
"createdAt": 1793813154
}
fromandtoare inclusive business dates, each institution's day following its own time zone and boundary.- Every date a request names lies between 2000-01-01 and 2037-12-31 (400 otherwise), so the
yearof the payroll report is 2000 to 2037. - Range limits, both ends included: events at most 31 days, sessions at most 92, reports at most 366.
2026-10-01..2026-10-31is 31 days. - Other date fields (
startedOn,endedOnof a membership) are plain calendar dates.
When several things are wrong#
A request gets one error, the first problem found. Fix it and send again: another error may follow until the request is right.