Off-Cycle

Runs a payroll outside the company's normal pay schedule — for example, a bonus run, a correction, or pay for a single terminated employee. Unlike Run Payroll, which starts a run for the whole company on its existing schedule, this call lets you set custom pay period dates, a pay date, and a specific list of employees.

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.

Start an off-cycle payroll run

POST https://api.worklio.com/wep/companies/{CLIENT_ID}/payroll/offcycle

Parameters

FieldTypeRequiredDescription
startDatedate-time | nullYesPay period start date.
endDatedate-time | nullYesPay period end date.
payDatedate-time | nullYesPay date.
monthint32 | nullNoMonth (1–12).
payrollInMonthint32 | nullNoPayroll in month.
includeFlatAmountDeductionsboolean | nullNoInclude flat-amount deductions in the run.
includeArrearsboolean | nullNoInclude arrears in the run.
includeScheduledPayboolean | nullNoInclude scheduled pay in the run.
includeTimeOffAccrualsboolean | nullNoInclude time-off accruals in the run.
sendPaydayAnnouncementEmailboolean | nullNoSend the payday announcement email for this run.
employeeIDsarray of int32 | nullYesEmployee IDs to include in this run.
payFrequencyOverrideint32 (enum)YesPay frequency to use for this run. See values below.

payFrequencyOverride values

ValueName
0NA
1Weekly
2BiWeekly
3SemiMonthly
4Monthly

Example request

require("dotenv").config();

const TOKEN = process.env.API_KEY;
const CLIENT_ID = process.env.CLIENT_ID;
const EMPLOYEE_ID = process.env.EMPLOYEE_ID;
const url = `https://api.worklio.com/wep/companies/${CLIENT_ID}/payroll/offcycle`;

const payload = {
  startDate: "2026-09-19",
  endDate: "2026-09-25",
  payDate: "2026-09-28",
  month: null,
  payrollInMonth: null,
  includeFlatAmountDeductions: true,
  includeArrears: false,
  includeScheduledPay: true,
  includeTimeOffAccruals: false,
  sendPaydayAnnouncementEmail: false,
  employeeIDs: [EMPLOYEE_ID], //with more employees in can be [EMPLOYEE_ID, EMPLOYEE_ID2,...]
  payFrequencyOverride: 0
};

async function runOffCyclePayroll() {
  const response = await fetch(url, {
    method: "POST",
    headers: {
      accept: "application/json",
      "api-version": "2.0",
      authorization: `Bearer ${TOKEN}`,
      "content-type": "application/json",
      "x-api-version": "2.0"
    },
    body: JSON.stringify(payload)
  });

  console.log(response.status);
  const raw = await response.text();
  console.log(JSON.stringify(JSON.parse(raw), null, 2));
}

runOffCyclePayroll();
curl -s -X POST "https://api.worklio.com/wep/companies/$CLIENT_ID/payroll/offcycle" \
  -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" \
  -d '{
    "startDate": "2026-09-19",
    "endDate": "2026-09-25",
    "payDate": "2026-09-28",
    "month": null,
    "payrollInMonth": null,
    "includeFlatAmountDeductions": true,
    "includeArrears": false,
    "includeScheduledPay": true,
    "includeTimeOffAccruals": false,
    "sendPaydayAnnouncementEmail": false,
    "employeeIDs": ['"$EMPLOYEE_ID"'],
    "payFrequencyOverride": 0
  }' | jq .

Example response

{
  "companyId": 1028,
  "runId": 1002133,
  "payrollType": 2,
  "startedOn": "2026-09-18",
  "payDay": "2026-09-28",
  "periodStart": "2026-09-19",
  "periodEnd": "2026-09-25",
  "daysToProcessPayments": 4,
  "deadline": "2026-09-24T21:00:00Z",
  "currentUIStep": 0,
  "currentProcStep": 501,
  "currentProcStepDesc": "Payroll Engine Activated",
  "currentProcStepProgress": 0,
  "currentProcStepStatus": 1,
  "direction": 0,
  "isPayrollBlocked": false,
  "canUserOverride": false,
  "errors": [],
  "warnings": []
}

payrollType is 2 for a run started through this endpoint, versus 0 for a regular scheduled run started through Run Payroll.

🚧

A 200 response here does not guarantee every ID in employeeIDs was actually added to the run. An employee is only added if they aren't already part of another payroll that's currently being processed — if they are, the call still returns 200 and the run is created, but that employee is silently left out. Check the run's employee list before relying on who's included.

Advancing and finalizing the run

Once you have runId, advance and finalize the run the same way as a regular payroll run — see steps 2 and 3 in Run Payroll.


Did this page help you?