API reference

Mawro HRMS API

The Mawro HRMS REST API for integrations: employee and organization data, attendance capture from any device, leave, and payroll journals for your ERP.

  • Base URL: https://mawro.neuroskill.tech/api/v1
  • Authentication: POST /auth/login returns a JWT access token; send it as Authorization: Bearer <token>. Refresh it with POST /auth/refresh. Use a dedicated integration user: it sees and does only what its role allows.
  • API keys: server-to-server integrations can use the /ext endpoints with a workspace API key (Authorization: Bearer mk_live_…), limited to the scopes it was given and to 120 requests per minute per key by default.
  • Responses: JSON bodies are wrapped as { "data": …, "meta": { "correlationId", "timestamp" } }. File downloads are returned as files. Errors use { "error": { "key", "message", "statusCode", "details", … } }.
  • Dates: timestamps are ISO 8601 in UTC; business dates are YYYY-MM-DD.
  • Idempotency: punch batches carry an idempotencyKey; re-sending it returns the original result.
  • Rate limits: 600 requests per minute per client; sign-in and token refresh 20 per minute. Exceeding them returns 429.
Base URLhttps://mawro.neuroskill.tech/api/v1

Authentication

Sign in, refresh and inspect the session.

Sign in

POST/auth/loginNo auth

Exchanges a username and password for an access token, a refresh token and the session. Use a dedicated integration user whose role grants only the permissions your integration needs. Limited to 20 attempts per minute per client address.

Request body application/json

usernamerequiredstring
passwordrequiredstring
tenantCodestring

Needed only when signing in through the shared host.

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/auth/login" \
  -H "Content-Type: application/json" \
  -d '{
  "username": "integration.payroll",
  "password": "••••••••",
  "tenantCode": "ACME"
}'
Request example
{
  "username": "integration.payroll",
  "password": "••••••••",
  "tenantCode": "ACME"
}
201Response
{
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…",
    "refreshToken": "rt_9f3c1a…",
    "expiresIn": 3600,
    "session": {
      "user": {
        "id": "f0b1c2d3-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
        "username": "integration.payroll",
        "email": "integration@acme.example",
        "displayName": "Payroll integration",
        "locale": "en",
        "timeZone": "UTC"
      },
      "tenant": {
        "id": "c7d8e9f0-1a2b-4c3d-8e4f-5a6b7c8d9e0f",
        "tenantNumber": "T-0042",
        "displayName": "Acme Hospitality",
        "countryCode": "US",
        "baseCurrency": "USD",
        "timeZone": "America/New_York",
        "enabledModules": [
          "EMPLOYEE_MASTER",
          "ATTENDANCE_TIME",
          "LEAVE",
          "PAYROLL"
        ]
      },
      "activeRoleContextId": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e",
      "permissions": [
        "PAY_GL:VIEW",
        "PAY_GL:EXPORT",
        "PAY_AMOUNT:VIEW"
      ]
    }
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Refresh the access token

POST/auth/refreshNo auth

Exchanges a refresh token for a new access token and refresh token. Each refresh token works once; keep the new one. Limited to 20 attempts per minute per client address.

Request body application/json

refreshTokenrequiredstring

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/auth/refresh" \
  -H "Content-Type: application/json" \
  -d '{
  "refreshToken": "rt_9f3c1a…"
}'
Request example
{
  "refreshToken": "rt_9f3c1a…"
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
422Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "Enter the joining date, e.g. 2024-03-01.",
    "statusCode": 422,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…",
    "details": [
      {
        "field": "joiningDate",
        "key": "CFG-001",
        "message": "Enter the joining date, e.g. 2024-03-01.",
        "severity": "ERROR"
      }
    ]
  }
}

Sign out

POST/auth/logout

