API Reference

The Easy Manage HR REST API lets you build integrations, mobile apps, and automations on top of your HR data. All responses are JSON. The API is versioned — current version is v1.

Base URL https://{subdomain}.hr.techbloomsolutions.com/api/v1
Each organisation has its own subdomain. Replace {subdomain} with your company's subdomain, e.g. acme.hr.techbloomsolutions.com.

Authentication

The API uses Laravel Sanctum Bearer tokens. Obtain a token via POST /auth/login, then include it in every subsequent request as an Authorization header.

HTTP
Authorization: Bearer your_token_here
Content-Type: application/json
Accept: application/json
Tokens do not expire automatically. Call POST /auth/logout to revoke a token, or POST /auth/refresh to rotate it. Store tokens securely — never expose them in client-side code.

Error Codes

All errors follow a consistent envelope. The message field is human-readable; use status for programmatic handling.

JSON — Error Response
{
  "success": false,
  "message": "Unauthenticated.",
  "errors":  null,
  "timestamp": "2024-06-07T10:30:00.000000Z"
}
Status Meaning Common Cause
200 OK Request succeeded.
201 Created Resource created successfully.
400 Bad Request Invalid or missing parameters.
401 Unauthenticated Missing or invalid Bearer token.
403 Forbidden Authenticated but not authorised for this action.
404 Not Found Resource does not exist or is outside your tenant.
422 Unprocessable Validation failed — check the errors object for field-level messages.
500 Server Error Unexpected server error. Contact support if persistent.

Auth

POST /auth/login Obtain a Bearer token Public

Parameters

Name Type Description
email string required User email address.
password string required User password.
device string optional Device name for token labelling (e.g. "iPhone 15").
Request Body — JSON
{
                          "email":    "admin@acme.co.ke",
                          "password": "secret1234",
                          "device":   "My App"
                        }
Response — JSON
{
                          "success": true,
                          "data": {
                            "token": "1|abc123xyz...",
                            "user": {
                              "id":    1,
                              "name":  "Alice Mwangi",
                              "email": "admin@acme.co.ke",
                              "roles": ["hr_manager"]
                            }
                          },
                          "message":   "Login successful.",
                          "timestamp": "2024-06-07T10:30:00.000000Z"
                        }
POST /auth/logout Revoke current token Auth
Requires Authorization: Bearer <token> header.
Response — JSON
{
                          "success": true,
                          "message":   "Logged out successfully.",
                          "timestamp": "2024-06-07T10:31:00.000000Z"
                        }
POST /auth/refresh Rotate token (revoke + issue new) Auth
Requires Authorization: Bearer <token> header.
Response — JSON
{
                          "success": true,
                          "data": { "token": "2|newtoken..." },
                          "message":   "Token refreshed.",
                          "timestamp": "2024-06-07T10:32:00.000000Z"
                        }

Employees

GET /employees List all employees Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
search string optional Full-text search on name, email, or employee number.
department_id integer optional Filter by department ID.
status string optional active | inactive | terminated | on_leave
per_page integer optional Results per page (default 15, max 100).
page integer optional Page number (default 1).
Response — JSON
{
                          "success": true,
                          "data": {
                            "data": [{
                              "id":              42,
                              "employee_number": "EMP-0042",
                              "first_name":      "James",
                              "last_name":       "Otieno",
                              "email":           "james.otieno@acme.co.ke",
                              "phone":           "+254712345678",
                              "job_title":       "Software Engineer",
                              "department_id":   3,
                              "status":          "active",
                              "hire_date":       "2022-03-01",
                              "department":      { "id": 3, "name": "Engineering" }
                            }],
                            "total": 58, "per_page": 15, "current_page": 1
                          }
                        }
POST /employees Create a new employee Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
first_name string required First name.
last_name string required Last name.
email string required Work email address (unique per tenant).
phone string optional Phone number (E.164 preferred).
job_title string optional Job title / position.
department_id integer optional Department ID.
hire_date date required Hire date in YYYY-MM-DD format.
status string optional active (default) | inactive | terminated | on_leave
national_id string optional National ID number.
kra_pin string optional KRA PIN for payroll tax computation.
nssf_number string optional NSSF member number.
nhif_number string optional NHIF / SHA member number.
bank_name string optional Bank name for payroll disbursement.
bank_account string optional Bank account number.
basic_salary numeric optional Gross basic salary (KES).
Request Body — JSON
{
                          "first_name":    "Jane",
                          "last_name":     "Kamau",
                          "email":         "jane.kamau@acme.co.ke",
                          "department_id": 3,
                          "hire_date":     "2024-07-01",
                          "basic_salary":  85000,
                          "kra_pin":       "A001234567B"
                        }
Response — JSON
{
                          "success": true,
                          "data": { /* employee object */ },
                          "message": "Employee created successfully."
                        }
GET /employees/{id} Get a single employee Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
id integer required Employee ID.
Response — JSON
{
                          "success": true,
                          "data": { /* full employee object with department, user, etc. */ }
                        }
