MASKDocs

Integration API

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 (endedAt of an open shift, expiresAt of 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's kind). 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 (dayBoundaryMinutes after 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
}
  • from and to are 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 year of 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-31 is 31 days.
  • Other date fields (startedOn, endedOn of 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.