API Reference

Complete reference for all Audit1 API endpoints

📖 API Reference

Base URL: https://apiv2.audit1.com/api/v2

📘

All requests require X-Client-ID and X-Client-Secret headers. See Authentication.


📤 POST /payroll/reports

Submit payroll data for workers' compensation audit.

Required Fields

FieldTypeDescription
employer_feinstringFederal EIN ("12-3456789" or "123456789")
policy_numberstringWorkers' comp policy number
employeesarrayNon-empty array of employee records

Optional Fields

FieldTypeDescription
pay_period.start_datestringPeriod start (YYYY-MM-DD)
pay_period.end_datestringPeriod end (YYYY-MM-DD)

Employee Records

Flexible schema — include whatever payroll fields you have. Common fields:

FieldDescription
first_name, last_nameEmployee name
employee_idYour internal ID
class_codeWC classification code (e.g., "8810")
stateWork state (e.g., "CA")
gross_wagesGross wages for the period
hours_workedHours worked
overtimeOvertime pay

Example Request

{
  "employer_fein": "12-3456789",
  "policy_number": "WC1025561",
  "employees": [
    {
      "first_name": "Jane",
      "last_name": "Smith",
      "class_code": "8810",
      "state": "CA",
      "gross_wages": 2500.00,
      "hours_worked": 80
    }
  ],
  "pay_period": {
    "start_date": "2024-01-01",
    "end_date": "2024-01-15"
  }
}

Response (202 Accepted)

{
  "success": true,
  "file_id": "682abc123def456789012345",
  "status": "completed",
  "environment": "sandbox",
  "employer": {
    "id": "681xyz789abc123456789012",
    "business_name": "Smith Industries LLC",
    "fein": "12-3456789"
  },
  "policy": {
    "id": "680def456ghi789012345678",
    "policy_number": "WC1025561"
  },
  "employee_count": 1,
  "file_name": "Smith-Industries-LLC_2024-01-01_2024-01-15_WC1025561_..."
}
⚠️

500+ employees: Returns immediately with file_id: null. Processing continues in the background — check status via the endpoint below or your portal dashboard.

Errors

StatusErrorCause
400Missing required fieldsemployer_fein, policy_number, or employees missing
400employees must be non-emptyEmpty employees array
401Missing authentication headersMissing X-Client-ID or X-Client-Secret
401Invalid client_idKey not found or deactivated
401Invalid client_secretWrong secret for this client ID
404Employer not foundNo employer matches the FEIN
404Policy not foundNo active policy matches the number

👥 POST /employees/sync

Report employee hires, terminations, and wage updates.

Required Fields

FieldTypeDescription
employer_idstringEmployer identifier
employeesarrayNon-empty array of change records

Each employee requires:

FieldTypeValues
employee_idstringYour internal ID
actionstringhire, terminate, or update

Action-specific fields:

ActionRequiredDescription
hirename, hire_dateNew employee
terminatetermination_dateEmployee leaving
update(any fields)Wage or info changes

Example Request

{
  "employer_id": "681xyz789abc123456789012",
  "employees": [
    { "employee_id": "EMP001", "action": "hire", "name": "John Doe", "hire_date": "2024-01-15" },
    { "employee_id": "EMP002", "action": "terminate", "termination_date": "2024-03-01" },
    { "employee_id": "EMP003", "action": "update", "gross_wages": 3500.00 }
  ]
}

Response (202 Accepted)

{
  "message": "Employee sync initiated",
  "sync_id": "682abc123def456789012345",
  "file_id": "682abc123def456789012345",
  "environment": "sandbox",
  "employer_id": "681xyz789abc123456789012",
  "employees_processed": 3,
  "status": "processing"
}

📋 GET /files/status/:file_id

Check processing status of a submitted file.

Path parameter: file_id — the ID returned from /payroll/reports or /employees/sync

Response (200)

{
  "file_id": "682abc123def456789012345",
  "status": "completed",
  "created_at": "2026-03-28T10:30:00.000Z",
  "updated_at": "2026-03-28T10:32:00.000Z",
  "employee_count": 150,
  "employer_id": "681xyz789abc123456789012",
  "period": { "start": "2024-01-01", "end": "2024-01-15" }
}

File Statuses

