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:

  1. Get the run's report list, which includes a fileToken per report.
  2. Exchange the fileToken for a short-lived downloadToken.
  3. 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

FieldTypeDescription
captionstringDisplay name of the report, e.g. "Payroll Register".
descriptionstringLonger description of the report. Empty for every report type observed so far.
fileTokenstringOpaque token identifying this report's file. Pass it to the endpoint in step 2 to get a download link.
reportTypestringMachine-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, and immediateTransactions — those aren't covered here.

Report types

The following reportType values were returned for the payroll run used throughout this guide:

reportTypeCaption
CashRequirementsCash Requirements
CashRequirementsSummaryCash Requirements Summary
DeductionBenefitRosterClientDeduction/Benefit Roster - Client
TimeSheetNextPayrollClientTime Entry Sheet
PayrollRecapClientPayroll Recap
PayrollRegisterPayroll Register
DirectDepositsEmployee Direct Deposit Register
CheckRegisterPayroll Check Register
DeductionRegisterDeduction/Benefit Register
DeductionBenefitRosterClientDeduction/Benefit Roster
HoursEarningsRecapHours 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.
  • fileToken and downloadToken are specific to one payroll run and one report. Re-run step 1 to get current fileToken values rather than reusing old ones.

Did this page help you?