REST API
Klees public REST API — authentication, rate limits, endpoint reference, webhooks, and the integration patterns most customers use for custom payroll and HR workflows.
Updated May 29, 2026
Klees ships a REST API that mirrors what the apps do. Every action a manager can take in the UI is available programmatically. The API is the integration layer for custom payroll, HR, BI warehouses, and bespoke field-ops workflows. For the related security model, see Security and Compliance.
Base URL and versioning
https://api.klees.app/v1
The API is versioned at the path level. Breaking changes ship as v2. Non-breaking additions (new fields, new endpoints) ship within the current major version.
All endpoints return JSON with a consistent envelope:
{
"data": { },
"meta": {
"request_id": "req_01HZ...",
"took_ms": 24
}
}
Errors:
{
"error": {
"code": "unauthorized",
"message": "Invalid or expired token",
"request_id": "req_01HZ..."
}
}
Authentication
The API uses bearer tokens. From Settings → API Keys, an Admin or Owner creates a token with a label, optional expiration, and a scope (read-only, read-write, or resource-scoped).
GET /v1/workers
Authorization: Bearer kl_live_abc123...
Accept-Language: en-US
Tokens are shown once at creation — store them in your secret manager. Rotation is zero-downtime (create new, revoke old). Every API call is recorded in the audit log. OAuth 2.0 is available on Enterprise.
Rate limits
| Tier | Per-second | Per-minute | Per-day |
|---|---|---|---|
| Standard | 5 | 300 | 50,000 |
| Pro | 10 | 600 | 200,000 |
| Enterprise | Negotiated | Negotiated | Unlimited (fair use) |
Rate limit headers ship on every response:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 587
X-RateLimit-Reset: 1748736000
A 429 response includes Retry-After in seconds. Clients should implement exponential backoff with jitter.
Common endpoints
A non-exhaustive list of the most-used endpoints:
| Method | Path | Purpose |
|---|---|---|
GET | /v1/workers | List workers (paginated) |
GET | /v1/workers/{id} | Worker detail |
POST | /v1/workers | Create a worker (invite) |
GET | /v1/jobs | List jobs |
POST | /v1/jobs | Create a job |
GET | /v1/jobs/{id} | Job detail with geofence and budget |
GET | /v1/time-entries | List time entries (filterable by date, worker, job, status) |
POST | /v1/time-entries/{id}/approve | Approve a time entry |
POST | /v1/time-entries/{id}/reject | Reject with note |
GET | /v1/customers | List customers |
GET | /v1/reports/job-costing | Job costing report (JSON or CSV) |
POST | /v1/exports/payroll | Trigger a payroll export |
GET | /v1/audit-log | Audit log entries |
Full reference with request and response shapes lives at https://api.klees.app/docs.
Pagination and filtering
Listing endpoints accept limit (default 50, max 200) and cursor. Most accept filter parameters that mirror the UI:
GET /v1/time-entries?from=2026-05-01&to=2026-05-31&status=approved&worker_id=W001
Multiple values on a single filter use comma separation. Date filters accept ISO-8601.
Webhooks
Klees can push events to your HTTP endpoint. From Settings → Webhooks, register a URL and pick which events you want.
Common events:
time_entry.created— a worker clocked in or outtime_entry.approved— a manager approvedtime_entry.flagged_pinshot_low— PinShot scored below thresholdtime_entry.flagged_outside_fence— worker clocked in outside the job geofencejob.createdjob.budget_threshold— job crossed 75/100/110% of budgetschedule.publishedpayroll.export_completed
Webhook delivery uses signed requests:
POST /your-handler HTTP/1.1
Host: your-app.example.com
Content-Type: application/json
X-Klees-Signature: t=1748736000,v1=abc123...
X-Klees-Event: time_entry.flagged_pinshot_low
{
"event": "time_entry.flagged_pinshot_low",
"data": { "time_entry_id": "te_01HZ...", "score": 42 },
"occurred_at": "2026-05-30T14:23:11Z"
}
Verify signatures using the secret shown when you registered the webhook. Klees retries failed deliveries with exponential backoff over 24 hours.
Common integration patterns
Custom payroll handoff — if your provider isn’t on the direct sync list, subscribe to time_entry.approved, fetch the detail, map to your provider’s schema, push. Shifts the heavy lift to the webhook side and stays close to real-time.
BI warehouse sync — nightly call /v1/time-entries, /v1/jobs, /v1/customers, and /v1/audit-log for the previous day; land in raw tables. Most customers use Fivetran or Airbyte against the REST API.
Custom Live Map embed — the /v1/positions/live endpoint streams worker positions with the same 60-second delay as the Live Map UI. Enterprise only.
Status, SDKs
API status and incident postmortems live at https://status.klees.app. Official SDKs: Node.js (@klees/sdk-node), Python (klees-sdk), Ruby (klees). Community SDKs for Go, PHP, and .NET are listed in the API portal. All SDKs handle auth, retries, and pagination cursors.