Overview

Employees belong to an Employer. They represent the individuals being paid — each with their own TFN, super fund, tax treatment, and STP Phase 2 classification.

Endpoints are nested under the employer:

GET  /api/v1/employers/:employer_id/employees
POST /api/v1/employers/:employer_id/employees
GET  /api/v1/employers/:employer_id/employees/:id
PATCH /api/v1/employers/:employer_id/employees/:id

The Employee object

Common fields (always returned)

Field Type Notes
id integer
employer_id integer
first_name string
last_name string
full_name string Computed
payroll_id string Your system's ID for this employee. Must be unique within the employer.
employment_basis string F, P, C, L — see STP codes
employment_basis_label string Computed (e.g. "Full-time")
income_type string SAW, CHP, WHM, SWP, VOL, JPD
income_type_label string Computed (e.g. "Salary and wages")
employment_start_date string (ISO 8601 date)
cessation_date string (ISO 8601 date, nullable) When employment ended
active boolean
terminated boolean Computed. True if cessation_date is set and in the past
created_at string (ISO 8601)
updated_at string (ISO 8601)

Detail fields (only on GET /:id)

Field Type Notes
title string Mr, Ms, Dr, etc.
gender string
date_of_birth string (ISO 8601 date)
tfn_masked string ***-***-782 — the last 3 digits only. Full TFN is never returned.
email string
phone string
address_line_1 string
address_line_2 string
suburb string
state string AU state code
postcode string
cessation_reason string Required when cessation_date is set
income_type_country string ISO 3166 country code, required for WHM income type
tax_treatment_code string See STP codes
pay_rate_type integer 0 = hourly, 1 = salaried
pay_rate number Decimal
hours_per_pay_period number Decimal
super_fund_name string
super_usi string Unique Superannuation Identifier
super_member_number string
bank_account_name string
bank_bsb string Formatted as 123-456
bank_account_number_masked string Last 3 digits only

Writeable fields

When creating or updating an employee, you can send any of these fields in the request body. TFN, super, bank, and address can all be updated independently.

{
  "employee": {
    "first_name": "Aria",
    "last_name": "Patel",
    "title": "Ms",
    "gender": "F",
    "date_of_birth": "1995-03-14",
    "tfn": "123456782",
    "email": "aria@acme.example",
    "phone": "+61400000000",
    "address_line_1": "12 Test St",
    "suburb": "Sydney",
    "state": "NSW",
    "postcode": "2000",
    "payroll_id": "EMP-001",
    "employment_basis": "F",
    "employment_start_date": "2024-07-01",
    "income_type": "SAW",
    "tax_treatment_code": "RTRR0000",
    "pay_rate_type": 1,
    "pay_rate": 120000.00,
    "hours_per_pay_period": 76.00,
    "super_fund_name": "Australian Retirement Trust",
    "super_usi": "ATO0100AU",
    "super_member_number": "12345678",
    "bank_account_name": "A Patel",
    "bank_bsb": "062-000",
    "bank_account_number": "12345678"
  }
}

TFN handling

  • TFNs are encrypted at rest using Rails' built-in attribute encryption
  • The full TFN is never returned by the API — only the masked form (last 3 digits)
  • Pass a 9-digit TFN string with no spaces or dashes
  • If you leave TFN blank, the ATO expects one of the substitution values (000000000 for no TFN quoted, 111111111 for applied for, 333333333 for under 18)

Endpoints

List employees for an employer

GET /api/v1/employers/:employer_id/employees

Scopes: employees:read

Query parameters:

Param Default Notes
include_terminated 0 Set to 1 to include terminated employees
page 1
per_page 25 Max 100

Response: 200 OK with an array of compact Employee objects.

curl https://stp.beeswaxapp.com/api/v1/employers/12/employees \
  -H "Authorization: Bearer stp_test_..."

Get an employee

GET /api/v1/employers/:employer_id/employees/:id

Scopes: employees:read

Response: 200 OK with the full Employee object including detail fields.

Create an employee

POST /api/v1/employers/:employer_id/employees

Scopes: employees:write

Idempotent: yes

Body: see writeable fields above. first_name, last_name, and employment_basis are required. income_type defaults to SAW.

Response: 201 Created with full Employee object.

Update an employee

PATCH /api/v1/employers/:employer_id/employees/:id

Scopes: employees:write

Idempotent: yes

Body: any subset of the writeable fields.

Response: 200 OK with updated Employee object.

Terminating an employee

To mark an employee as terminated, set cessation_date and cessation_reason:

{
  "employee": {
    "cessation_date": "2026-03-31",
    "cessation_reason": "V"
  }
}

cessation_reason codes (STP Phase 2):

Code Meaning
V Voluntary cessation
I Ill health
D Deceased
R Redundancy
F Dismissal
C Contract cessation
T Transfer
O Other

Terminated employees are excluded from GET /employees by default. Pass ?include_terminated=1 to see them. They still count against your free tier quota until you delete them (which you can only do via the web UI, for compliance reasons).

Validation rules

  • first_name and last_name are required
  • payroll_id must be unique within the employer
  • employment_basis must be one of F, P, C, L
  • income_type must be one of SAW, CHP, WHM, SWP, VOL, JPD
  • state must be a valid Australian state code if provided
  • postcode must be 4 digits if provided
  • bank_bsb must be 6 digits (with or without dash)

Common tasks

Bulk import employees from a CSV

while IFS=, read -r first last tfn payroll_id; do
  curl https://stp.beeswaxapp.com/api/v1/employers/12/employees \
    -X POST \
    -H "Authorization: Bearer stp_live_..." \
    -H "Idempotency-Key: employee-import-$payroll_id" \
    -H "Content-Type: application/json" \
    -d "{
      \"employee\": {
        \"first_name\": \"$first\",
        \"last_name\": \"$last\",
        \"tfn\": \"$tfn\",
        \"payroll_id\": \"$payroll_id\",
        \"employment_basis\": \"F\",
        \"income_type\": \"SAW\",
        \"employment_start_date\": \"2026-04-01\"
      }
    }"
done < employees.csv

The idempotency key keyed on payroll_id means you can rerun the import safely — existing employees won't be duplicated.