Revokes the given refresh token (or the caller's tokens). The access token stays valid until it expires.

Request body application/json

refreshTokenstring

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/auth/logout" \
  -H "Authorization: Bearer $MAWRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "refreshToken": "rt_9f3c1a…"
}'
Request example
{
  "refreshToken": "rt_9f3c1a…"
}
201Response
{
  "data": {
    "success": true
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Current session

GET/auth/me

Returns the signed-in identity, tenant, role contexts and resolved permission codes. Useful to check what an integration user is allowed to do.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/auth/me" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Employees

The employee directory, records and dated facts.

List employees

GET/employees/directory

Employees the caller may see, paged, filtered and sorted. Returns directory columns only; identity, pay and bank data are on the record behind their own field security. Requires EMPLOYEE_DIRECTORY:VIEW.

Parameters

searchstring · query

Matches employee code and names; every word must match.

statusstring · query

An employment status, or CURRENT for everyone still employed.

legalEntityIdstring (uuid) · query

Only this legal entity.

departmentIdstring (uuid) · query

Only people currently in this department.

pageinteger · query

1-based page number.

pageSizeinteger · query

Rows per page.

sortBystring · query

Sort column.

employeeCodenamestatusjoiningDate
sortDirstring · query

Sort direction.

ascdesc

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/employees/directory" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": {
    "rows": [
      {
        "id": "3b8f0d6e-91c4-4b1f-8a62-5d0c7e2f4a19",
        "employeeCode": "EMP-000214",
        "givenName": "Ana",
        "familyName": "Santos",
        "givenNameAr": null,
        "familyNameAr": null,
        "photoAttachmentId": null,
        "status": "ACTIVE_CONFIRMED",
        "readiness": "ACTIVE",
        "joiningDate": "2023-03-12T00:00:00.000Z",
        "exitDate": null,
        "legalEntityCode": "LE-MAIN",
        "jobCode": "SUP-RST",
        "jobTitle": "Restaurant Supervisor",
        "workingTitle": null,
        "departmentCode": "OPS",
        "departmentName": "Operations",
        "locationCode": "DT",
        "locationName": "Downtown Branch",
        "managerPeriodId": "9c2e4f71-0b8a-4d3e-a6f5-17d2c9e0b384",
        "managerName": "Fatima Hajri"
      }
    ],
    "total": 1,
    "page": 1,
    "pageSize": 25
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Create an employee (draft)

POST/employees

Creates one person and one employment period in DRAFT, after a duplicate check. A high-risk duplicate blocks with 409 until a reviewer lists the cleared person IDs in acknowledgedDuplicateIds. Requires EMPLOYMENT_PERIOD:CREATE.

Request body application/json

givenNamerequiredstring
middleNamestring | null
familyNamerequiredstring
givenNameArstring | null
familyNameArstring | null
dateOfBirthstring | null (date)
genderstringMALEFEMALEUNSPECIFIED
nationalityCodestring | null

ISO 3166-1 alpha-2.

legalEntityIdrequiredstring (uuid)
joiningDaterequiredstring (date)
identifiersobject[]
typerequiredstring
valuerequiredstring
expiresOnstring | null (date)
acknowledgedDuplicateIdsstring (uuid)[]

Person IDs a reviewer has checked and cleared as not duplicates.

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 409Conflict: duplicate, stale version or concurrent change. Nothing was saved.
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/employees" \
  -H "Authorization: Bearer $MAWRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "givenName": "Daniel",
  "familyName": "Cruz",
  "gender": "MALE",
  "nationalityCode": "PH",
  "dateOfBirth": "1994-06-21",
  "legalEntityId": "a41e7c02-5f3b-4d8e-9c17-6b2d0e8f3a55",
  "joiningDate": "2026-11-01",
  "identifiers": [
    {
      "type": "PASSPORT",
      "value": "P4821937",
      "expiresOn": "2031-03-02"
    }
  ]
}'
Request example
{
  "givenName": "Daniel",
  "familyName": "Cruz",
  "gender": "MALE",
  "nationalityCode": "PH",
  "dateOfBirth": "1994-06-21",
  "legalEntityId": "a41e7c02-5f3b-4d8e-9c17-6b2d0e8f3a55",
  "joiningDate": "2026-11-01",
  "identifiers": [
    {
      "type": "PASSPORT",
      "value": "P4821937",
      "expiresOn": "2031-03-02"
    }
  ]
}
201Response
{
  "data": {
    "personId": "d5e6f7a8-b9c0-4d1e-8f2a-3b4c5d6e7f80",
    "employmentPeriodId": "0a1b2c3d-4e5f-4a6b-9c7d-8e9f0a1b2c3d",
    "employeeCode": "EMP-000231",
    "duplicates": {
      "candidates": []
    }
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Get an employee

GET/employees/{id}

The employee record with person, identifiers and current assignments, masked to the caller. Requires EMPLOYMENT_PERIOD:VIEW and the record inside your data scope.

Parameters

idrequiredstring (uuid) · path

Employment-period ID.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/employees/{id}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": {
    "id": "3b8f0d6e-91c4-4b1f-8a62-5d0c7e2f4a19",
    "employeeCode": "EMP-000214",
    "status": "ACTIVE_CONFIRMED",
    "readiness": "ACTIVE",
    "joiningDate": "2023-03-12T00:00:00.000Z",
    "exitDate": null,
    "legalEntity": {
      "id": "a41e7c02-5f3b-4d8e-9c17-6b2d0e8f3a55",
      "code": "LE-MAIN"
    },
    "person": {
      "id": "e1f2a3b4-c5d6-4e7f-8a9b-0c1d2e3f4a5b",
      "personCode": "PER-000198",
      "givenName": "Ana",
      "familyName": "Santos",
      "givenNameAr": null,
      "familyNameAr": null,
      "dateOfBirth": null,
      "nationalityCode": null,
      "identifiers": [
        {
          "id": "aa11bb22-cc33-4d44-8e55-ff6677889900",
          "identifierType": "PASSPORT",
          "displayValue": "••••••",
          "expiresOn": "2031-03-02T00:00:00.000Z",
          "verificationStatus": "DOCUMENT_VERIFIED"
        }
      ]
    },
    "assignments": [
      {
        "id": "1f2e3d4c-5b6a-4978-8a9b-0c1d2e3f4a5b",
        "code": "ASG-000214",
        "kind": "PRIMARY",
        "current": {
          "workingTitle": null,
          "effectiveFrom": "2026-01-01T00:00:00.000Z"
        }
      }
    ]
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Read an employee fact

GET/employees/{id}/facts/{factKey}

The values of one dated fact (documents, contacts, addresses, contracts, compensation, bank details, dependents, qualifications, entitlements, personal details) as they stood on a date. Each fact has its own permission (for example EMPLOYEE_DOCUMENT:VIEW), and sensitive fields are masked without the matching grant.

Parameters

idrequiredstring (uuid) · path

Employment-period ID.

factKeyrequiredstring · path

The fact to read. GET /employees/metadata/facts lists every fact and its fields.

personal-detailscontactsaddressesdocumentscontractscompensationbank-detailsdependentsqualificationsentitlementssponsorship
asOfstring (date) · query

Business date; defaults to today.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/employees/{id}/facts/{factKey}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "7c8d9e0f-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
      "documentType": "PASSPORT",
      "documentNumber": "••••••",
      "issuingCountryCode": "PH",
      "issuingAuthority": "Department of Foreign Affairs",
      "issueDate": "2021-03-02T00:00:00.000Z",
      "expiryDate": "2031-03-02T00:00:00.000Z",
      "documentStatus": "ISSUED"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

List fact definitions

GET/employees/metadata/facts

Every declared employee fact with its labels and fields, derived from the schema the server validates against. Requires EMPLOYMENT_PERIOD:VIEW.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/employees/metadata/facts" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Organization

Legal entities, departments, locations, positions, grades, cost centers and other effective-dated records.

List organization records

GET/config/{entity}

Lists effective-dated configuration records: legal entities, departments, locations, positions, jobs, grades, cost centers, leave types, shifts and more. Requires VIEW on the entity (for example DEPARTMENT:VIEW).

Parameters

entityrequiredstring · path

The record type.

legal-entitiescompaniesbusiness-unitsdepartmentslocationsorganization-nodespositionsjobsjob-familiesgradescost-centersemployment-typesemployee-categoriesleave-typesholiday-calendarsshiftsdocument-types
pageinteger · query

1-based page number.

pageSizeinteger · query

Rows per page.

searchstring · query

Free-text search on code and name.

sortBystring · query

Sort column.

sortDirstring · query

Sort direction.

ascdesc
asOfDatestring (date) · query

Return the versions in effect on this date.

statusstring · query

Record status filter.

DRAFTPENDINGACTIVEINACTIVEARCHIVED
activationStatusstring · query

Activation status filter.

PENDINGSCHEDULEDACTIVEEXPIREDSUPERSEDEDCANCELLED
companyIdstring (uuid) · query

Only this company.

legalEntityIdstring (uuid) · query

Only this legal entity.

departmentIdstring (uuid) · query

Only this department.

locationIdstring (uuid) · query

Only this location.

costCenterIdstring (uuid) · query

Only this cost center.

includeInactiveboolean · query

Include inactive records.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/config/{entity}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": {
    "items": [
      {
        "id": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
        "recordId": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
        "code": "OPS",
        "displayName": "Operations",
        "recordStatus": "ACTIVE",
        "versionNo": 2,
        "effectiveFrom": "2026-01-01",
        "effectiveTo": null,
        "approvalStatus": "APPROVED",
        "activationStatus": "ACTIVE",
        "isCurrent": true,
        "rowVersion": 3
      }
    ],
    "page": 1,
    "pageSize": 25,
    "total": 1,
    "totalPages": 1,
    "sortDir": "asc"
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Get an organization record

GET/config/{entity}/{id}

One configuration record, optionally as of a date or at a specific version. Requires VIEW on the entity.

Parameters

entityrequiredstring · path

The record type.

legal-entitiescompaniesbusiness-unitsdepartmentslocationsorganization-nodespositionsjobsjob-familiesgradescost-centersemployment-typesemployee-categoriesleave-typesholiday-calendarsshiftsdocument-types
idrequiredstring (uuid) · path

Record ID.

asOfDatestring (date) · query

Version in effect on this date.

versionIdstring (uuid) · query

A specific version.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/config/{entity}/{id}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Attendance

Punch ingestion from any device, the capture ledger and daily attendance.

Send punches (any device)

POST/attendance/punches/batch

The universal ingestion endpoint for biometric terminals, card readers, kiosks and middleware: up to 5,000 events per batch. Idempotent on idempotencyKey, so a device that retries after a timeout never double-punches anyone. Unknown badges, implausible times and replays are kept as visible exceptions rather than dropped. Requires RAW_PUNCH:IMPORT.

Request body application/json

deviceCodestring | null

Code of a registered capture device. An unknown or decommissioned device is refused (422).

channelrequiredstringBIOMETRIC_DEVICECARD_READERMOBILE_APPWEBKIOSKSUPERVISOR_ENTRYAPIIMPORT
idempotencyKeyrequiredstring

Unique per delivery. Re-sending the same key returns the first result unchanged (replayed: true) instead of ingesting again.

eventsrequiredobject[]
sourceIdentityrequiredstring

The identity the device presented: badge number or device user ID.

eventAtrequiredstring

When the event happened at the source, ISO 8601 with an offset. An unparseable time is kept and quarantined, not refused.

directionstring

Omit when the device does not report one; pairing decides.

INOUT
latitudenumber | null
longitudenumber | null
accuracyMetresnumber | null
payloadobject

The original device record. Hashed and kept so a dispute can be settled against it.

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 409Conflict: duplicate, stale version or concurrent change. Nothing was saved.
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/attendance/punches/batch" \
  -H "Authorization: Bearer $MAWRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "deviceCode": "DT-GATE-01",
  "channel": "BIOMETRIC_DEVICE",
  "idempotencyKey": "DT-GATE-01-20261018-0007",
  "events": [
    {
      "sourceIdentity": "10482",
      "eventAt": "2026-10-18T06:52:11-04:00",
      "direction": "IN",
      "payload": {
        "verifyMode": "FINGER",
        "workCode": 0
      }
    },
    {
      "sourceIdentity": "10517",
      "eventAt": "2026-10-18T06:55:40-04:00",
      "direction": "IN"
    }
  ]
}'
Request example
{
  "deviceCode": "DT-GATE-01",
  "channel": "BIOMETRIC_DEVICE",
  "idempotencyKey": "DT-GATE-01-20261018-0007",
  "events": [
    {
      "sourceIdentity": "10482",
      "eventAt": "2026-10-18T06:52:11-04:00",
      "direction": "IN",
      "payload": {
        "verifyMode": "FINGER",
        "workCode": 0
      }
    },
    {
      "sourceIdentity": "10517",
      "eventAt": "2026-10-18T06:55:40-04:00",
      "direction": "IN"
    }
  ]
}
201Response
{
  "data": {
    "batchId": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
    "replayed": false,
    "eventCount": 2,
    "accepted": 2,
    "duplicates": 0,
    "unmatched": 0,
    "quarantined": 0,
    "rejected": 0
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Read the punch ledger

GET/attendance/punches

Every captured event and its outcome, newest first, scoped to the people the caller may see. Requires RAW_PUNCH:VIEW.

Parameters

fromstring (date-time) · query

Events at or after this instant.

tostring (date-time) · query

Events at or before this instant.

employmentPeriodIdstring (uuid) · query

Only this employee.

outcomestring · query

Only this outcome.

ACCEPTEDDUPLICATEUNMATCHED_IDENTITYQUARANTINEDREJECTED
channelstring · query

Only this channel.

BIOMETRIC_DEVICECARD_READERMOBILE_APPWEBKIOSKSUPERVISOR_ENTRYAPIIMPORT
supervisorOnlyboolean · query

Only supervisor entries.

limitinteger · query

Maximum rows.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/attendance/punches" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "4a5b6c7d-8e9f-4a0b-9c1d-2e3f4a5b6c7d",
      "batchId": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
      "deviceId": "6c7d8e9f-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
      "channel": "BIOMETRIC_DEVICE",
      "sourceIdentity": "10482",
      "employmentPeriodId": "3b8f0d6e-91c4-4b1f-8a62-5d0c7e2f4a19",
      "eventAt": "2026-10-18T10:52:11.000Z",
      "receivedAt": "2026-10-18T10:52:14.302Z",
      "direction": "IN",
      "latitude": null,
      "longitude": null,
      "accuracyMetres": null,
      "withinGeoFence": null,
      "outcome": "ACCEPTED",
      "outcomeReason": null,
      "duplicateOfId": null,
      "supervisorEntry": false,
      "device": {
        "code": "DT-GATE-01",
        "name": "Downtown main gate"
      }
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Punches that need attention

GET/attendance/punches/exceptions

The latest 100 events that could not become a punch (unmatched identity, quarantined or rejected) with the reason. Requires RAW_PUNCH:VIEW.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/attendance/punches/exceptions" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Devices that have gone quiet

GET/attendance/devices/silent

Active capture devices with no heartbeat within the window (default 6 hours). A silent device makes it look as if nobody came to work. Requires CAPTURE_DEVICE:VIEW.

Parameters

minutesinteger · query

Silence threshold in minutes.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/attendance/devices/silent" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "6c7d8e9f-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
      "code": "WH-DOCK-02",
      "name": "Warehouse dock reader",
      "lastHeartbeatAt": "2026-10-17T22:04:51.000Z"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Daily attendance

GET/attendance/days

Derived daily attendance for a date window: status, scheduled and worked minutes, lateness, overtime and punch pairs. Scoped to the people the caller may see. Requires ATTENDANCE_DAY:VIEW.

Parameters

fromrequiredstring (date) · query

First business date.

torequiredstring (date) · query

Last business date.

employmentPeriodIdstring (uuid) · query

Only this employee.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/attendance/days" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Leave

Leave types, balances and requests.

Leave types for a person

GET/leave/types/available

The leave types a person may apply for on a date, with their rules (paid, half days, notice, attachments). Requires LEAVE_REQUEST:VIEW.

Parameters

employmentPeriodIdrequiredstring (uuid) · query

The employee.

asOfstring (date) · query

Business date; defaults to today.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/leave/types/available" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "leaveTypeId": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
      "code": "ANNUAL",
      "name": "Annual leave",
      "nameAr": "إجازة سنوية",
      "category": "ANNUAL",
      "color": "#2563EB",
      "paid": true,
      "payPercent": 100,
      "annualEntitlementDays": 21,
      "allowHalfDay": true,
      "countCalendarDays": false,
      "minNoticeDays": 7,
      "maxConsecutiveDays": null,
      "attachmentAfterDays": null,
      "allowNegative": false,
      "allowHourly": false,
      "caseProfile": null,
      "retroWindowDays": 30
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Leave balances for a person

GET/leave/balances

One person's balances for a leave year, computed from the ledger: carried, entitled, earned, taken, pending and available. Requires LEAVE_BALANCE:VIEW.

Parameters

employmentPeriodIdrequiredstring (uuid) · query

The employee.

yearinteger · query

Leave year; defaults to the current year.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/leave/balances" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "balanceId": "bal-2026-annual",
      "leaveTypeId": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
      "code": "ANNUAL",
      "name": "Annual leave",
      "nameAr": "إجازة سنوية",
      "category": "ANNUAL",
      "color": "#2563EB",
      "year": 2026,
      "asOf": "2026-10-18",
      "unlimited": false,
      "carried": 4,
      "entitled": 21,
      "earned": 17.5,
      "adjusted": 0,
      "expired": 0,
      "taken": 4,
      "pending": 3,
      "balance": 17.5,
      "available": 14.5
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

List leave requests

GET/leave/requests

Leave requests in the caller's scope, newest first (up to 500). Requires LEAVE_REQUEST:VIEW.

Parameters

statusstring · query

Comma-separated statuses, e.g. SUBMITTED,APPROVED.

mineboolean · query

Only the caller's own requests.

fromstring (date) · query

Requests ending on or after this date.

tostring (date) · query

Requests starting on or before this date.

employmentPeriodIdstring (uuid) · query

Only this employee.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/leave/requests" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
      "reference": "LV-2026-00412",
      "employmentPeriodId": "3b8f0d6e-91c4-4b1f-8a62-5d0c7e2f4a19",
      "employeeCode": "EMP-000214",
      "employeeName": "Ana Santos",
      "leaveTypeId": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
      "leaveTypeCode": "ANNUAL",
      "leaveTypeName": "Annual leave",
      "category": "ANNUAL",
      "fromDate": "2026-11-01",
      "toDate": "2026-11-12",
      "startHalf": false,
      "endHalf": false,
      "days": 10,
      "status": "SUBMITTED",
      "phase": "PENDING",
      "reasonDetail": "Family visit",
      "submittedAt": "2026-10-18T08:12:00.000Z",
      "decidedAt": null,
      "decisionComments": null,
      "createdAt": "2026-10-18T08:10:31.000Z"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Raise a leave request (draft)

POST/leave/requests

Creates a leave request as a DRAFT after applying every leave rule; blocking rules return 422 naming the field. Send it for approval with POST /leave/requests/{id}/submit. Requires LEAVE_REQUEST:CREATE.

Request body application/json

employmentPeriodIdrequiredstring (uuid)
leaveTypeIdrequiredstring (uuid)
fromDaterequiredstring (date)
toDatestring (date)

Defaults to fromDate.

startHalfboolean

First day is a half day.

endHalfboolean

Last day is a half day.

hoursnumber

Hourly leave, in quarter hours (e.g. 2 or 3.5). Not combinable with half days.

reasonDetailstring
contactDuringLeavestring
handoverNotestring
handoverToIdstring (uuid)
handoverTasksstring[]
delegateIdstring (uuid)

Who covers your approvals while you are away.

delegationCommentsstring

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/leave/requests" \
  -H "Authorization: Bearer $MAWRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "employmentPeriodId": "3b8f0d6e-91c4-4b1f-8a62-5d0c7e2f4a19",
  "leaveTypeId": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
  "fromDate": "2026-11-01",
  "toDate": "2026-11-12",
  "reasonDetail": "Family visit",
  "contactDuringLeave": "+1 555 0142"
}'
Request example
{
  "employmentPeriodId": "3b8f0d6e-91c4-4b1f-8a62-5d0c7e2f4a19",
  "leaveTypeId": "9e0f1a2b-3c4d-4e5f-8a6b-7c8d9e0f1a2b",
  "fromDate": "2026-11-01",
  "toDate": "2026-11-12",
  "reasonDetail": "Family visit",
  "contactDuringLeave": "+1 555 0142"
}
201Response
{
  "data": {
    "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
    "reference": "LV-2026-00412",
    "status": "DRAFT",
    "days": 10,
    "attachmentRequired": false,
    "delegateWarnings": []
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Get a leave request

GET/leave/requests/{id}

One request with its day-by-day breakdown and ledger entries. Requires LEAVE_REQUEST:VIEW.

Parameters

idrequiredstring (uuid) · path

Leave request ID.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/leave/requests/{id}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Submit a leave request

POST/leave/requests/{id}/submit

Sends a draft (or a request returned for information) into the approval workflow. Requires LEAVE_REQUEST:SUBMIT.

Parameters

idrequiredstring (uuid) · path

Leave request ID.

Responses

  • 201OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 409Conflict: duplicate, stale version or concurrent change. Nothing was saved.
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/leave/requests/{id}/submit" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
201Response
{
  "data": {
    "id": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
    "reference": "LV-2026-00412",
    "status": "SUBMITTED",
    "exceptions": []
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Payroll

Payroll runs, GL journals for your ERP, and payslips.

List payroll runs

GET/payroll/runs

Payroll runs, newest first, with totals (masked without amount access). Requires PAY_RUN:VIEW.

Parameters

payGroupIdstring (uuid) · query

Only this pay group.

periodIdstring (uuid) · query

Only this period.

statusstring · query

Only this status.

DRAFTCALCULATINGCALCULATEDIN_REVIEWAPPROVEDLOCKEDPUBLISHEDBANK_FILE_GENERATEDPAYMENT_PARTIALPAIDCLOSEDCANCELLEDREVERSED
runTypestring · query

Only this run type.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/runs" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a",
      "reference": "PR-2026-10-MONTHLY",
      "runType": "REGULAR",
      "status": "LOCKED",
      "population": "ALL",
      "payGroup": {
        "id": "4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b",
        "code": "MONTHLY",
        "name": "Monthly staff"
      },
      "period": {
        "id": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
        "code": "2026-10",
        "label": "October 2026",
        "start": "2026-10-01",
        "end": "2026-10-31",
        "payDate": "2026-10-28",
        "status": "OPEN"
      },
      "paymentDate": "2026-10-28",
      "headcount": 214,
      "totals": {
        "gross": "352910.00",
        "deductions": "10555.00",
        "net": "342355.00",
        "employerContrib": "0.00",
        "masked": false
      },
      "exceptionCounts": {
        "ERROR": 0,
        "WARNING": 3,
        "INFO": 12,
        "unacknowledged": 0
      },
      "calculatedAt": "2026-10-24T09:02:11.000Z",
      "approvedAt": "2026-10-25T13:40:00.000Z",
      "lockedAt": "2026-10-25T14:05:12.000Z",
      "publishedAt": null,
      "resultHash": "c1f0…9a",
      "rowVersion": 7,
      "createdAt": "2026-10-20T07:00:00.000Z"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Get a payroll run

GET/payroll/runs/{id}

A run with totals, the people who made and approved it, and its status timeline. Requires PAY_RUN:VIEW.

Parameters

idrequiredstring (uuid) · path

Payroll run ID.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/runs/{id}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

List GL journals

GET/payroll/journals

Accrual, payment, provision, reversal and settlement journals produced by locked payroll runs, newest first. Superseded versions are hidden unless asked for. Requires PAY_GL:VIEW.

Parameters

runIdstring (uuid) · query

Only this run.

periodIdstring (uuid) · query

Only this period.

kindstring · query

Only this kind.

ACCRUALPAYMENTPROVISIONREVERSALSETTLEMENT
statusstring · query

Only this status.

DRAFTBALANCEDUNBALANCEDEXPORTEDSUPERSEDED
includeSupersededboolean · query

Include superseded versions.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/journals" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "6a7b8c9d-0e1f-4a2b-9c3d-4e5f6a7b8c9d",
      "reference": "JRN-2026-10-ACC-01",
      "kind": "ACCRUAL",
      "kindLabel": "Accrual",
      "status": "BALANCED",
      "versionNo": 1,
      "runId": "3d4e5f6a-7b8c-4d9e-8f0a-1b2c3d4e5f6a",
      "runReference": "PR-2026-10-MONTHLY",
      "periodId": "5f6a7b8c-9d0e-4f1a-8b2c-3d4e5f6a7b8c",
      "periodCode": "2026-10",
      "legalEntityId": "a41e7c02-5f3b-4d8e-9c17-6b2d0e8f3a55",
      "legalEntityCode": "LE-MAIN",
      "legalEntityName": "Acme Hospitality Inc.",
      "postingDate": "2026-10-31",
      "currency": "USD",
      "aggregation": "ACCOUNT_COSTCENTRE",
      "totalDebit": "352910.00",
      "totalCredit": "352910.00",
      "masked": false,
      "exportable": true,
      "lineCount": 48,
      "exportCount": 0,
      "lastExportedAt": null,
      "createdAt": "2026-10-25T14:05:20.000Z",
      "rowVersion": 1
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Get a GL journal

GET/payroll/journals/{id}

A journal with its lines (account, cost centre, department, analysis, debit, credit), diagnostics, previous exports and versions. Requires PAY_GL:VIEW.

Parameters

idrequiredstring (uuid) · path

Journal ID.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/journals/{id}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Export a journal for your ERP

POST/payroll/journals/{id}/export

Renders a balanced journal through a journal layout (configurable columns, date format and file type) as CSV or XLSX, ready to import into your ERP or accounting system. Each export is a new, logged version with a SHA-256. Requires PAY_GL:EXPORT and PAY_AMOUNT:VIEW.

Parameters

idrequiredstring (uuid) · path

Journal ID.

Request body application/json

layoutCodestring

Journal layout to use; defaults to the tenant's default layout.

formatstring

Defaults to the layout's format.

CSVXLSX
reasonstring

Recorded in the audit trail.

Responses

  • 201The journal file (not wrapped in the JSON envelope).
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 409Conflict: duplicate, stale version or concurrent change. Nothing was saved.
  • 422Validation failed; details lists each problem by field.
  • 429Rate limit exceeded. Wait and retry.
curl -X POST "https://mawro.neuroskill.tech/api/v1/payroll/journals/{id}/export" \
  -H "Authorization: Bearer $MAWRO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "layoutCode": "GENERIC_CSV",
  "format": "CSV",
  "reason": "October close"
}'
Request example
{
  "layoutCode": "GENERIC_CSV",
  "format": "CSV",
  "reason": "October close"
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Download a stored export

GET/payroll/journals/{id}/exports/{exportId}

Downloads an earlier export version again, byte for byte. The download is logged. Requires PAY_GL:EXPORT.

Parameters

idrequiredstring (uuid) · path

Journal ID.

exportIdrequiredstring (uuid) · path

Export version ID.

Responses

  • 200The stored journal file.
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/journals/{id}/exports/{exportId}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

Get a payslip

GET/payroll/payslips/{id}

One payslip as printable HTML with its SHA-256. Available to payroll users with amount access (audited) or to the employee for their own published payslip; anyone else gets 404. Requires PAY_RUN:VIEW or PAY_PAYSLIP:VIEW.

Parameters

idrequiredstring (uuid) · path

Payslip ID.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 404No such record in your tenant (CFG-038).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/payslips/{id}" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}
403Response
{
  "error": {
    "key": "CFG-008",
    "type": "ERROR",
    "message": "You do not have permission to perform this action.",
    "statusCode": 403,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

My payslips

GET/payroll/me/payslips

The caller's own published payslips, newest first. Never takes an employee ID: the employee comes from the login. Requires PAY_PAYSLIP:VIEW.

Responses

  • 200OK
  • 401Missing, invalid or expired access token.
  • 403The caller lacks the permission (CFG-008) or the record is outside their data scope (CFG-009).
  • 429Rate limit exceeded. Wait and retry.
curl -X GET "https://mawro.neuroskill.tech/api/v1/payroll/me/payslips" \
  -H "Authorization: Bearer $MAWRO_TOKEN"
200Response
{
  "data": [
    {
      "id": "7b8c9d0e-1f2a-4b3c-8d4e-5f6a7b8c9d0e",
      "periodCode": "2026-09",
      "periodLabel": "September 2026",
      "periodLabelAr": "سبتمبر 2026",
      "payDate": "2026-09-28",
      "net": "1715.00",
      "currency": "USD",
      "versionNo": 1,
      "revised": false,
      "publishedAt": "2026-09-27T12:00:00.000Z"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The session has expired. Sign in again.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-18T09:15:02.118Z",
    "path": "/api/v1/…"
  }
}

External API

Server-to-server endpoints under /ext, authenticated with a workspace API key (Authorization: Bearer mk_live_…) instead of a user session. Keys are created by an administrator under Settings › Integrations, shown once, stored hashed, limited to the scopes chosen, never above their creator's own permissions, rate-limited per key and audited on every call.

The key itself

GET/ext/me

The workspace the key belongs to, its name, prefix, granted scopes and expiry, and the scopes in effect right now. No scope needed.

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/me" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "data": {
    "tenant": "ACME-RETAIL",
    "key": {
      "name": "Payroll bureau sync",
      "prefix": "mk_live_7Hq2",
      "scopes": [
        "EMPLOYMENT_PERIOD:VIEW",
        "PAY_RUN:VIEW"
      ],
      "expiresAt": "2027-04-18T09:00:00.000Z"
    },
    "effectiveScopes": [
      "EMPLOYMENT_PERIOD:VIEW",
      "PAY_RUN:VIEW"
    ]
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

List employees

GET/ext/employees

Employment records, cursor-paged in id order. Pass nextCursor back as cursor until it is null. Scope: EMPLOYMENT_PERIOD:VIEW. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Parameters

limitinteger · query

Page size, 1–500 (default 100).

cursorstring (uuid) · query

The nextCursor of the previous page.

statusstring · query

Only this employment status.

DRAFTPENDING_ACTIVATIONSCHEDULED_ACTIVEACTIVE_ON_PROBATIONEXTENDED_PROBATIONACTIVE_CONFIRMEDON_LEAVEUNPAID_LEAVESECONDEDSUSPENDEDNOTICE_PERIODABSCONDEDEXITEDRETIREDDECEASEDCANCELLED
updatedSincestring (date-time) · query

Only records changed at or after this instant (ISO 8601 with offset).

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 422A query parameter or the body failed validation.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/employees" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "data": [
    {
      "id": "3f2a9c10-6b1e-4d7a-9c2e-5a8b7d6c4e21",
      "employeeCode": "EMP-000214",
      "personId": "0b7e3c55-1f9a-4c2d-8e6b-3a4d5c6e7f80",
      "givenName": "Ana",
      "middleName": null,
      "familyName": "Santos",
      "preferredName": null,
      "givenNameAr": null,
      "familyNameAr": null,
      "nationality": "PH",
      "email": "ana.santos@example.com",
      "status": "ACTIVE_CONFIRMED",
      "legalEntityId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
      "joiningDate": "2023-03-12",
      "originalJoiningDate": "2023-03-12",
      "exitDate": null,
      "updatedAt": "2026-10-19T14:02:11.000Z"
    }
  ],
  "nextCursor": null,
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

One employee

GET/ext/employees/{id}

One employment record by id. Scope: EMPLOYMENT_PERIOD:VIEW. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Parameters

idrequiredstring (uuid) · path

Employment record id.

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 404No such record, or it is outside the key creator's data scope.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/employees/{id}" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "data": {
    "id": "3f2a9c10-6b1e-4d7a-9c2e-5a8b7d6c4e21",
    "employeeCode": "EMP-000214",
    "personId": "0b7e3c55-1f9a-4c2d-8e6b-3a4d5c6e7f80",
    "givenName": "Ana",
    "middleName": null,
    "familyName": "Santos",
    "preferredName": null,
    "givenNameAr": null,
    "familyNameAr": null,
    "nationality": "PH",
    "email": "ana.santos@example.com",
    "status": "ACTIVE_CONFIRMED",
    "legalEntityId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
    "joiningDate": "2023-03-12",
    "originalJoiningDate": "2023-03-12",
    "exitDate": null,
    "updatedAt": "2026-10-19T14:02:11.000Z"
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

Read raw punches

GET/ext/attendance/punches

The capture ledger: every punch received, from any channel. Scope: RAW_PUNCH:VIEW. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Parameters

fromstring (date-time) · query

From this instant (ISO 8601 with offset).

tostring (date-time) · query

Up to this instant (ISO 8601 with offset).

employeeIdstring (uuid) · query

One employee only.

limitinteger · query

1–500 (default 200).

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 422A query parameter or the body failed validation.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/attendance/punches" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "data": [
    {
      "id": "5c4b3a29-1807-4f6e-9d5c-4b3a29180716",
      "employeeId": "3f2a9c10-6b1e-4d7a-9c2e-5a8b7d6c4e21",
      "employeeCode": "EMP-000214",
      "sourceIdentity": "10482",
      "eventAt": "2026-10-20T06:52:11.000Z",
      "receivedAt": "2026-10-20T06:52:14.380Z",
      "direction": "IN",
      "channel": "API",
      "device": "DT-GATE-01",
      "outcome": "ACCEPTED"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

Send punches (batch)

POST/ext/attendance/punches/batch

The same ingestion as POST /attendance/punches/batch, authenticated with an API key and recorded on the API channel. Idempotent on idempotencyKey: re-sending a batch returns the original result. Scope: RAW_PUNCH:IMPORT. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Request body application/json

idempotencyKeyrequiredstring

Unique per batch; a retry sends the same value.

deviceCodestring

Optional device code registered in Mawro.

eventsrequiredobject[]
sourceIdentityrequiredstring
eventAtrequiredstring (date-time)
directionstringINOUT

Responses

  • 201OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 422A query parameter or the body failed validation.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X POST "https://mawro.neuroskill.tech/api/v1/ext/attendance/punches/batch" \
  -H "Authorization: Bearer $MAWRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "idempotencyKey": "tms-export-20261020-0912",
  "deviceCode": "DT-GATE-01",
  "events": [
    {
      "sourceIdentity": "10482",
      "eventAt": "2026-10-20T06:52:11Z",
      "direction": "IN"
    }
  ]
}'
Request example
{
  "idempotencyKey": "tms-export-20261020-0912",
  "deviceCode": "DT-GATE-01",
  "events": [
    {
      "sourceIdentity": "10482",
      "eventAt": "2026-10-20T06:52:11Z",
      "direction": "IN"
    }
  ]
}
201Response
{
  "data": {
    "batchId": "8d9e0f1a-2b3c-4d4e-9f5a-6b7c8d9e0f1a",
    "replayed": false,
    "eventCount": 1,
    "accepted": 1,
    "duplicates": 0,
    "unmatched": 0,
    "quarantined": 0,
    "rejected": 0
  },
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

Leave balances

GET/ext/leave/balances

Balances for one year, per employee and leave type. Scope: LEAVE_BALANCE:VIEW. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Parameters

yearinteger · query

Calendar year (default: the current year).

employeeIdstring (uuid) · query

One employee only.

limitinteger · query

1–2000 (default 1000).

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 404No such record, or it is outside the key creator's data scope.
  • 422A query parameter or the body failed validation.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/leave/balances" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "year": 2026,
  "data": [
    {
      "employeeId": "3f2a9c10-6b1e-4d7a-9c2e-5a8b7d6c4e21",
      "employeeCode": "EMP-000214",
      "leaveType": "ANNUAL",
      "leaveTypeName": "Annual Leave",
      "carried": 0,
      "entitled": 30,
      "adjusted": 0,
      "taken": 9.5,
      "pending": 2,
      "available": 18.5,
      "unlimited": false
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

Approved payroll runs

GET/ext/payroll/runs

The latest 100 runs that are approved or later (never a draft). Scope: PAY_RUN:VIEW. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/payroll/runs" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "data": [
    {
      "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
      "reference": "RUN-2026-09-01",
      "runType": "REGULAR",
      "status": "PAID",
      "periodId": "b0c1d2e3-f4a5-4b6c-9d8e-7f6a5b4c3d2e",
      "paymentDate": "2026-09-30",
      "approvedAt": "2026-09-27T11:20:00.000Z",
      "publishedAt": "2026-09-28T08:00:00.000Z",
      "headcount": 412
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

One run’s results

GET/ext/payroll/runs/{id}/export

Results per employee and per pay component. Amounts are included only when the key's creator holds the SALARY sensitive grant (amountsIncluded says which). Scope: PAY_RUN:VIEW. The key's effective permissions are its scopes intersected with its creator's live permissions, and rows are limited to the creator's data scope.

Parameters

idrequiredstring (uuid) · path

Payroll run id.

Responses

  • 200OK
  • 401No key, or the key is invalid, expired or revoked, or its creator can no longer sign in.
  • 403The key does not hold the scope the endpoint needs, or its creator lost that permission.
  • 404No such record, or it is outside the key creator's data scope.
  • 429The key's per-minute limit was reached (default 120). Wait the Retry-After seconds. X-RateLimit-Limit and X-RateLimit-Remaining come with every response.
curl -X GET "https://mawro.neuroskill.tech/api/v1/ext/payroll/runs/{id}/export" \
  -H "Authorization: Bearer $MAWRO_API_KEY"
200Response
{
  "run": {
    "id": "c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f",
    "reference": "RUN-2026-09-01",
    "status": "PAID",
    "runType": "REGULAR",
    "paymentDate": "2026-09-30"
  },
  "amountsIncluded": false,
  "data": [
    {
      "employeeId": "3f2a9c10-6b1e-4d7a-9c2e-5a8b7d6c4e21",
      "employeeCode": "EMP-000214",
      "name": "Ana Santos",
      "status": "CALCULATED",
      "costCenter": "CC-DT-FOH",
      "paymentMethod": "BANK_TRANSFER"
    }
  ],
  "meta": {
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z"
  }
}
401Response
{
  "error": {
    "key": "CFG-001",
    "type": "ERROR",
    "message": "The API key is not valid, has expired or was revoked.",
    "statusCode": 401,
    "correlationId": "6f1c2b9e-4d1a-4b7e-9f0e-2a7c5d3e8b41",
    "timestamp": "2026-10-20T09:15:02.118Z",
    "path": "/api/v1/ext/…"
  }
}

Need an endpoint that is not listed here? Contact us; the reference covers the integration surface we support for customers. Contact sales