StatusDescription
pending⏳ Received, waiting to process
uploaded📥 Stored, beginning identification
identified🔍 Employer and policy matched
normalized📊 Data extracted and standardized
validated✅ Class codes and states verified
completed🎉 All processing finished
failed❌ Processing failed

🔔 POST /webhook/inbound/:connection_id

Push payroll data via webhook. Uses HMAC signature instead of API keys. See Webhooks for setup and signature details.

Body: Same format as /payroll/reports

Required headers:

HeaderDescription
X-Webhook-SignatureHMAC-SHA256(secret, "${timestamp}.${body}") hex digest
X-Webhook-TimestampUnix milliseconds (within 5 min of server time)

Response: Same shape as /payroll/reports


⚠️ Error Format

All errors return JSON:

{
  "error": "Error type",
  "message": "Human-readable description"
}
StatusMeaningAction
202✅ AcceptedSuccess — processing
400❌ Bad RequestCheck request body
401🔒 UnauthorizedCheck credentials
404🔍 Not FoundCheck IDs/FEIN
500💥 Server ErrorRetry, then contact support
502⚡ Upstream ErrorRetry

💻 Client Libraries

JavaScript

class Audit1Client {
  constructor(clientId, clientSecret) {
    this.baseUrl = "https://apiv2.audit1.com/api/v2";
    this.headers = {
      "X-Client-ID": clientId,
      "X-Client-Secret": clientSecret,
      "Content-Type": "application/json",
    };
  }

  async submitPayroll(employerFein, policyNumber, employees, payPeriod) {
    const res = await fetch(`${this.baseUrl}/payroll/reports`, {
      method: "POST",
      headers: this.headers,
      body: JSON.stringify({ employer_fein: employerFein, policy_number: policyNumber, employees, pay_period: payPeriod }),
    });
    if (!res.ok) throw new Error(`API Error (${res.status}): ${(await res.json()).error}`);
    return res.json();
  }

  async syncEmployees(employerId, employees) {
    const res = await fetch(`${this.baseUrl}/employees/sync`, {
      method: "POST",
      headers: this.headers,
      body: JSON.stringify({ employer_id: employerId, employees }),
    });
    if (!res.ok) throw new Error(`API Error (${res.status}): ${(await res.json()).error}`);
    return res.json();
  }

  async getFileStatus(fileId) {
    const res = await fetch(`${this.baseUrl}/files/status/${fileId}`, { headers: this.headers });
    if (!res.ok) throw new Error(`API Error (${res.status}): ${(await res.json()).error}`);
    return res.json();
  }
}

// Usage
const client = new Audit1Client(process.env.AUDIT1_CLIENT_ID, process.env.AUDIT1_CLIENT_SECRET);
const result = await client.submitPayroll("12-3456789", "WC1025561", [
  { first_name: "Jane", last_name: "Smith", class_code: "8810", state: "CA", gross_wages: 2500 }
], { start_date: "2024-01-01", end_date: "2024-01-15" });

Python

import os, requests

class Audit1Client:
    def __init__(self, client_id, client_secret):
        self.base_url = "https://apiv2.audit1.com/api/v2"
        self.headers = {"X-Client-ID": client_id, "X-Client-Secret": client_secret}

    def submit_payroll(self, employer_fein, policy_number, employees, pay_period=None):
        r = requests.post(f"{self.base_url}/payroll/reports", headers=self.headers,
            json={"employer_fein": employer_fein, "policy_number": policy_number,
                  "employees": employees, "pay_period": pay_period}, timeout=30)
        r.raise_for_status()
        return r.json()

    def sync_employees(self, employer_id, employees):
        r = requests.post(f"{self.base_url}/employees/sync", headers=self.headers,
            json={"employer_id": employer_id, "employees": employees}, timeout=30)
        r.raise_for_status()
        return r.json()

    def get_file_status(self, file_id):
        r = requests.get(f"{self.base_url}/files/status/{file_id}", headers=self.headers, timeout=30)
        r.raise_for_status()
        return r.json()

# Usage
client = Audit1Client(os.environ["AUDIT1_CLIENT_ID"], os.environ["AUDIT1_CLIENT_SECRET"])
result = client.submit_payroll("12-3456789", "WC1025561", [
    {"first_name": "Jane", "last_name": "Smith", "class_code": "8810", "state": "CA", "gross_wages": 2500}
], {"start_date": "2024-01-01", "end_date": "2024-01-15"})