PUT /employees/{id} Update an employee Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
id integer required Employee ID (path param).
first_name string optional First name.
last_name string optional Last name.
email string optional Work email.
department_id integer optional Department ID.
status string optional active | inactive | terminated | on_leave
basic_salary numeric optional Updated gross salary.
Request Body — JSON
{
                          "status":       "on_leave",
                          "basic_salary": 90000
                        }
Response — JSON
{
                          "success": true,
                          "data": { /* updated employee object */ },
                          "message": "Employee updated successfully."
                        }
DELETE /employees/{id} Delete (soft) an employee Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
id integer required Employee ID.
Response — JSON
{
                          "success": true,
                          "message": "Employee deleted successfully."
                        }

Departments

GET /departments/tree Organisation chart (nested tree) Auth
Requires Authorization: Bearer <token> header.
Response — JSON
{
                          "success": true,
                          "data": [{
                            "id": 1, "name": "Headquarters",
                            "children": [{
                              "id": 2, "name": "Engineering",
                              "children": []
                            }]
                          }]
                        }
GET /departments List departments (flat) Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
name string optional Filter by name (partial match).
parent_id integer optional Filter by parent department ID.
per_page integer optional Results per page.
Response — JSON
{
                          "success": true,
                          "data": {
                            "data": [{
                              "id": 2, "name": "Engineering",
                              "parent_id": 1,
                              "employees_count": 14
                            }],
                            "total": 8
                          }
                        }
POST /departments Create a department Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
name string required Department name (unique per tenant).
parent_id integer optional Parent department ID for nested structures.
description string optional Optional description.
manager_id integer optional Employee ID of the department manager.
Request Body — JSON
{
                          "name":      "Product Design",
                          "parent_id": 2,
                          "manager_id": 42
                        }
Response — JSON
{
                          "success": true,
                          "data": { /* department object */ },
                          "message": "Department created successfully."
                        }

Attendance

GET /attendance List attendance records Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
start_date date optional Filter from this date (YYYY-MM-DD).
end_date date optional Filter to this date (YYYY-MM-DD).
department_id integer optional Filter by department.
status string optional present | absent | late | half_day
per_page integer optional Results per page (default 15).
Response — JSON
{
                          "success": true,
                          "data": {
                            "data": [{
                              "id":           1001,
                              "employee_id":  42,
                              "date":         "2024-06-07",
                              "clock_in":    "08:02:00",
                              "clock_out":   "17:01:00",
                              "status":       "present",
                              "hours_worked": 8.98
                            }]
                          }
                        }
GET /attendance/today Today's attendance summary Auth
Requires Authorization: Bearer <token> header.
Response — JSON
{
                          "success": true,
                          "data": {
                            "date":         "2024-06-07",
                            "total_employees": 58,
                            "present":        52,
                            "absent":         4,
                            "late":           2,
                            "on_leave":       3,
                            "records": [ /* today's attendance records */ ]
                          }
                        }
GET /attendance/reports Aggregate attendance report Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
start_date date required Report start date (YYYY-MM-DD).
end_date date required Report end date (YYYY-MM-DD).
department_id integer optional Limit to one department.
group_by string optional day | week | month | employee | department
Response — JSON
{
                          "success": true,
                          "data": {
                            "period": { "start": "2024-06-01", "end": "2024-06-30" },
                            "summary": {
                              "total_days":    30,
                              "working_days": 21,
                              "attendance_rate": "94.3%"
                            },
                            "rows": [ /* grouped rows */ ]
                          }
                        }
POST /attendance/clock-in Record a clock-in event Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
employee_id integer required Employee ID clocking in.
latitude numeric optional GPS latitude (required if geofencing is active).
longitude numeric optional GPS longitude (required if geofencing is active).
note string optional Optional clock-in note.
Request Body — JSON
{
                          "employee_id": 42,
                          "latitude":    -1.286389,
                          "longitude":   36.817223
                        }
Response — JSON
{
                          "success": true,
                          "data": {
                            "id":          1002,
                            "employee_id": 42,
                            "date":        "2024-06-07",
                            "clock_in":   "08:05:12",
                            "status":      "present"
                          },
                          "message": "Clock-in recorded."
                        }
POST /attendance/clock-out Record a clock-out event Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
employee_id integer required Employee ID clocking out.
latitude numeric optional GPS latitude.
longitude numeric optional GPS longitude.
note string optional Optional clock-out note.
Request Body — JSON
{
                          "employee_id": 42
                        }
Response — JSON
{
                          "success": true,
                          "data": {
                            "id":           1002,
                            "clock_out":   "17:03:44",
                            "hours_worked": 8.97
                          },
                          "message": "Clock-out recorded."
                        }

Leave

GET /leaves/requests List leave requests Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
employee_id integer optional Filter by employee.
status string optional pending | approved | rejected | cancelled
start_date date optional From date (YYYY-MM-DD).
end_date date optional To date (YYYY-MM-DD).
per_page integer optional Results per page.
Response — JSON
{
                          "success": true,
                          "data": {
                            "data": [{
                              "id":          77,
                              "employee_id": 42,
                              "leave_type":  { "id": 1, "name": "Annual Leave" },
                              "start_date":  "2024-07-01",
                              "end_date":    "2024-07-05",
                              "days":        5,
                              "status":      "approved",
                              "reason":      "Family holiday"
                            }]
                          }
                        }
