KalHR logo

API reference

Attendance

Read clock-ins and the status of each working day, the daily absence report, excused days, and holidays.

KalHR stores one attendance record per employee per day. Clocking in writes Present or Late; when HR runs the absence report for a day, everyone without a record gets Absent, Leave, Holiday or Excused. So a day's records are complete once its report has finished, which the attendance.absence_report.completed event tells you.

Records, reports and holidays need Attendance: View. Excused days (attendance exceptions) need the View Attendance Exceptions permission, which Attendance: View includes.

Attendance statuses

statusNumberMeaning
Present0Clocked in on time
Late1Clocked in after the policy's late cut-off
Absent2Expected, and no clock-in or excuse
Leave3On approved leave
Holiday4A public or company holiday
Excused5Covered by an approved attendance exception

To filter, send the name or the number: Status=Absent or Status=2.

List attendance records

GET/v1/attendance/listKey needs Attendance: View

Returns your organisation's attendance records, a page at a time, most recent day first.

Query parameters

ParameterTypeDefaultDescription
PageNumberinteger1The page to return
PageSizeinteger10Records per page
StartDate, EndDatedateOnly days from and to these dates, inclusive, as YYYY-MM-DD
EmployeeIduuidOnly this employee's records
CompanyIduuidOnly this company. Ids come from Companies.
DepartmentuuidOnly this department
UnituuidOnly this unit
Statusname or integerOnly this status
WorkModename or integerRemote (0), Onsite (1) or Hybrid (2)
ApplicableDaynameOnly this weekday, such as Monday
NeedsReviewbooleantrue for clock-ins on fully excused days, which HR should look at
SearchTermstringPart of the employee's first or last name
GET v1/attendance/list
curl "https://api.kalhr.com/v1/attendance/list?StartDate=2026-10-01&EndDate=2026-10-31&Status=Absent&PageSize=100" \
  -H "Authorization: Bearer $KALHR_API_KEY"

Response

{
  "isSuccessful": true,
  "code": "00",
  "message": "Success",
  "data": {
    "data": [
      {
        "id": "5c4b3a29-1807-4f6e-9d5c-4b3a29180706",
        "employeeId": "4b9d2c1e-7a3f-4e8b-9c21-5d6e7f8a9b0c",
        "firstName": "Ada",
        "lastName": "Okafor",
        "email": "ada.okafor@acme.ng",
        "department": "Finance",
        "role": "Payroll Officer",
        "company": { "id": "1f2e3d4c-5b6a-4987-8a6b-5c4d3e2f1a0b", "name": "Acme Nigeria Ltd" },
        "attendanceDate": "2026-10-19",
        "applicableDay": "Monday",
        "trackingMethod": "ClockInClockOut",
        "clockInTime": "08:52:10",
        "clockOutTime": "17:31:44",
        "status": "Late",
        "totalWorkedHours": 8.66,
        "workmode": "Hybrid",
        "location": "12 Admiralty Way, Lekki, Lagos",
        "needsReview": false
      }
    ],
    "pageNumber": 1,
    "pageSize": 100,
    "totalRecords": 1,
    "totalPages": 1
  }
}
FieldTypeDescription
iduuidThe attendance record
employeeId, firstName, lastName, emailuuid, stringThe employee
department, rolestringTheir first department and job role
companyobjectid, name
attendanceDatedateThe day, as YYYY-MM-DD
applicableDaystringIts weekday
trackingMethodstringTheir attendance policy's method: ClockInClockOut, or AttendanceOnly (presence only, no clock-out)
clockInTime, clockOutTimetimeHH:mm:ss, in the company's local time. Missing when they didn't clock in or out.
statusstringSee statuses
totalWorkedHoursnumberHours between clock-in and clock-out
workmodestringRemote, Onsite or Hybrid, on that day
locationstringWhere they clocked in, when recorded
attendanceExceptionIduuidThe exception excusing the day, if any
excuseTypestringThat exception's type, such as RemoteDay
excusedHalfDaystringFirstHalf or SecondHalf when only half the day is excused
needsReviewbooleantrue when they clocked in on a day that was fully excused

