Employee Onboarding Process
Employee Onboarding adds a new employee to a company by walking them through a series of steps defined in an onboarding template. Some steps are completed by you (the employer) through the API, and some are completed by the employee themselves.
The employer-side flow through the API is:
- Start onboarding from a template.
- Enter the employee's basic information.
- Enter employment basic information.
- Enter employment details.
- (Optional) Prefill the employee's personal and contact information.
After that, the employee must complete their own onboarding steps before you can continue.
Before you start: create an onboarding template
Onboarding templates cannot be created through the API. Create them in BackOffice:
Client → Settings → Onboarding → Onboarding Templates
In the template, you choose which onboarding steps are included and who completes each one. Note the template's ID — you'll pass it as templateId when you start onboarding.
The steps returned by the API, and the fields it asks for, depend on how the template is configured.
Authentication and headers
All requests require a bearer access token (see How to Get API Access). CLIENT_ID is the company identifier returned as id when you create the company.
Every request in this guide uses these headers:
| Header | Value |
|---|---|
authorization | Bearer {TOKEN} |
accept | application/json |
content-type | application/merge-patch+json |
api-version | 2.0 |
x-api-version | 2.0 |
Step 1: Start onboarding
Creates a new onboarding from a template and returns the list of steps it contains.
POST https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/start
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
templateId | integer | Required | ID of the onboarding template created in BackOffice |
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/start`;
const payload = {
templateId: 2094
};
async function startOnboarding() {
const response = await fetch(url, {
method: "POST",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
console.log(await response.text());
}
startOnboarding();curl -s -X POST "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/start" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{ "templateId": 2094 }' | jq .Example response
The steps array depends on your template — yours may contain more or fewer steps.
{
"templateId": 2094,
"steps": [
{ "step": 1, "num": 1, "name": "Employee Basic Information" },
{ "step": 2, "num": 1, "name": "Employment Basic Information" },
{ "step": 3, "num": 1, "name": "Employment Detail Information" },
{ "step": 0, "num": 2, "name": "Employment Summary" },
{ "step": 0, "num": 2, "name": "Personal Information" },
{ "step": 0, "num": 2, "name": "Contact Information" },
{ "step": 0, "num": 2, "name": "W-9 Form" },
{ "step": 0, "num": 2, "name": "W-9 Review" },
{ "step": 0, "num": 2, "name": "Documents Acknowledgment" },
{ "step": 0, "num": 2, "name": "Signing Documents Summary" },
{ "step": 6, "num": 3, "name": "Complete Net Pay Allocation" },
{ "step": 12, "num": 3, "name": "W-9 Form Review" },
{ "step": 10, "num": 3, "name": "Document Review/Signing" }
],
"onboardingId": 2068,
"nextStep": 1,
"customRequiredFields": [
"email",
"ssn"
]
}| Field | Description |
|---|---|
templateId | The template this onboarding was created from |
steps | The steps included in this onboarding, as configured in the template |
onboardingId | Unique identifier of this onboarding. Save it — every following step uses it in the path. |
nextStep | The next step to complete |
customRequiredFields | Fields the template requires in the next step, in addition to the default required fields |
Step 2: Enter employee basic information
Sets the employee's name and identifiers.
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/start/{ONBOARDING_ID}/eebasicinfo
ONBOARDING_ID is the onboardingId returned in Step 1.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
firstName | string | Required | Employee's first name |
lastName | string | Required | Employee's last name |
ssn | string | Required if listed in customRequiredFields | Social Security Number |
email | string | Required if listed in customRequiredFields | Employee's email address |
Send every field listed in customRequiredFields from the Step 1 response.
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/start/${ONBOARDING_ID}/eebasicinfo`;
const payload = {
firstName: "Daniel",
lastName: "Carter",
ssn: "875-52-1231",
email: "[email protected]"
};
async function enterEmployeeBasicInfo() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
console.log(await response.text());
}
enterEmployeeBasicInfo();curl -s -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/start/2068/eebasicinfo" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{
"firstName": "Daniel",
"lastName": "Carter",
"ssn": "875-52-1231",
"email": "[email protected]"
}' | jq .Example response
{
"onboardingId": 2068,
"nextStep": 2,
"customRequiredFields": []
}Step 3: Enter employment basic information
Sets the employee's hire date.
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/start/{ONBOARDING_ID}/employmentbasic
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
originalHireDate | string (ISO date, YYYY-MM-DD) | Required | The employee's original hire date |
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/start/${ONBOARDING_ID}/employmentbasic`;
const payload = {
originalHireDate: "2026-10-01"
};
async function enterEmploymentBasicInfo() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
console.log(await response.text());
}
enterEmploymentBasicInfo();curl -s -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/start/2068/employmentbasic" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{ "originalHireDate": "2026-10-01" }' | jq .{
onboardingId: 2068,
previousStep: 1,
nextStep: 3,
customRequiredFields: []
}Step 4: Enter employment details
Sets the employee's employment type, compensation, and work location.
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/start/{ONBOARDING_ID}/employmentdetail
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
employmentType | integer | Required | Employment type |
compensationType | integer | Required | Compensation type |
compensableHours | number | Required | Hours the employee is expected to work per week |
compensationAmount | number | Required | Compensation amount |
workLocationId | integer | Required | ID of the employee's work location. 0 = works from home. |
highlyCompensated | integer | Required | Whether the employee is highly compensated. 1 = yes, 0 = no. |
keyEmployee | integer | Required | Whether the employee is a key employee. 1 = yes, 0 = no. |
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/start/${ONBOARDING_ID}/employmentdetail`;
const payload = {
employmentType: 2,
compensationType: 5,
compensableHours: 40,
compensationAmount: 2000,
workLocationId: 0, // works from home
highlyCompensated: 1,
keyEmployee: 0
};
async function enterEmploymentDetails() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status);
console.log(await response.text());
}
enterEmploymentDetails();curl -s -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/start/2068/employmentdetail" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{
"employmentType": 2,
"compensationType": 5,
"compensableHours": 40,
"compensationAmount": 2000,
"workLocationId": 0,
"highlyCompensated": 1,
"keyEmployee": 0
}' | jq .Example response
{
"onboardingId": 2068,
"previousStep": 2,
"nextStep": 0,
"customRequiredFields": []
}nextStep: 0 means you've completed the employer steps that come before the employee's part of onboarding.
Step 5 (optional): Prefill employee information
If you already have the employee's personal or contact information, you can prefill it. The employee then only needs to verify it during their part of onboarding instead of typing it in. The information can only be prefilled if employee didn't start his part of onboarding yet.
Both prefill requests have these requirements:
approveStepmust betrue.- For
personalinfoee,w2ElectronicConsentmust also betrue.
Both return 204 No Content with no response body on success.
Prefill personal information
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/start/{ONBOARDING_ID}/personalinfoee
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
gender | integer | Optional | Employee's gender |
birthOn | string (ISO date, YYYY-MM-DD) | Optional | Date of birth |
citizenship | integer | Optional | Citizenship status |
w2ElectronicConsent | boolean | Required | Must be true |
approveStep | boolean | Required | Must be true |
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/start/${ONBOARDING_ID}/personalinfoee`;
const payload = {
gender: 1,
birthOn: "2001-01-08",
citizenship: 1,
w2ElectronicConsent: true,
approveStep: true
};
async function prefillPersonalInfo() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status); // 204, no body
}
prefillPersonalInfo();curl -s -o /dev/null -w "%{http_code}\n" -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/start/2068/personalinfoee" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{
"gender": 1,
"birthOn": "2001-01-08",
"citizenship": 1,
"w2ElectronicConsent": true,
"approveStep": true
}'Prefill contact information
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/start/{ONBOARDING_ID}/contactinfoee
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
personalEmail | string | Optional | Employee's personal email address |
residentialAddress | object | Optional | Employee's home address (see below) |
approveStep | boolean | Required | Must be true |
Optional in this case just means it doesn't have to be in request body, but if it's not employee will still have to fill it in.
residentialAddress fields:
| Field | Type | Description |
|---|---|---|
addressLine1 | string | Street address |
city | string | City |
state | string | Two-letter state code |
zip | string | ZIP code |
country | string | Two-letter country code |
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/start/${ONBOARDING_ID}/contactinfoee`;
const payload = {
personalEmail: "[email protected]",
residentialAddress: {
addressLine1: "350 Fifth Avenue",
city: "New York",
state: "NY",
zip: "10118",
country: "US"
},
approveStep: true
};
async function prefillContactInfo() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status); // 204, no body
}
prefillContactInfo();curl -s -o /dev/null -w "%{http_code}\n" -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/start/2068/contactinfoee" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{
"personalEmail": "[email protected]",
"residentialAddress": {
"addressLine1": "350 Fifth Avenue",
"city": "New York",
"state": "NY",
"zip": "10118",
"country": "US"
},
"approveStep": true
}'Next: the employee completes their steps
The employee must now complete their own onboarding steps (in the example template above: personal information, contact information, W-9 form, and document acknowledgment). The remaining employer steps, which start at Step 6, are available only after the employee finishes.
Finish onboarding as the employer
The steps below match the example template used in this guide. As with the earlier steps, which steps you see and what they require depend on how your onboarding template is configured.
All finalize requests use the same base path and the same ONBOARDING_ID returned in Step 1:
https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}
Step 6: Approve net pay allocation
The employee chooses how their net pay is split during their part of onboarding. You review that allocation and approve it. This takes two requests: GET to read the allocation, then PUT to approve it.
Get the net pay allocation
GET https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/netpay
The request has no body.
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/netpay`;
async function getNetPayAllocation() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
}
});
console.log(response.status);
console.log(JSON.stringify(await response.json(), null, 2));
}
getNetPayAllocation();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/netpay" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" | jq .[
{
"id": 1,
"payMethod": 2,
"accountHolderName": "Alex Smith",
"accountType": 1,
"routingNumber": "121000356",
"accountNumber": "000123456791",
"percent": 100,
"startOn": "2026-10-13T00:00:00Z",
"requirePreNote": false,
"applyForAllPayStubs": true
}
]Approve the net pay allocation
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/netpay
The request has no body. A successful request returns 204 No Content with no response body.
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/netpay`;
async function approveNetPayAllocation() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
}
});
console.log(response.status); // 204, no body
}
approveNetPayAllocation();curl -s -o /dev/null -w "%{http_code}\n" -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/netpay" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0"Step 7: Review documents
Returns the documents prepared during onboarding so you can review them before signing.
GET https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/docreview
The request has no body.
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/docreview`;
async function getDocumentsForReview() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
}
});
console.log(response.status);
console.log(JSON.stringify(await response.json(), null, 2));
}
getDocumentsForReview();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/docreview" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" | jq .The response contains documents encoded in base64.
{
"signatureRequired": false,
"documents": [
{
"title": "Onboarding Template",
"preview": [
"data:data:application/octet-stream;base64;base64....",
"data:data:application/octet-stream;base64;base64....",
"data:data:application/octet-stream;base64;base64....",
"data:data:application/octet-stream;base64;base64...."
]
},
{
"title": "1099-MISC.docx",
"preview": [
"data:data:application/octet-stream;base64;base64....",
"data:data:application/octet-stream;base64;base64....",
"data:data:application/octet-stream;base64;base64....",
"data:data:application/octet-stream;base64;base64...."
]
}
]
}Step 8: Finish document review and signing
Confirms that you reviewed the documents and signs them. Choose whether the signature is electronic or wet ink.
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/docreview/finish
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
declarePenalties | boolean | null | Required | Whether you accepted the declaration required to finish the review or signing. Send true to accept. |
erTypeSignature | integer | Required | How you want to sign the documents. 1 = electronically: the system generates the signature from the name in erSignatureName. 2 = wet ink: you sign the documents manually. |
erSignatureName | string | null | Required if erTypeSignature is 1 | Name used for the electronic signature. |
A successful request returns 204 No Content with no response body.
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/docreview/finish`;
const payload = {
declarePenalties: true,
erTypeSignature: 1, // 1 = electronic, 2 = wet ink
erSignatureName: "Admin"
};
async function finishDocumentReview() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
},
body: JSON.stringify(payload)
});
console.log(response.status); // 204, no body
}
finishDocumentReview();curl -s -o /dev/null -w "%{http_code}\n" -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/docreview/finish" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" \
-d '{
"declarePenalties": true,
"erTypeSignature": 1,
"erSignatureName": "Admin"
}'Step 9: Check which documents need to be uploaded
Some documents cannot be signed electronically. If the employee chose to sign a document manually (wet ink) during their part of onboarding, you must print the document, have it signed, and upload the signed copy. In this example, the employee chose to sign the W-9 manually, so a W-9 upload is required.
This request lists the documents that still need an upload.
GET https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/docupload
The request has no body.
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/docupload`;
async function getRequiredUploads() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
}
});
console.log(response.status);
console.log(JSON.stringify(await response.json(), null, 2));
}
getRequiredUploads();curl -s -X GET "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/docupload" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" | jq .Example response
{
"documents": [
{
"type": 7,
"uploaded": false
}
]
}| Field | Type | Description |
|---|---|---|
documents | array | Documents that require an upload |
documents[].type | integer | Document type. Use this value in the upload path in Step 11. 7 = W-9. |
documents[].uploaded | boolean | true if the document has already been uploaded |
Step 10: Finish the W-9 review
Confirms that you reviewed the employee's W-9. Complete this step before you upload the signed W-9, so you can review the form before it is printed, signed, and uploaded.
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/w9/finish
The request has no body. A successful request returns 204 No Content with no response body.
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/w9/finish`;
async function finishW9Review() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
}
});
console.log(response.status); // 204, no body
}
finishW9Review();curl -s -o /dev/null -w "%{http_code}\n" -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/w9/finish" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0"Step 11: Upload the signed documents
Uploads a signed document for each entry returned in Step 9. Send one request per document.
POST https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/docupload/upload/{DOCUMENT_TYPE}
DOCUMENT_TYPE is the type value from the Step 9 response. For the W-9, use 7.
The request body is multipart/form-data with one part:
| Field | Type | Required | Description |
|---|---|---|---|
file | file | Required | The signed document as a PDF |
Do not set the content-type header yourself. Your HTTP client sets it, including the multipart boundary. A successful request returns 204 No Content with no response body.
Example request
require("dotenv").config();
const fs = require("fs");
const path = require("path");
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const DOCUMENT_TYPE = 7; // 7 = W-9
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/docupload/upload/${DOCUMENT_TYPE}`;
const filePath = path.join(__dirname, "w9-daniel-carter.pdf");
async function uploadDocument() {
const fileBuffer = fs.readFileSync(filePath);
const form = new FormData();
form.append(
"file",
new Blob([fileBuffer], { type: "application/pdf" }),
path.basename(filePath)
);
const response = await fetch(url, {
method: "POST",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"x-api-version": "2.0"
},
body: form
});
console.log(response.status); // 204, no body
}
uploadDocument();curl -s -o /dev/null -w "%{http_code}\n" -X POST "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/docupload/upload/7" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "x-api-version: 2.0" \
-F "[email protected];type=application/pdf"To confirm the upload, call the Step 9 request again. The document's uploaded value is true after a successful upload.
Step 12: Finish onboarding
Completes onboarding and starts the employee's employment. Call it after all previous steps are done.
PUT https://api.worklio.com/wep/companies/{CLIENT_ID}/onboarding/finalize/{ONBOARDING_ID}/finish
The request has no body.
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const ONBOARDING_ID = 2068;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/onboarding/finalize/${ONBOARDING_ID}/finish`;
async function finishOnboarding() {
const response = await fetch(url, {
method: "PUT",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/merge-patch+json",
"x-api-version": "2.0"
}
});
console.log(response.status);
console.log(JSON.stringify(await response.json(), null, 2));
}
finishOnboarding();curl -s -X PUT "https://api.worklio.com/wep/companies/$CLIENT_ID/onboarding/finalize/2068/finish" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/merge-patch+json" \
-H "x-api-version: 2.0" | jq .Example response
{
"id": 4382,
"firstName": "Daniel",
"lastName": "Carter",
"middleName": "",
"birthDate": "2001-01-08T00:00:00Z",
"hireDate": "2026-10-01T00:00:00Z",
"email": "[email protected]",
"phone": ""
}| Field | Type | Description |
|---|---|---|
id | integer | ID of the new employee |
firstName | string | Employee's first name |
lastName | string | Employee's last name |
middleName | string | Employee's middle name. Empty if not set. |
birthDate | string (ISO 8601 date-time) | Employee's date of birth |
hireDate | string (ISO 8601 date-time) | Employee's hire date |
email | string | Employee's email address |
phone | string | Employee's phone number. Empty if not set. |
The employee now exists as an active employee of the company, with the hire date you set in Step 3.
Updated 37 minutes ago
