npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@markwharton/eh-payroll

v3.4.0

Published

Employment Hero Payroll API client

Downloads

2,560

Readme

@markwharton/eh-payroll

Employment Hero Payroll API client for employee data, roster shifts, and time & attendance.

Install

npm install @markwharton/eh-payroll

Quick Start

import { PayrollClient } from '@markwharton/eh-payroll';

const client = new PayrollClient({
  apiKey: 'xxx',
  businessId: 123,
  region: 'au',  // 'au' | 'nz' | 'uk' | 'sg' | 'my' (default: 'au')
});

// Validate credentials
const validation = await client.validateApiKey();
if (!validation.ok) throw new Error(validation.error);

// Get all employees
const empResult = await client.getEmployees();
if (empResult.ok) console.log(empResult.data); // PayrollAuEmployee[]

// Get employees filtered by location
const filteredResult = await client.getEmployees({ locationId: 5 });
if (filteredResult.ok) console.log(filteredResult.data); // PayrollAuEmployee[]

// Get roster shifts for a date range (auto-paginates)
const rosterResult = await client.getRosterShifts('2026-02-03', '2026-02-09');
if (rosterResult.ok) console.log(rosterResult.data); // PayrollRosterShift[]

// Get roster shifts with filters
const pubResult = await client.getRosterShifts('2026-02-03', '2026-02-09', {
  employeeId: 42,
  shiftStatus: 'Published',
  selectAllRoles: true
});
if (pubResult.ok) console.log(pubResult.data); // PayrollRosterShift[]

// Get leave requests for a date range (all filters server-side)
const leaveResult = await client.getLeaveRequests({
  fromDate: '2026-01-01',
  toDate: '2026-03-31',
  status: 'Approved',
});
if (leaveResult.ok) console.log(leaveResult.data); // PayrollLeaveRequest[]

// Get business locations
const locResult = await client.getLocations();
if (locResult.ok) console.log(locResult.data); // PayrollLocation[]

// List kiosks
const kioskResult = await client.getKiosks();
if (kioskResult.ok) console.log(kioskResult.data); // PayrollKiosk[]

// Get kiosk staff (time and attendance)
const staffResult = await client.getKioskStaff(kioskId);
if (staffResult.ok) console.log(staffResult.data); // PayrollKioskEmployee[]

// Get employee groups
const groupResult = await client.getEmployeeGroups();
if (groupResult.ok) console.log(groupResult.data); // PayrollEmployeeGroup[]

// Get standard hours for an employee (includes FTE value)
const hoursResult = await client.getStandardHours(employeeId);
if (hoursResult.ok) console.log(hoursResult.data); // PayrollStandardHours

// Get leave balances for an employee
const balanceResult = await client.getEmployeeLeaveBalances(employeeId);
if (balanceResult.ok) console.log(balanceResult.data); // PayrollLeaveBalance[]

Result Pattern

All methods return Result<T> — see api-core Result Pattern. Always check ok before accessing data.

API Reference

| Method | Parameters | Returns | |--------|-----------|---------| | validateApiKey() | — | Result<void> | | getEmployees(options?) | PayrollEmployeeOptions? | Result<PayrollAuEmployee[]> | | getEmployee(employeeId) | number | Result<PayrollAuEmployee> | | getEmployeeImage(employeeId) | number | Result<PayrollEmployeeImage> | | getStandardHours(employeeId) | number | Result<PayrollStandardHours> | | getEmployeeLeaveBalances(employeeId, options?) | number, PayrollLeaveBalanceOptions? | Result<PayrollLeaveBalance[]> | | getUnavailabilities(options?) | PayrollUnavailabilityOptions? | Result<PayrollUnavailability[]> | | getLocations() | — | Result<PayrollLocation[]> | | getEmployeeGroups() | — | Result<PayrollEmployeeGroup[]> | | getPublicHolidays(options?) | PayrollPublicHolidayOptions? | Result<PayrollPublicHoliday[]> | | getWorkTypes() | — | Result<PayrollWorkType[]> | | getLeaveCategories() | — | Result<PayrollLeaveCategory[]> | | getRosterShifts(from, to, options?) | string, string, PayrollRosterShiftOptions? | Result<PayrollRosterShift[]> | | getKiosks() | — | Result<PayrollKiosk[]> | | getKioskStaff(kioskId, options?) | number, PayrollKioskStaffOptions? | Result<PayrollKioskEmployee[]> | | getLeaveRequests(options?) | PayrollLeaveRequestOptions? | Result<PayrollLeaveRequest[]> | | getEmployeeLeaveRequests(employeeId, options?) | number, PayrollEmployeeLeaveRequestOptions? | Result<PayrollLeaveRequest[]> | | clearCache() | — | void | | invalidateEmployeeCache() | — | void | | invalidateLeaveRequestCache() | — | void | | invalidateRosterShiftCache() | — | void | | invalidateLocationCache() | — | void | | invalidateKioskCache() | — | void |

getLeaveRequests()

Returns leave requests with all filters applied server-side. The business-level endpoint returns a flat array — no pagination.

Leave requests are time-series data — unlike employees and locations which remain relatively stable, leave requests grow continuously. Always use fromDate/toDate filters to bound the result set.

