API Reference
Complete REST API documentation. All endpoints are under /api/v1/ and require authentication unless noted. Swagger UI available at /docs in development mode.
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /health | Full health check (DB + Redis status, uptime, version) | None |
| GET | /ready | Kubernetes readiness probe | None |
| GET | /live | Kubernetes liveness probe | None |
| GET | / | API root info (name, version, links) | None |
| GET | /docs | Swagger UI (dev only) | None |
| GET | /metrics | Prometheus metrics | None |
Full health check (DB + Redis status, uptime, version)
Auth: None
Kubernetes readiness probe
Auth: None
Kubernetes liveness probe
Auth: None
API root info (name, version, links)
Auth: None
Swagger UI (dev only)
Auth: None
Prometheus metrics
Auth: None
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/auth/me | Current user with session and tenant info | Required |
| GET | /api/v1/auth/tenants | List user's accessible tenants | Required |
| POST | /api/v1/auth/switch-tenant | Switch active tenant context | Required |
| GET | /api/v1/auth/mfa/backup-codes/status | MFA backup code count | Required |
| POST | /api/v1/auth/mfa/backup-codes/regenerate | Regenerate 10 MFA backup codes | Required |
Current user with session and tenant info
Auth: Required
List user's accessible tenants
Auth: Required
Switch active tenant context
Auth: Required
MFA backup code count
Auth: Required
Regenerate 10 MFA backup codes
Auth: Required
Note: Better Auth handles standard auth routes (sign-in, sign-up, sign-out, MFA setup, password reset) at /api/auth/*
| Method | Path | Description | Permission |
|---|---|---|---|
| GET | /api/v1/hr/stats | Dashboard statistics | employees:read |
| GET | /api/v1/hr/org-units | List org units (paginated) | org:read |
| GET | /api/v1/hr/org-units/hierarchy | Full org unit tree | org:read |
| GET | /api/v1/hr/org-units/:id | Get org unit | org:read |
| POST | /api/v1/hr/org-units | Create org unit | org:write |
| PUT | /api/v1/hr/org-units/:id | Update org unit | org:write |
| DELETE | /api/v1/hr/org-units/:id | Soft-delete org unit | org:write |
| GET | /api/v1/hr/positions | List positions | positions:read |
| GET | /api/v1/hr/positions/:id | Get position | positions:read |
| POST | /api/v1/hr/positions | Create position | positions:write |
| PUT | /api/v1/hr/positions/:id | Update position | positions:write |
| DELETE | /api/v1/hr/positions/:id | Delete position | positions:write |
| GET | /api/v1/hr/employees | List employees (paginated) | employees:read |
| GET | /api/v1/hr/employees/by-number/:num | Get by employee number | employees:read |
| GET | /api/v1/hr/employees/:id | Get employee | employees:read |
| POST | /api/v1/hr/employees | Hire employee | employees:write |
| PUT | /api/v1/hr/employees/:id/personal | Update personal info | employees:write |
| PUT | /api/v1/hr/employees/:id/contract | Update contract | employees:write |
| PUT | /api/v1/hr/employees/:id/position | Transfer/promote | employees:write |
| PUT | /api/v1/hr/employees/:id/compensation | Change compensation | compensation:write |
| PUT | /api/v1/hr/employees/:id/manager | Change manager | employees:write |
| POST | /api/v1/hr/employees/:id/status | Status transition | employees:write |
| POST | /api/v1/hr/employees/:id/terminate | Terminate employee | employees:delete |
| POST | /api/v1/hr/employees/:id/rehire | Rehire terminated employee | employees:write |
| PATCH | /api/v1/hr/employees/:id/ni-category | Update NI category | employees:write |
| GET | /api/v1/hr/employees/:id/history/:dimension | Effective-dated history | employees:read |
| GET | /api/v1/hr/employees/:id/statutory-notice | UK ERA s.86 notice period | employees:read |
| GET | /api/v1/hr/employees/:id/addresses | Current addresses | employees:read |
| GET | /api/v1/hr/employees/:id/addresses/history | Address history | employees:read |
| POST | /api/v1/hr/employees/:id/addresses | Create address | employees:write |
| PUT | /api/v1/hr/employees/:id/addresses/:addressId | Update address | employees:write |
| DELETE | /api/v1/hr/employees/:id/addresses/:addressId | Close address | employees:write |
| GET | /api/v1/hr/employees/:id/positions | Concurrent position assignments | employees:read |
| POST | /api/v1/hr/employees/:id/positions | Assign additional position | employees:write |
| DELETE | /api/v1/hr/employees/:id/positions/:id | End position assignment | employees:write |
| GET | /api/v1/hr/org-chart | Org chart (nodes + edges) | org:read |
| GET | /api/v1/hr/org-chart/direct-reports/:id | Direct reports | employees:read |
| GET | /api/v1/hr/org-chart/reporting-chain/:id | Full reporting chain | employees:read |
Dashboard statistics
employees:read
List org units (paginated)
org:read
Full org unit tree
org:read
Get org unit
org:read
Create org unit
org:write
Update org unit
org:write
Soft-delete org unit
org:write
List positions
positions:read
Get position
positions:read
Create position
positions:write
Update position
positions:write
Delete position
positions:write
List employees (paginated)
employees:read
Get by employee number
employees:read
Get employee
employees:read
Hire employee
employees:write
Update personal info
employees:write
Update contract
employees:write
Transfer/promote
employees:write
Change compensation
compensation:write
Change manager
employees:write
Status transition
employees:write
Terminate employee
employees:delete
Rehire terminated employee
employees:write
Update NI category
employees:write
Effective-dated history
employees:read
UK ERA s.86 notice period
employees:read
Current addresses
employees:read
Address history
employees:read
Create address
employees:write
Update address
employees:write
Close address
employees:write
Concurrent position assignments
employees:read
Assign additional position
employees:write
End position assignment
employees:write
Org chart (nodes + edges)
org:read
Direct reports
employees:read
Full reporting chain
employees:read
| Method | Path | Description | Permission |
|---|---|---|---|
| POST | /api/v1/payroll/runs | Create payroll run | payroll:runs:write |
| GET | /api/v1/payroll/runs | List runs | payroll:runs:read |
| GET | /api/v1/payroll/runs/:id | Get run with line items | payroll:runs:read |
| POST | /api/v1/payroll/runs/:id/calculate | Calculate payroll | payroll:runs:write |
| PATCH | /api/v1/payroll/runs/:id/approve | Approve run | payroll:runs:write |
| POST | /api/v1/payroll/runs/:id/export | Export CSV/JSON | payroll:export:read |
| POST | /api/v1/payroll/runs/:id/journal-entries | Generate journal entries | payroll:runs:write |
| GET | /api/v1/payroll/runs/:id/journal-entries | Get journal entries | payroll:runs:read |
| GET | /api/v1/payroll/journal-entries | List journal entries (filtered) | payroll:runs:read |
| PUT | /api/v1/payroll/employees/:id/tax-details | Update tax details | payroll:tax_details:write |
| GET | /api/v1/payroll/employees/:id/tax-details | Get tax details | payroll:tax_details:read |
| GET | /api/v1/payroll/employees/:id/payslips/:runId | Get payslip data | payroll:payslips:read |
| GET | /api/v1/payroll/pay-schedules | List pay schedules | payroll:runs:read |
| POST | /api/v1/payroll/pay-schedules | Create pay schedule | payroll:runs:write |
| GET | /api/v1/payroll/pay-schedules/:id | Get pay schedule | payroll:runs:read |
| PUT | /api/v1/payroll/pay-schedules/:id | Update pay schedule | payroll:runs:write |
| POST | /api/v1/payroll/employees/:id/pay-assignment | Assign to schedule | payroll:runs:write |
| GET | /api/v1/payroll/employees/:id/pay-assignments | List pay assignments | payroll:runs:read |
| POST | /api/v1/payroll/period-locks | Lock payroll period | payroll:runs:write |
| POST | /api/v1/payroll/period-locks/:id/unlock | Unlock period | payroll:runs:write |
| GET | /api/v1/payroll/period-locks | List period locks | payroll:runs:read |
Create payroll run
payroll:runs:write
List runs
payroll:runs:read
Get run with line items
payroll:runs:read
Calculate payroll
payroll:runs:write
Approve run
payroll:runs:write
Export CSV/JSON
payroll:export:read
Generate journal entries
payroll:runs:write
Get journal entries
payroll:runs:read
List journal entries (filtered)
payroll:runs:read
Update tax details
payroll:tax_details:write
Get tax details
payroll:tax_details:read
Get payslip data
payroll:payslips:read
List pay schedules
payroll:runs:read
Create pay schedule
payroll:runs:write
Get pay schedule
payroll:runs:read
Update pay schedule
payroll:runs:write
Assign to schedule
payroll:runs:write
List pay assignments
payroll:runs:read
Lock payroll period
payroll:runs:write
Unlock period
payroll:runs:write
List period locks
payroll:runs:read
| Method | Path | Description | Auth |
|---|---|---|---|
| GET | /api/v1/integrations | List tenant integrations | Required |
| GET | /api/v1/integrations/:id | Get integration | Required |
| POST | /api/v1/integrations/connect | Connect integration | Required |
| PATCH | /api/v1/integrations/:id/config | Update config | Required |
| POST | /api/v1/integrations/:id/disconnect | Disconnect | Required |
| DELETE | /api/v1/integrations/:id | Delete integration | Required |
List tenant integrations
Auth: Required
Get integration
Auth: Required
Connect integration
Auth: Required
Update config
Auth: Required
Disconnect
Auth: Required
Delete integration
Auth: Required
Workforce Management
/api/v1/absence/*Leave requests, policies, types, entitlements/api/v1/time/*Timesheets, shifts, clock-in/out/api/v1/onboarding/*Templates, tasks/api/v1/probation/*Probation tracking/api/v1/equipment/*Equipment management
Talent & Performance
/api/v1/talent/*Reviews, goals, development plans/api/v1/talent-pools/*Talent pool management/api/v1/feedback-360/*360-degree feedback/api/v1/competencies/*Frameworks, assessments/api/v1/succession/*Plans, pools/api/v1/one-to-one/*1:1 meetings/api/v1/recognition/*Recognition & rewards
Recruitment & Learning
/api/v1/recruitment/*Requisitions, candidates, interviews, offers/api/v1/lms/*Courses, learning paths, certificates
Benefits & Compensation
/api/v1/benefits/*Plans, enrollment, nominations/api/v1/pension/*Schemes, enrollment, compliance
Employee Relations
/api/v1/cases/*ER cases, comments, attachments/api/v1/warnings/*Disciplinary warnings/api/v1/whistleblowing/*Whistleblowing reports/api/v1/flexible-working/*Flexible working requests
UK Compliance
/api/v1/ssp/*Statutory Sick Pay/api/v1/family-leave/*Family leave/api/v1/statutory-leave/*Statutory leave/api/v1/nmw/*National Minimum Wage/api/v1/wtr/*Working Time Regulations/api/v1/right-to-work/*Right to work checks/api/v1/gender-pay-gap/*Gender pay gap reporting/api/v1/ir35/*IR35 compliance/api/v1/bank-holidays/*Bank holiday management/api/v1/health-safety/*Health & safety
GDPR & Privacy
/api/v1/dsar/*Data subject access requests/api/v1/data-erasure/*Data erasure requests/api/v1/data-breach/*Breach incident tracking
Automation & Workflows
/api/v1/workflows/*Definitions, instances, tasks/api/v1/approvals/*Approval chains/api/v1/notifications/*Notification management
Platform & Admin
/api/v1/tenant/*Tenant settings/api/v1/security/*Roles, permissions, users, audit log/api/v1/dashboard/*Dashboard data/api/v1/documents/*Upload, download, manage/api/v1/analytics/*Metrics, charts/api/v1/reports/*Dynamic report builder/api/v1/sso/*SAML/OIDC configuration/api/v1/api-keys/*API key management/api/v1/bulk-operations/*Bulk operations/api/v1/data-import/*Data import
Authentication
Two authentication methods are supported. All API endpoints under /api/v1/ require authentication unless explicitly noted.
Session Cookie
The primary method for browser-based clients. After signing in via Better Auth, a session token is set as an HTTP-only cookie.
Cookie: staffora.session_token=eyJhb... - Set automatically by Better Auth on sign-in
- HTTP-only, Secure, SameSite=Lax
- CSRF protection via HMAC-SHA256 double-submit
API Key
For service-to-service and programmatic access. API keys are tenant-scoped, hashed with SHA-256, and managed via the API Keys module.
Authorization: Bearer sfra_live_... -
Prefix:
sfra_for easy identification - Stored as SHA-256 hash (plaintext never persisted)
- Scoped to a single tenant with configurable permissions
Pagination
All collection endpoints use cursor-based pagination for consistent, efficient paging through large result sets.
Request Parameters
cursor string, optional Opaque cursor from previous response. Omit for first page.
limit number, optional Number of items per page (default: 20, max: 100).
GET /api/v1/hr/employees?limit=25&cursor=eyJpZCI6Ij... Response Shape
{
"data": [ ... ],
"pagination": {
"hasMore": true,
"nextCursor": "eyJpZCI6Ij...",
"prevCursor": "eyJpZCI6Ij..."
}
} - No offset drift -- consistent across concurrent writes
- Efficient index-based seeking (no OFFSET scans)
Rate Limiting
Redis-backed rate limiting protects the API from abuse while providing clear feedback via response headers.
Response Headers
X-RateLimit-Limit Maximum requests allowed in the current window.
X-RateLimit-Remaining Number of requests remaining in the current window.
X-RateLimit-Reset Unix timestamp (seconds) when the rate limit window resets.
When a rate limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header indicating seconds until the next request can be made.
Error Response Format
All errors follow a consistent shape with machine-readable codes and a request ID for debugging.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request body",
"details": [
{ "field": "email", "message": "Must be a valid email" }
],
"requestId": "req_01HXYZ..."
}
} 400 Validation / bad request 401 Not authenticated 403 Insufficient permissions 404 Resource not found 409 Conflict / duplicate 429 Rate limit exceeded 500 Internal server error 503 Service unavailable