Build on BimHR Solutions
Authenticate with API keys, list and create employees, submit leave requests, and receive signed webhook events for payroll, leave, and onboarding workflows.
Authentication
All v1 API requests must include an Authorization: Bearer header with a valid BIMHR API key. Keys are issued by the company owner from Settings → API Keys and have the prefix bimhr_live_.
The full key is shown to the owner exactly once at creation time. Only the SHA-256 hash is stored — if you lose the key, you must revoke and reissue it.
The key's company_id becomes the implicit tenant scope for every request. A key issued for company A can neverread or write company B's data, even if the request URL is identical.
Authorization: Bearer bimhr_live_<your_key>
Scopes
Each API key has a set of scopes that determine which endpoints it can access. An empty scopes array means all scopes — useful for first-party integration keys. Recognized scopes:
- employees:read
- employees:write
- leave:read
- leave:write
- payroll:read
- payroll:write
- webhooks:read
Endpoints
Employees
List, create, fetch, and update employee records. The API key's company_id becomes the implicit tenant scope — a key issued for company A can NEVER read or write company B's employees.
/api/v1/employeesemployees:readList employees for the API key's company (up to 200, newest first).
/api/v1/employeesemployees:writeCreate a new employee record (lightweight — no auth invite or compensation profile).
/api/v1/employees/{id}employees:readFetch a single employee by id. Returns 404 if the employee is in a different company.
/api/v1/employees/{id}employees:writeUpdate fields on an employee (first_name, last_name, email, job_title, etc.).
Leave
List leave requests and submit new ones on behalf of an employee. New requests are created with status='pending' so they flow through your normal approval chain.
/api/v1/leaveleave:readList leave requests. Filter with ?employee_id= and/or ?status=.
/api/v1/leaveleave:writeSubmit a new leave request on behalf of an employee.
Payroll
List payroll runs (metadata only — never individual payslip lines). Use the in-app UI to drill into a specific run.
/api/v1/payrollpayroll:readList payroll runs. Filter with ?status=, paginate with ?limit= (max 200).
Webhooks
List webhook delivery history for the API key's company. Useful for integration monitoring.
/api/v1/webhookswebhooks:readList webhook deliveries. Filter with ?endpoint_id=, ?status=, ?limit=.
Webhooks
When an event happens inside BIMHR (leave approved, payroll completed, employee onboarded, etc.), BIMHR fires an HTTP POST to each registered webhook endpoint. Register endpoints from Settings → Webhooks.
Event types
An endpoint with an empty events array subscribes to ALL event types.
employee.createdFired when a new employee is onboarded.
employee.terminatedFired when an employee is marked terminated.
leave.requestedFired when an employee submits a leave request.
leave.approvedFired when a leave request is approved.
leave.rejectedFired when a leave request is rejected.
timesheet.submittedFired when an employee submits a timesheet.
timesheet.approvedFired when a timesheet is approved.
payroll.completedFired when a payroll run finishes generating payslips.
payroll.approvedFired when a payroll run is approved/finalised.
advance.requestedFired when an employee requests an advance.
advance.approvedFired when an advance request is approved.
document.uploadedFired when a document is uploaded for an employee.
contract.signedFired when a contract is fully signed by both parties.
onboarding.completedFired when an employee's onboarding checklist is complete.
Payload reference
The POST body is a JSON object with the following shape:
{
"event": "leave.approved",
"delivered_at": "2026-07-28T12:34:56.789Z",
"delivery_id": "uuid",
"payload": {
"requestId": "uuid",
"employeeId": "uuid"
}
}Verifying the signature
Every POST includes an X-Webhook-Signatureheader containing the hex-encoded HMAC-SHA256 of the raw request body, keyed by the endpoint's secret. Verify it before processing:
import { createHmac } from "crypto";
// Read raw body BEFORE any JSON parsing.
const rawBody = await request.text(); // or: request.body in Python
const signature = request.headers.get("X-Webhook-Signature");
const expected = createHmac("sha256", WEBHOOK_SECRET)
.update(rawBody, "utf8")
.digest("hex");
if (signature !== expected) {
return new Response("Invalid signature", { status: 401 });
}
// Signature is valid — safe to parse + act on the payload.
const event = JSON.parse(rawBody);
console.log(event.event, event.payload);Retry policy
Failed deliveries are retried up to 5 times with exponential backoff (1s, 2s, 4s, 8s, 16s). After all attempts fail, the delivery is marked failed and the owner can manually retry it from the Webhooks settings tab.
Rate limits
API requests are rate-limited per IP at 60 requests per minute. When the limit is exceeded, the API responds with HTTP 429 and aRetry-Afterheader indicating when to retry.
For higher limits (batch imports, real-time integrations), contact support to discuss a dedicated rate-limit tier.
Code examples
A minimal example: list the employees for the API key's company.
curl
curl -X GET https://your-bimhr-domain.com/api/v1/employees \ -H "Authorization: Bearer bimhr_live_<your_key>" \ -H "Accept: application/json"
javascript
const res = await fetch("https://your-bimhr-domain.com/api/v1/employees", {
method: "GET",
headers: {
"Authorization": "Bearer bimhr_live_<your_key>",
"Accept": "application/json",
},
});
const data = await res.json();
console.log(data.employees);python
import requests
res = requests.get(
"https://your-bimhr-domain.com/api/v1/employees",
headers={
"Authorization": "Bearer bimhr_live_<your_key>",
"Accept": "application/json",
},
)
print(res.json()["employees"])Ready to integrate?
Sign in as the company owner, head to Settings → API Keys, and issue your first key.
Go to Settings →