Developers
Build on Mawro with an open REST API
Workspace API keys with scopes, signed webhooks and 38 documented endpoints for employees, organisation data, attendance, leave and payroll, with JSON responses, predictable errors and an OpenAPI 3.1 file you can import anywhere.
- Base URL
https://mawro.neuroskill.tech/api/v1 - Authentication
API key (Bearer mk_live_…) on /ext; user JWT elsewhere - Versioning
In the path: /api/v1 - Rate limits
120 / minute per API key by default; 600 / minute per signed-in user
Quickstart
Your first call in three steps
- 1Create an API keyAn administrator opens Settings › Integrations › API keys, names the key, ticks only the scopes it needs (for example "Send attendance punches") and can set an expiry. The key is shown once; Mawro keeps only a hash of it.
- 2Call the external APISend the key as Authorization: Bearer mk_live_… to the /ext endpoints. A key never sees more than the person who created it, and every call is audited.
- 3Subscribe to webhooksAdd an https endpoint under Settings › Integrations › Webhooks and pick events such as employee.hired or payroll.run_approved. Every delivery is signed, so you can check it came from Mawro.
Common integrations
What teams build first
Attendance devices
Post punches from any terminal or time system with an API key, with an idempotency key so retries never double-count.
POST /ext/attendance/punches/batch Payroll and accounting
Read approved payroll runs and each run's results per employee and component; amounts only when the key's creator may see salaries.
GET /ext/payroll/runs/{id}/export HR data sync
Page through employees changed since your last sync, and let the employee.* webhooks tell you when to sync again.
GET /ext/employees Responses
One envelope, predictable errors
- Successful responses return the result under data, with a correlation ID and server timestamp under meta.
- Errors return a stable key, an HTTP status and field-level details you can show to users.
- Timestamps are ISO-8601 in UTC. Lists are paged or capped; see each endpoint.
- Quote the correlation ID (also in the X-Correlation-Id header) when you contact support.
{
"data": {
"rows": [
{
"id": "7d1c…",
"displayName": "Ana Santos",
"employeeNumber": "EMP-000214"
}
],
"total": 1,
"page": 1,
"pageSize": 25
},
"meta": {
"correlationId": "b6f0c2a4-…",
"timestamp": "2026-10-18T09:15:02.114Z"
}
}{
"error": {
"key": "CFG-001",
"type": "ERROR",
"message": "Validation failed.",
"statusCode": 422,
"correlationId": "b6f0c2a4-…",
"timestamp": "2026-10-18T09:15:02.114Z",
"path": "/api/v1/attendance/punches/batch",
"details": [
{
"field": "events[0].eventAt",
"key": "CFG-001",
"message": "Must be an ISO-8601 timestamp.",
"severity": "ERROR"
}
]
}
}Webhooks
Events pushed to your systems, signed
Each delivery is a JSON POST of { id, type, createdAt, data } with X-Mawro-Event, X-Mawro-Delivery, X-Mawro-Timestamp and X-Mawro-Signature headers. A 2xx answer within 10 seconds counts as delivered; otherwise Mawro retries up to 8 times with growing gaps, keeps a delivery log you can redeliver from, and pauses an endpoint after 20 failures in a row. Endpoints must be public https addresses; private and internal addresses are refused.
employee.hiredAn employment record became active (direct hire or onboarding go-live).employee.updatedA fact on an employee record was written, or the employment status changed.employee.terminatedAn exit was completed and the employment ended.leave.approvedA leave request was approved.attendance.publishedAn attendance period was locked: its figures are final for payroll.payroll.run_approvedA payroll run was approved.onboarding.completedAn onboarding case was completed.offboarding.completedAn exit case was completed.
import { createHmac, timingSafeEqual } from 'node:crypto';
// Express: app.post('/hooks/mawro', express.raw({ type: '*/*' }), handler)
function fromMawro(req, secret) {
const ts = req.get('X-Mawro-Timestamp');
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const expected = 'v1=' + createHmac('sha256', secret)
.update(ts + '.' + req.body).digest('hex');
return req.get('X-Mawro-Signature').split(',').some((s) =>
s.trim().length === expected.length &&
timingSafeEqual(Buffer.from(s.trim()), Buffer.from(expected)));
}The signature is HMAC-SHA256 of "timestamp.body" with your endpoint secret (shown once, and rotatable). During a rotation the header can carry two signatures.
Reference
Browse the endpoints
Authentication
4 endpoints
- POST
/auth/login - POST
/auth/refresh - POST
/auth/logout - GET
/auth/me
Employees
5 endpoints
- GET
/employees/directory - POST
/employees - GET
/employees/{id} - GET
/employees/{id}/facts/{factKey}
Organization
2 endpoints
- GET
/config/{entity} - GET
/config/{entity}/{id}
Attendance
5 endpoints
- POST
/attendance/punches/batch - GET
/attendance/punches - GET
/attendance/punches/exceptions - GET
/attendance/devices/silent
Leave
6 endpoints
- GET
/leave/types/available - GET
/leave/balances - GET
/leave/requests - POST
/leave/requests
Payroll
8 endpoints
- GET
/payroll/runs - GET
/payroll/runs/{id} - GET
/payroll/journals - GET
/payroll/journals/{id}
External API
8 endpoints
- GET
/ext/me - GET
/ext/employees - GET
/ext/employees/{id} - GET
/ext/attendance/punches
Give each integration its own API key with only the scopes it needs. Endpoints outside /ext take a user session token from POST /auth/login, for tools that act as a signed-in person. Integrations
See Mawro running on your own processes
Book a 30-minute walkthrough with our team, or start a free trial and invite your HR team today.