Get a day's absence report

GET/v1/attendance/report/{id}Key needs Attendance: View

The totals for one day, once HR has run its absence report. The reportId in the attendance.absence_report.completed event is the id here.

GET v1/attendance/report/9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a
curl "https://api.kalhr.com/v1/attendance/report/9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a" \
  -H "Authorization: Bearer $KALHR_API_KEY"

Response

{
  "isSuccessful": true,
  "code": "00",
  "message": "Success",
  "data": {
    "reportId": "9d8c7b6a-5f4e-4d3c-8b2a-1f0e9d8c7b6a",
    "reportDate": "2026-10-19",
    "status": "Completed",
    "isWorkDay": true,
    "completedAt": "2026-10-19T18:05:12Z",
    "totalEmployeesProcessed": 134,
    "presentCount": 112,
    "lateCount": 9,
    "absentCount": 4,
    "leaveCount": 6,
    "holidayCount": 0,
    "excusedCount": 3,
    "excusedAbsenceCount": 9,
    "unexcusedAbsenceCount": 4
  }
}
FieldDescription
reportDateThe day the report covers
statusCompleted when the counts are final
isWorkDayfalse when the day wasn't a working day
totalEmployeesProcessedEmployees the report looked at
presentCount, lateCount, absentCount, leaveCount, holidayCount, excusedCountEmployees with each status
excusedAbsenceCountNot expected in: leave, holiday and excused together
unexcusedAbsenceCountThe same as absentCount

List attendance exceptions

GET/v1/attendance/exceptionsKey needs Attendance: View

Attendance exceptions are days HR (or a line manager, with approval) has excused: an excused absence, a day off, a remote day, or a closure. They change what a day counts as, so an excused employee is never Absent or Late.

Good to know

What an exception is for stays in KalHR. Keys don't receive the employee's reason, HR's remarks, the attachment or the change history, and Search matches names only.

Query parameters

ParameterTypeDefaultDescription
PageNumberinteger1The page to return
PageSizeinteger20Exceptions per page, up to 100
From, TodateOnly exceptions covering any day in this range, as YYYY-MM-DD
EmployeeIduuidOnly this employee's
CompanyIduuidOnly this company's
DepartmentIduuidOnly employees in this department
Statusname or integerPending (1), Approved (2), Rejected (3) or Cancelled (4)
Typename or integerExcusedAbsence (1), DayOffGranted (2), RemoteDay (3) or CompanyClosure (4)
BatchIduuidOnly exceptions created together in one bulk action
SearchstringPart of the employee's name
GET v1/attendance/exceptions
curl "https://api.kalhr.com/v1/attendance/exceptions?Status=Approved&From=2026-10-01&To=2026-10-31" \
  -H "Authorization: Bearer $KALHR_API_KEY"

Response

{
  "isSuccessful": true,
  "code": "00",
  "message": "Success",
  "data": {
    "data": [
      {
        "id": "e1d2c3b4-a596-4877-8695-a4b3c2d1e0f9",
        "employeeId": "4b9d2c1e-7a3f-4e8b-9c21-5d6e7f8a9b0c",
        "employeeName": "Ada Okafor",
        "companyId": "1f2e3d4c-5b6a-4987-8a6b-5c4d3e2f1a0b",
        "startDate": "2026-10-22",
        "endDate": "2026-10-23",
        "days": 2,
        "type": "RemoteDay",
        "isPaid": true,
        "status": "Approved",
        "requiresApproval": false,
        "createdByName": "Tunde Bello",
        "created": "2026-10-18T09:14:03",
        "approvedByName": "Tunde Bello",
        "approvedAt": "2026-10-18T09:14:03Z",
        "canCancel": false
      }
    ],
    "pageNumber": 1,
    "pageSize": 20,
    "totalRecords": 1,
    "totalPages": 1
  }
}
FieldTypeDescription
iduuidThe exception
employeeId, employeeName, companyIduuid, string, uuidWho it excuses
startDate, endDatedateFirst and last day covered
daysintegerCalendar days covered; a half day counts as one
halfDaystringFirstHalf or SecondHalf for a half day; missing for whole days
typestringSee Type above
isPaidbooleanWhether the days are paid
statusstringSee Status above. Only Approved exceptions change attendance.
requiresApprovalbooleanRaised by a line manager and sent for approval
batchIduuidSet when created in bulk
createdByName, createdstring, datetimeWho raised it and when (UTC)
approvedByName, approvedAt, rejectedAt, cancelledAtstring, datetimeIts decision
canCancelbooleanAlways false for a key

