KPI Matrix How-to Guide Public

KPI Matrix — API

KPI Matrix — API The KPI Matrix module exposes two JSON APIs, both built on ERPat's stateless JWT-bearer surfaces and both reusing the module's src/Services/* (the same business…

Guide version: r1 Module version: 1.4.0 Updated: 2026-07-22 Estimated time: 3 min 2 views

The KPI Matrix module exposes two JSON APIs, both built on ERPat's stateless JWT-bearer surfaces and both reusing the module's src/Services/* (the same business logic the web controllers use). All data access goes through models; every response row is projected through the kpi_api_shape_*() helpers (helpers/kpi_matrix_helper.php) — no internal columns, display names only.

Shared response envelope (from App\Core\ApiController / EndUserApiController):

// success
{ "ok": true, "data": { /* ... */ } }
// error
{ "ok": false, "error": { "code": "<snake_case>", "message": "<human>", "details": {} } }

1. Client (Integration) API — /api/v1/kpi/*

  • Controller: controllers/Kpi_matrix_api.php (extends App\Core\ApiAuthController)
  • Audience: external/programmatic systems (reporting/BI).
  • Auth: OAuth-style bearer JWT + X-Company-Key (tenant). Scope kpi:read (declared in config/api_scope.php, granted per API client).
  • Capability: READ-ONLY.
  • Routes: config/api_routes.php · Spec: public/api/v1/openapi.json (php erpat api:openapi --postman).
Method & path Purpose
GET /api/v1/kpi/cycles Review cycles (with template name + counts)
GET /api/v1/kpi/cycles/{id} A single cycle
GET /api/v1/kpi/templates KPI templates
GET /api/v1/kpi/templates/{id} A single template plus its weighted metrics
GET /api/v1/kpi/results?cycle_id= Composite results for a cycle (defaults to the active cycle)
GET /api/v1/kpi/employees/{id}/scores?cycle_id= One employee's scores + composite in a cycle
GET /api/v1/kpi/salary-recommendations?cycle_id=&status= Salary recommendations

A missing record returns 404 kpi_not_found; a missing/insufficient scope returns 403 forbidden (handled by authorizeScope).


2. End-User API — /v1/api/kpi/*

  • Controller: controllers/Kpi_matrix_euapi.php (extends App\Core\EndUserApiAuthController)
  • Audience: the authenticated employee (first-party self-service / mobile).
  • Auth: stateless HS256 JWT; identity is the employee users.id in the JWT sub, resolved self-only via selfUserId() — a request-supplied user id is never trusted.
  • Gating: requireModule('module_kpi_matrix') (404 module_unavailable when the tenant has the module off) and requirePermit('kpi_matrix') (KPI is a permissioned HR feature, matching the web "My KPIs" access model).
  • Capability: READ-ONLY, SELF-ONLY. GET only (405 otherwise).
  • Routes: config/euapi_routes.php · Spec: public/v1/api/openapi.json (php erpat euapi:openapi --postman).
Method & path Purpose
GET /v1/api/kpi/my/scores?cycle_id= My scores by category + composite (active cycle by default)
GET /v1/api/kpi/my/history My composite-score trend
GET /v1/api/kpi/my/assignments My KPI assignments
GET /v1/api/kpi/my/results/{cycle_id} My finalized results for a cycle (404 if none)
GET /v1/api/kpi/my/salary-recommendation?cycle_id= My salary recommendation(s)

Design

  • No logic duplication. Both controllers delegate to the same services (CycleService, TemplateService, OverviewAnalyticsService, EmployeeKpiService, SalaryRecommendationService) that the web controllers use. The controllers only handle transport (auth + request parsing + envelope).
  • Projection. Rows never leave a model raw — kpi_api_shape_*() casts with null-coalescing, exposes display names only (no PII/email), and turns a rating_band key into a {key,label,color} object via the module's rating-band config.
  • Regeneration. After changing routes/endpoints run php erpat api:openapi --postman and php erpat euapi:openapi --postman, and keep module.json api.endpoints[] in sync.
Was this guide helpful?

Report a content problem