PayrollLeaveRequestOptions:

| Option | Type | Description | |--------|------|-------------| | fromDate | string | Start date filter (YYYY-MM-DD) | | toDate | string | End date filter (YYYY-MM-DD) | | status | PayrollLeaveRequestStatus | 'Approved', 'Pending', 'Rejected', or 'Cancelled' | | employeeId | number | Filter by employee ID | | leaveCategoryId | number | Filter by leave category ID | | locationId | number | Filter by location ID | | groupBy | 'Employee' \| 'LeaveType' | Group results by employee or leave type | | restrictOverlappingLeave | boolean | Restrict results to leave overlapping the date range |

getEmployeeLeaveRequests()

Returns leave requests for a specific employee using the per-employee endpoint with OData pagination.

PayrollEmployeeLeaveRequestOptions:

| Option | Type | Description | |--------|------|-------------| | status | PayrollLeaveRequestStatus | 'Approved', 'Pending', 'Rejected', or 'Cancelled' | | fromDate | string | Start date filter (ISO 8601) | | toDate | string | End date filter (ISO 8601) |

getEmployeeLeaveBalances()

Returns the accrued leave balance per category for an employee. The balance is the "live" value calculated from pay runs — updated after each pay run is processed. Supports an optional asAtDate parameter for point-in-time balance queries.

PayrollLeaveBalanceOptions:

| Option | Type | Description | |--------|------|-------------| | asAtDate | string | Point-in-time date for balance query (ISO 8601 date-time) |

getUnavailabilities()

Returns unavailability records for the business. The endpoint returns a flat array (not paginated).

Unavailabilities are time-series data — always use fromDate/toDate filters to bound the result set.

PayrollUnavailabilityOptions:

| Option | Type | Description | |--------|------|-------------| | fromDate | string | Start date filter (YYYY-MM-DD) | | toDate | string | End date filter (YYYY-MM-DD) | | employeeId | number | Filter by employee ID | | defaultLocationId | number | Filter by default location ID |

getPublicHolidays()

Returns public holidays for the business.

PayrollPublicHolidayOptions:

| Option | Type | Description | |--------|------|-------------| | year | number | Filter by year |

getWorkTypes()

Returns all work types for the business. Automatically paginates through all results.

getLeaveCategories()

Returns all leave categories for the business. Automatically paginates through all results.

getRosterShifts()

Automatically paginates through all results (100 per page). Returns the complete set of roster shifts for the requested date range. All filter options are applied server-side, reducing the number of results and pages fetched.

Query Parameter Casing

The KeyPay Swagger spec uses inconsistent query parameter casing across endpoints. Roster shifts and leave requests use PascalCase (EmployeeId, ShiftStatus, FromDate), while other endpoints use camelCase (selectedColumns, filter.locationId). The library accepts camelCase options throughout and converts to PascalCase internally where needed.

Configuration

const client = new PayrollClient({
  apiKey: 'your-api-key',       // Required: used as Basic Auth username
  businessId: 12345,            // Required: business ID
  region: 'au',                 // Optional: au, nz, uk, sg, my (default: au)
  baseUrl: '...',               // Optional: override base URL (takes priority over region)
  rateLimitPerSecond: 5,        // Optional: rate limit (default 5, set 0 to disable)
  onRequest: ({ method, url, description }) => { ... },  // Optional: debug callback
  cache: {},                    // Optional: enable TTL caching (defaults below)
  cacheInstance: cache,         // Optional: custom cache backend (e.g., LayeredCache)
  retry: {                      // Optional: retry on 429/503
    maxRetries: 3,
    initialDelayMs: 1000,
    maxDelayMs: 10000,
  },
});

PayrollConfig extends ClientConfig from api-core, which provides the baseUrl, onRequest, retry, and cacheInstance fields. apiKey, businessId, region, cache, and rateLimitPerSecond are payroll-specific. Pass cacheInstance to use a custom cache backend (e.g., LayeredCache with persistent stores); otherwise cache: {} creates an in-memory TTLCache. Set persistRestricted: false to keep restricted-tier data in memory only.

Cache TTLs

| Cache Key | Default TTL | |-----------|-------------| | Employees | 5 min | | Locations | 5 min | | Employee groups | 5 min | | Standard hours | 5 min | | Roster shifts | 2 min | | Leave requests | 2 min | | Kiosks | 5 min | | Kiosk staff | 1 min |

Failed API results (ok: false) are never cached — transient errors won't persist for the full TTL. See the root README Cache System section for the full cache architecture (layered stores, restricted data handling, request coalescing).

Rate Limiting

The client enforces a sliding-window rate limit of 5 requests per second (the API limit). All outbound requests pass through the rate limiter automatically. Set rateLimitPerSecond: 0 in config to disable (useful for tests). The RateLimiter class is provided by api-core and operates per-instance (see Known Limitations in the root README).

Retry

Automatically retries on HTTP 429 (Too Many Requests) and 503 (Service Unavailable) with exponential backoff. Respects the Retry-After header when present.

Authentication

Uses HTTP Basic Authentication with the API key as the username and an empty password, per the KeyPay API reference.

License

MIT