Get an attendance exception

GET/v1/attendance/exceptions/{id}Key needs Attendance: View

The same fields as the list, for one exception. An id outside your organisation answers isSuccessful: false.

GET v1/attendance/exceptions/e1d2c3b4-a596-4877-8695-a4b3c2d1e0f9
curl "https://api.kalhr.com/v1/attendance/exceptions/e1d2c3b4-a596-4877-8695-a4b3c2d1e0f9" \
  -H "Authorization: Bearer $KALHR_API_KEY"

List company holidays

GET/v1/attendance/holidaysKey needs Attendance: View

The holidays and closures your organisation has added itself, for one year, in date order. A recurring holiday is listed on the date it falls that year. Public holidays are a separate list (below).

ParameterTypeDefaultDescription
YearintegerThis yearThe year to list
CompanyIduuidThis company's holidays plus the organisation-wide ones. Leave it out for all.
GET v1/attendance/holidays
curl "https://api.kalhr.com/v1/attendance/holidays?Year=2026" \
  -H "Authorization: Bearer $KALHR_API_KEY"

Response

{
  "isSuccessful": true,
  "code": "00",
  "message": "Success",
  "data": [
    {
      "id": "0f1e2d3c-4b5a-4968-8778-695a4b3c2d1e",
      "name": "Company anniversary",
      "date": "2019-06-14",
      "occursOn": "2026-06-14",
      "isRecurring": true
    },
    {
      "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
      "name": "Lagos office closed for refurbishment",
      "date": "2026-11-27",
      "occursOn": "2026-11-27",
      "isRecurring": false,
      "companyId": "1f2e3d4c-5b6a-4987-8a6b-5c4d3e2f1a0b",
      "companyName": "Acme Nigeria Ltd"
    }
  ]
}
FieldTypeDescription
id, nameuuid, stringThe holiday
occursOndateThe day it falls on in the year you asked for
datedateThe date it was added for; for a recurring holiday, its first year
isRecurringbooleanRepeats on the same day every year
companyId, companyNameuuid, stringThe one company it applies to; missing when it's organisation-wide

This is a plain list, not paged.

List public holidays

GET/v1/attendance/holidays/publicKey needs Attendance: View

The public holidays of your organisation's countries (its own, its companies' and their offices'), or one company's, for a year. KalHR imports them from public calendars; they can't be edited.

ParameterTypeDefaultDescription
YearintegerThis yearThe year to list
CompanyIduuidOnly the countries this company and its offices are in
GET v1/attendance/holidays/public
curl "https://api.kalhr.com/v1/attendance/holidays/public?Year=2026" \
  -H "Authorization: Bearer $KALHR_API_KEY"

Response

{
  "isSuccessful": true,
  "code": "00",
  "message": "Success",
  "data": [
    { "name": "Independence Day", "startDate": "2026-10-01", "endDate": "2026-10-01", "countryId": 160, "countryName": "Nigeria" },
    { "name": "Christmas Day", "startDate": "2026-12-25", "endDate": "2026-12-25", "countryId": 160, "countryName": "Nigeria" }
  ]
}
FieldTypeDescription
namestringThe holiday
startDate, endDatedateFirst and last day, inclusive
countryId, countryNameinteger, stringThe country it belongs to

A day that is both a public holiday and a company holiday counts once.

  • Leave: leave requests and balances
  • Event catalogue: attendance.exception.approved, attendance.absence_report.completed

Last updated October 19, 2026

Missing an endpoint or an event?

Tell us what you're building. The API grows from what integrators ask for.

See KalHR in action - 30 min demo