API docs
Resources
Employees
Read records, export ready-to-use payroll files, update fields and sync bidirectionally with your payroll software. Writes never create new employees — they update matched ones (conservative merge).
Canonical model
Internally we keep a single canonical employee model from which all exports are built. Import and PATCH never wipe data — they only fill in empty or changed fields. Creating an employee from scratch happens through a separate onboarding flow.GET/employees
List of the tenant's employees (summary data, without decrypted PII). The response is paginated.
Query parameters
statusstringopcjonalne | filter by onboarding status (e.g. completed). |
companyIduuidopcjonalne | restrict to a single company (payer). |
updatedSinceISO-8601opcjonalne | only records changed since the given moment — for incremental sync. |
pageintegeropcjonalne | page number (default 1). |
pageSizeintegeropcjonalne | page size (default 50, max 200). |
curl -H "Authorization: Bearer onb_..." \
"https://www.onboardly.work/api/v1/employees?updatedSince=2026-07-01&pageSize=50"{
"data": [{
"id": "uuid", "firstName": "Jan", "lastName": "Kowalski",
"email": "jan@example.com", "phone": "+48…", "status": "completed",
"contractType": "zlecenie", "isForeigner": false, "nationalityType": null,
"position": "Kelner", "companyId": "uuid",
"startDate": "2026-06-01", "endDate": null,
"updatedAt": "2026-07-10T12:00:00.000Z"
}],
"page": 1, "pageSize": 50, "total": 130, "totalPages": 3
}GET/employees/{id}
Full canonical record with decrypted personal data. Every call logs the PII access (GDPR art. 30).
{
"data": {
"onboardingId": "uuid", "status": "completed",
"firstName": "Jan", "lastName": "Kowalski", "email": "…", "phone": "…",
"pesel": "86010112345", "birthDate": "1986-01-01", "placeOfBirth": "Warszawa",
"nationality": "PL", "isForeigner": false,
"residenceAddress": { "street": "…", "houseNumber": "…", "postalCode": "00-001", "city": "Warszawa", "country": "PL" },
"contractType": "zlecenie", "position": "Kelner",
"occupationCode": "941201", "startDate": "2026-06-01", "endDate": null,
"hourlyRate": 30.0, "bankAccount": "PL…", "bankName": "mBank",
"insurance": { "code": "041100", "confidence": "low", "requiresZusRegistration": true, "document": "ZUA" },
"nfzCode": "07", "pit2": true, "ppkResign": false,
"employer": { "name": "…", "nip": "…", "regon": "…", "address": "…" }
}
}| HTTP | code | Znaczenie |
|---|---|---|
404 | not_found | no such employee in this tenant. |
410 | pii_deleted | personal data deleted (GDPR). |
GET/employees/{id}/export?format=
Returns a ready-to-use file (not JSON) for your payroll software. The Content-Disposition: attachment header; any warnings in the X-Payroll-Warnings header (URL-encoded JSON).
Query parameter
formatenumopcjonalne | kedu | optima | symfonia | csv | xlsx (default kedu). KEDU is the universal ZUS filing read by Płatnik, Optima, Symfonia, enova and Gratyfikant. |
curl -H "Authorization: Bearer onb_..." \
"https://www.onboardly.work/api/v1/employees/{id}/export?format=kedu" -o kedu.xml| HTTP | code | Znaczenie |
|---|---|---|
400 | — | unknown format. |
422 | incomplete | required fields missing — the body contains { blockers[], warnings[] }. |
501 | format_not_ready | format not yet available for this path. |
PATCH/employees/{id}
Update payroll fields (flat columns). All fields optional. PII and address are not edited this way.
Request body
positionstringopcjonalne | job title. |
salaryNetnumberopcjonalne | net salary. |
hourlyRatenumberopcjonalne | hourly rate. |
startDate / endDateYYYY-MM-DDopcjonalne | employment dates. |
nfzCode / nfzBranchstringopcjonalne | NFZ code and branch. |
usName / usCodestringopcjonalne | tax office name and code. |
bankNamestringopcjonalne | bank name. |
nipstringopcjonalne | employee NIP (B2B / PIT-11). |
pit2 / ppkResignbooleanopcjonalne | PIT-2 declaration / PPK opt-out. |
curl -X PATCH -H "Authorization: Bearer onb_..." -H "Content-Type: application/json" \
-d '{"nfzCode":"07","bankName":"mBank","pit2":true}' \
"https://www.onboardly.work/api/v1/employees/{id}"{ "ok": true, "updated": ["nfzCode", "bankName", "pit2"] }| HTTP | code | Znaczenie |
|---|---|---|
400 | invalid | invalid field value. |
400 | empty | no fields to update. |
404 | not_found | no such employee in this tenant. |
POST/employees/import
Preview of the import — writes nothing. Parses the file and matches records by PESEL (fallback: first name + last name + date of birth).
Request body
formatenumwymagane | kedu | symfonia | optima | csv | xlsx. |
contentstringwymagane | file content (max 5 MB). |
curl -X POST -H "Authorization: Bearer onb_..." -H "Content-Type: application/json" \
-d '{"format":"kedu","content":"<KEDU>...</KEDU>"}' \
"https://www.onboardly.work/api/v1/employees/import"{
"total": 12, "matched": 10, "new": 2,
"rows": [{
"name": "Jan Kowalski", "pesel": "860…",
"matchedOnboardingId": "uuid", "match": "matched"
}]
}| HTTP | code | Znaczenie |
|---|---|---|
422 | parse_failed | the file could not be parsed. |
501 | format_not_ready | format parser not ready. |
POST/employees/import/confirm
Commit the import — conservative merge (fills in only empty or changed fields, never wipes). Upsert exclusively to matched and confirmed identifiers. Does not create new employees.
Request body
formatenumwymagane | as in the preview. |
contentstringwymagane | file content. |
confirmIdsuuid[]wymagane | identifiers of the matched employees to save. |
{
"updated": 2, "skipped": 1,
"updatedDetail": [{ "onboardingId": "uuid", "fields": ["personal.pesel", "nfzCode"] }],
"skippedDetail": [{ "reason": "brak zmian", "pesel": "…" }]
}POST/employees/{id}/zus/deregister
Sets the employment end date and returns a KEDU ZWUA file (ZUS deregistration). Requires a prior registration (ZUA/ZZA).
Request body
endDateYYYY-MM-DDwymagane | employment end date. |
curl -X POST -H "Authorization: Bearer onb_..." -H "Content-Type: application/json" \
-d '{"endDate":"2026-07-31"}' \
"https://www.onboardly.work/api/v1/employees/{id}/zus/deregister" -o zwua.xml| HTTP | code | Znaczenie |
|---|---|---|
409 | not_registered | B2B / specific-task contract — no registration, nothing to deregister. |
410 | pii_deleted | personal data deleted (GDPR). |
Implementation notes
- • KEDU export supports ZUA/ZZA; RUD (specific-task contract) is skipped (filed via PUE ZUS); ZWUA only through the deregistration endpoint.
- • The insurance title code for mandate contracts is sometimes
confidence: "low"— confirm it before filing with ZUS. - • Import and PATCH do not create employees from scratch — the onboarding flow is for that.