POST /leaves/requests Submit a leave request Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
employee_id integer required Employee submitting the request.
leave_type_id integer required Leave type ID (from /leaves/types).
start_date date required First day of leave (YYYY-MM-DD).
end_date date required Last day of leave (YYYY-MM-DD).
reason string optional Reason for the leave.
notes string optional Additional notes for approver.
Request Body — JSON
{
                          "employee_id":   42,
                          "leave_type_id": 1,
                          "start_date":    "2024-07-01",
                          "end_date":      "2024-07-05",
                          "reason":        "Annual family holiday"
                        }
Response — JSON
{
                          "success": true,
                          "data": { /* leave request object */ },
                          "message": "Leave request submitted successfully."
                        }
POST /leaves/requests/{id}/approve Approve a leave request Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
id integer required Leave request ID (path param).
comment string optional Approver comment.
Request Body — JSON
{
                          "comment": "Approved. Enjoy your holiday!"
                        }
Response — JSON
{
                          "success": true,
                          "message": "Leave request approved."
                        }
GET /leaves/balances/{employee_id} Employee's leave balances by type Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
employee_id integer required Employee ID (path param).
year integer optional Year (defaults to current year).
Response — JSON
{
                          "success": true,
                          "data": [{
                            "leave_type": "Annual Leave",
                            "entitled":   21,
                            "used":       5,
                            "pending":    0,
                            "remaining":  16
                          }]
                        }
GET /leaves/types List leave types Auth
Requires Authorization: Bearer <token> header.
Response — JSON
{
                          "success": true,
                          "data": [{
                            "id":              1,
                            "name":            "Annual Leave",
                            "days_per_year":   21,
                            "is_paid":         true,
                            "requires_approval": true
                          }]
                        }

Payroll

GET /payroll/periods List payroll periods Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
status string optional draft | processing | completed | paid
year integer optional Filter by year.
per_page integer optional Results per page.
Response — JSON
{
                          "success": true,
                          "data": {
                            "data": [{
                              "id":         12,
                              "name":       "June 2024",
                              "start_date": "2024-06-01",
                              "end_date":   "2024-06-30",
                              "status":     "completed",
                              "total_gross":   4935000,
                              "total_net":     3902000,
                              "employees_count": 58
                            }]
                          }
                        }
POST /payroll/periods/{period_id}/generate Run payroll computation for a period Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
period_id integer required Period ID (path param).
employee_ids array optional Subset of employee IDs to process. Omit to process all.
Request Body — JSON
{
                          // omit employee_ids to process everyone in the period
                          "employee_ids": [42, 43, 44]
                        }
Response — JSON
{
                          "success": true,
                          "data": {
                            "processed": 58,
                            "total_gross": 4935000,
                            "total_net":   3902000,
                            "total_paye":  890000,
                            "total_nssf":  52200,
                            "total_nhif":  90800
                          },
                          "message": "Payroll generated for 58 employees."
                        }
GET /payroll/my-payslips Authenticated employee's payslips Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
per_page integer optional Results per page.
Response — JSON
{
                          "success": true,
                          "data": {
                            "data": [{
                              "id":          234,
                              "period_name": "June 2024",
                              "basic_salary": 85000,
                              "gross_pay":    95000,
                              "net_pay":     74250,
                              "paye":        15200,
                              "nssf":        900,
                              "nhif":        1570,
                              "download_url": "/api/v1/payroll/payslips/234/download"
                            }]
                          }
                        }
GET /payroll/reports Payroll summary reports Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
period_id integer optional Specific period ID.
start_date date optional Report range start.
end_date date optional Report range end.
department_id integer optional Filter by department.
format string optional json (default) | csv
Response — JSON
{
                          "success": true,
                          "data": {
                            "periods": [{
                              "name":        "June 2024",
                              "total_gross": 4935000,
                              "total_net":   3902000,
                              "total_paye":  890000
                            }]
                          }
                        }

Geofencing

Geofencing restricts clock-in/clock-out to approved physical locations. If geofencing is required for your organisation, clock-in requests must include valid coordinates.

GET /geofences List configured geofences Auth
Requires Authorization: Bearer <token> header.
Response — JSON
{
                          "success": true,
                          "data": [{
                            "id":        1,
                            "name":      "Nairobi HQ",
                            "latitude":  -1.286389,
                            "longitude": 36.817223,
                            "radius_m":  200,
                            "is_active": true
                          }]
                        }
POST /geofences/validate Check if coordinates are within a geofence Auth
Requires Authorization: Bearer <token> header.

Parameters

Name Type Description
latitude numeric required Device GPS latitude.
longitude numeric required Device GPS longitude.
Request Body — JSON
{
                          "latitude":  -1.286389,
                          "longitude": 36.817223
                        }
Response — JSON
{
                          "success": true,
                          "data": {
                            "valid":        true,
                            "geofence_id":  1,
                            "geofence_name": "Nairobi HQ",
                            "distance_m":   45.2
                          },
                          "message": "Location is within the allowed geofence."
                        }