Payroll Reports
Every payroll run generates a set of reports (payroll register, cash requirements, direct deposit register, and others) once it's created. This page covers how to list the reports available for a payroll run and download one.
The run must be finalized before its reports are available — see Run Payroll. Reports aren't generated for a run that's still in progress.
Requires a bearer access token (see How to Get API Access). CLIENT_ID is the company identifier returned as id when you create the company. RUN_ID is the runId returned when you start a payroll run.
Downloading a report is a three-call sequence:
- Get the run's report list, which includes a
fileTokenper report. - Exchange the
fileTokenfor a short-liveddownloadToken. - Download the file with the
downloadToken.
Because the downloadToken from step 2 is short-lived, do steps 2 and 3 back to back in the same request flow rather than storing the token for later — see the combined example below.
1. Get the payroll run's reports
GET https://api.worklio.com/wep/companies/{CLIENT_ID}/payroll/{RUN_ID}/history/overview
Returns a full overview of a finalized payroll run — pay period dates, totals, tax breakdown, and the reports array this page focuses on. (The rest of the overview response is out of scope for this page.)
reports fields
reports fields| Field | Type | Description |
|---|---|---|
caption | string | Display name of the report, e.g. "Payroll Register". |
description | string | Longer description of the report. Empty for every report type observed so far. |
fileToken | string | Opaque token identifying this report's file. Pass it to the endpoint in step 2 to get a download link. |
reportType | string | Machine-readable report type. See the table below. |
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const RUN_ID = 1002124; // a finalized payroll run's runId
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/payroll/${RUN_ID}/history/overview`;
async function getPayrollOverview() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
getPayrollOverview();curl -s "https://api.worklio.com/wep/companies/$CLIENT_ID/payroll/1002124/history/overview" \
-H "accept: application/json" \
-H "api-version: 2.0" \
-H "authorization: Bearer $API_KEY" \
-H "content-type: application/json" \
-H "x-api-version: 2.0" | jq .Example response
{
"periodStart": "2026-09-11",
"periodEnd": "2026-09-17",
"payDay": "2026-09-18",
"totalGrossPay": 180000,
"totalNetPay": 74243.06,
"reports": [
{
"caption": "Cash Requirements",
"description": "",
"fileToken": "FDtDR0GnOcsIYc7FUqzZhYVbiG-q-f5ZyjNpQ3UFkhYukjLAyr0zo70Npil1J-yCUdtb1eYHiFeSjpCvJnymn2TDQq8UUkkdaBd-QtXRPRdHkjwq9rBbw",
"reportType": "CashRequirements"
},
{
"caption": "Payroll Register",
"description": "",
"fileToken": "o50Iv4rU05f4S-P9BFAbwWyxXyPqTL_RrxxUG3ViwNSZYUuMb7b55kHiElCXeA27GuqGJtjWuX-eubGHKYE70P4R17q992udvvvjcFc2aFNaDYaipnxDO",
"reportType": "PayrollRegister"
}
]
}The full response also includes
payStatements,eeAndERTaxes,dedsAndContribs, andimmediateTransactions— those aren't covered here.
Report types
The following reportType values were returned for the payroll run used throughout this guide:
reportType | Caption |
|---|---|
CashRequirements | Cash Requirements |
CashRequirementsSummary | Cash Requirements Summary |
DeductionBenefitRosterClient | Deduction/Benefit Roster - Client |
TimeSheetNextPayrollClient | Time Entry Sheet |
PayrollRecapClient | Payroll Recap |
PayrollRegister | Payroll Register |
DirectDeposits | Employee Direct Deposit Register |
CheckRegister | Payroll Check Register |
DeductionRegister | Deduction/Benefit Register |
DeductionBenefitRosterClient | Deduction/Benefit Roster |
HoursEarningsRecap | Hours And Earnings Recap |
2. Get a download link for a report
GET https://api.worklio.com/wep/files/{fileToken}/info
Exchange a report's fileToken (from step 1) for a downloadToken. The downloadToken and downloadUri this returns are short-lived (10 seconds) use them right away.
Example request
require("dotenv").config();
const TOKEN = process.env.API_KEY;
const FILE_TOKEN = "o50Iv4rU05f4S-P9BFAbwWyxXyPqTL_RrxxUG3ViwNSZYUuMb7b55kHiElCXeA27GuqGJtjWuX-eubGHKYE70P4R17q992udvvvjcFc2aFNaDYaipnxDO"; // fileToken from step 1
const url = `https://api.worklio.com/wep/files/${FILE_TOKEN}/info`;
async function getDownloadInfo() {
const response = await fetch(url, {
method: "GET",
headers: {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
},
});
console.log(response.status);
const raw = await response.text();
console.log(JSON.stringify(JSON.parse(raw), null, 2));
}
getDownloadInfo();Example response
{
"downloadToken": "6vFtymsuYibYxqEzo8lko9GByuxeLQdXtf4-UaufkkibHmhjn_j_ilo0eiUFcHsmdtHJLQ-qSwk_DkRD36cymWlSKbnxI5NT_CIaADvtOwQJYHJ2C3w46Yw@@",
"downloadUri": "https://api.worklio.com/wep/files/6vFtymsuYibYxqEzo8lko9GByuxeLQdXtf4-UaufkkibHmhjn_j_ilo0eiUFcHsmdtHJLQ-qSwk_DkRD36cymWlSKbnxI5NT_CIaADvtOwQJYHJ2C3w46Yw@@/download",
"previewUri": "https://api.worklio.com/wep/files/6vFtymsuYibYxqEzo8lko9GByuxeLQdXtf4-UaufkkibHmhjn_j_ilo0eiUFcHsmdtHJLQ-qSwk_DkRD36cymWlSKbnxI5NT_CIaADvtOwQJYHJ2C3w46Yw@@/preview"
}downloadUri is the full URL for step 3 below — you don't need to build it yourself.
3. Download the report
GET https://api.worklio.com/wep/files/{downloadToken}/download
Returns the report file. Reports are PDFs.
Putting it together
Because the downloadToken is short-lived, fetch it and use it immediately, in the same script, rather than storing it:
require("dotenv").config();
const fs = require("fs");
const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const RUN_ID = 1002124; // a finalized payroll run's runId
const REPORT_TYPE = "PayrollRegister"; // see the report types table above
const headers = {
accept: "application/json",
"api-version": "2.0",
authorization: `Bearer ${TOKEN}`,
"content-type": "application/json",
"x-api-version": "2.0"
};
async function downloadPayrollReport() {
// 1. Get the run's report list
const overviewRes = await fetch(
`https://api.worklio.com/wep/companies/${CLIENT_ID}/payroll/${RUN_ID}/history/overview`,
{ method: "GET", headers }
);
const overview = await overviewRes.json();
const report = overview.reports.find(r => r.reportType === REPORT_TYPE);
if (!report) {
throw new Error(`No report of type ${REPORT_TYPE} found for run ${RUN_ID}`);
}
// 2. Exchange the fileToken for a short-lived download link
const infoRes = await fetch(
`https://api.worklio.com/wep/files/${report.fileToken}/info`,
{ method: "GET", headers }
);
const { downloadUri } = await infoRes.json();
// 3. Download the file right away, while the downloadToken is still valid
const fileRes = await fetch(downloadUri, { method: "GET", headers });
if (!fileRes.ok) {
throw new Error(`Download failed: ${fileRes.status}`);
}
const buffer = Buffer.from(await fileRes.arrayBuffer());
const outPath = `${report.reportType}.pdf`;
fs.writeFileSync(outPath, buffer);
console.log(`Saved ${outPath}`);
}
downloadPayrollReport();Calling download too late will result in download not being successful.
{
"status": 0,
"code": "400",
"errorCode": "WEP_BadRequest",
"message": "10/9/2026 - 6:24:21 AM : Download token is expired!",
"stackTrace": "",
"pagination": {
"pageNo": 0,
"pageSize": 0,
"totalRecords": 0,
"totalPages": 0,
"dataToken": ""
},
"validationErrors": null
}Notes
- The payroll run must be finalized before its reports exist. Calling this against a run that hasn't been finalized isn't covered here — confirm the behavior before documenting it.
fileTokenanddownloadTokenare specific to one payroll run and one report. Re-run step 1 to get currentfileTokenvalues rather than reusing old ones.
Updated 3 days ago
