Workers Comp.

A workers' compensation rate table tells Worklio how much of each employee's wages to charge for workers' comp premium, per class code, for a given state. Set this up for any state where the company has payroll exposure, typically alongside company tax setup for that state.

Creating a rate requires a valid class code. Class codes are the standard classification codes (e.g. NCCI-style codes) used to categorize the type of work performed; each one has its own workers' comp rate. Look up available codes before creating a rate.

Auth

Requires a bearer access token (see How to Get API Access).

Step 1: Look up class codes

GET https://api.worklio.com/wep/workcomp/codes

This endpoint isn't scoped to a company — it returns the full list of class codes available across all companies. There's no pagination or filtering; the response is the complete list every time.

Example request

require("dotenv").config();

const TOKEN = process.env.API_KEY;
const url = `https://api.worklio.com/wep/workcomp/codes`;

async function getWorkCompCodes() {
  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);
  console.log(await response.text());
}

getWorkCompCodes();
curl -s "https://api.worklio.com/wep/workcomp/codes" \
  -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

[
  .
  .
  .,
  {
    "code": "9534",
    "description": "CRANE/HOISTING CONTRACTORS-NOC"
  },
  {
    "code": "9545",
    "description": "SIGN/BILLBOARD POSTING"
  },
  {
    "code": "9549",
    "description": "ADVERTISING CO -OUTDOORS"
  },
  {
    "code": "9984",
    "description": "ATOMIC ENERGY:PROJECT WORK"
  },
  {
    "code": "9985",
    "description": "ATOMIC ENERGY:RADIATION EXPOSURE"
  }
]

This is a representative excerpt. The actual response returns every class code. Save the code values you need; you'll use them in rates[].code below.

Step 2: Create the rate

POST https://api.worklio.com/wep/companies/{CLIENT_ID}/workcomp/rates

CLIENT_ID is the company identifier returned as id when you create the company.

Required fields:

FieldTypeRequiredDescription
effectiveFromstringYesDate this rate table takes effect, as YYYY-MM-DD.
statestringYesTwo-letter state code this rate table applies to.
ratesarray of objectsYesOne or more class-code/rate pairs to set for this state and effective date. See below.
chargeOnPremiumWagesbooleanNoWhether the overtime/premium portion of pay is subject to the workers' comp premium calculation. Default False.
sec125ReductionbooleanNoWhether Section 125 (cafeteria plan) pre-tax deductions reduce the wages subject to the workers' comp premium calculation. Default False.

rates[] object fields:

FieldTypeRequiredDescription
codestringYesA class code from Step 1.
ratenumberYesRate per $100 of wages for this class code.

You can include more than one { code, rate } entry in rates to set multiple class codes for the same state and effective date in a single call.

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}/workcomp/rates`;

const payload = {
  effectiveFrom: "2026-09-17",
  state: "TX",
  rates: [
    {
      code: "9549",
      rate: 10
    }
  ],
  chargeOnPremiumWages: false,
  sec125Reduction: true
};

async function createWorkCompRate() {
  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);
  console.log(await response.text());
}

createWorkCompRate();
curl -s -X POST "https://api.worklio.com/wep/companies/$CLIENT_ID/workcomp/rates" \
  -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 '{
    "effectiveFrom": "2026-09-17",
    "state": "TX",
    "rates": [
      {
        "code": "9549",
        "rate": 10
      }
    ],
    "chargeOnPremiumWages": false,
    "sec125Reduction": true
  }' | jq .

Example response

{
  "id": 174,
  "fein": "12-3456789",
  "effectiveFrom": "2026-09-17",
  "state": "TX",
  "sec125Reduction": true,
  "chargeOnPremiumWages": false,
  "rates": [
    {
      "code": "9549",
      "rate": 10
    }
  ]
}

id is the rate table's unique identifier. fein isn't a request field — it's the company's FEIN, returned for reference.

Error response — invalid class code

{
  "status": 0,
  "code": "500",
  "errorCode": null,
  "message": "9/18/2026 - 7:13:04 AM : Class code does not exist.",
  "stackTrace": "",
  "pagination": {
    "pageNo": 0,
    "pageSize": 0,
    "totalRecords": 0,
    "totalPages": 0,
    "dataToken": ""
  },
  "validationErrors": null
}

Returned when a code in rates[] doesn't match a code from Step 1.

Error response — effectiveFrom not after the existing rate table

{
  "status": 0,
  "code": "500",
  "errorCode": null,
  "message": "9/18/2026 - 7:14:20 AM : New versions of Workers' Compensation Rate must have a EffectiveFrom date greater than the last existing EffectiveFrom date.",
  "stackTrace": "",
  "pagination": {
    "pageNo": 0,
    "pageSize": 0,
    "totalRecords": 0,
    "totalPages": 0,
    "dataToken": ""
  },
  "validationErrors": null
}

Each call to this endpoint creates a new version of the rate table for that state. It doesn't edit an existing one. If a rate table already exists for the state, effectiveFrom on the new call must be later than the most recent existing effectiveFrom for that state, or this error is returned.

🚧

Both error responses above return an HTTP 500, not a 400 — that's the API's actual behavior, not a mistake in this guide.


Did this page help you?