Set up, run, and integrate VerityPay
From your first payroll run through to the REST API. Written for whoever has to make it work.
Getting started
VerityPay is a multi-tenant South African payroll platform. Every organisation is isolated: all queries scope to organisationId, so one client's data cannot be reached from another client's session.
The engine calculates PAYE using the SARS annualised method, enforces the UIF cap of R177.12 a month, applies SDL at 1% above the R500,000 annual payroll threshold, and tracks BCEA leave cycles on its own.
Organisation setup
Create an account, then capture the following during onboarding:
- Registered name and trading name
- SARS PAYE reference number
- UIF reference number
- SDL reference number, if you are above the threshold
- The banking profile that salaries are paid from
Your first payroll run
Add your employees, then open Payroll and choose New run. Pick the pay period, confirm who is included, and calculate. You see the full gross-to-net breakdown before anything is approved.
Owners, payroll admins and finance users can approve a run. Whoever calculated a run may also approve it; the audit trail records when the same person did both.
Payroll processing
A run computes gross-to-net for every included employee in one pass, against an employee snapshot taken at calculation time. Once completed, a run is immutable.
PAYE, the annualised method
Monthly gross is projected to a year, taxed on the annual brackets, reduced by age rebates, then divided back to a monthly figure.
monthly_gross x 12
-> find bracket
-> base_tax + rate x (annual - bracket_floor)
-> subtract rebates
-> / 12 = monthly PAYE
Rebates (2025/26)
Primary R17,235 all taxpayers
Secondary R9,444 age 65 and over
Tertiary R3,145 age 75 and over
Tax thresholds
Under 65 R95,750
65 to 74 R148,217
75 and over R165,689Rebates stack by age and are applied automatically from the employee record. Below the threshold, PAYE is zero and the run still files correctly.
Correction runs
Completed runs cannot be edited. To fix an error, create a correction run that references the original. Both are kept in full for audit. Overpayments and underpayments appear as separate line items on the correction payslip.
Payslips
Branded PDF payslips generate on approval. Employees download theirs from the portal immediately. Payroll administrators can bulk-download every payslip for a run.
Tax calculations
The tax engine is pure functions with no database access, no network calls and no side effects. The same inputs always produce the same output, which is what makes it testable to the cent.
Three gross definitions are tracked separately, because they are genuinely different numbers: grossForPAYE, grossForUIF and grossForSDL.
UIF
1% employee and 1% employer, capped at R177.12 a month against a salary ceiling of R17,712.
Excluded from UIF gross: bonuses, overtime, retrenchment pay and retirement lump sums. Included: basic salary, commission and most allowances.
SDL
1%, employer only, payable where annual payroll exceeds R500,000. SDL gross includes everything with no exclusions, so it is the widest of the three definitions.
ETI
The Employment Tax Incentive reduces your PAYE liability for qualifying employees aged 18 to 29 earning below the threshold. VerityPay works out the reduction and applies it before the EMP201 is generated.
Leave management
Leave follows the BCEA. Balances update the moment a leave transaction is recorded, and the run picks up whatever the balance is at calculation time.
Annual leave
15 working days a year, accrued at 1.25 days a month. Leave taken comes off the accrued balance. Carry-over caps and forfeiture are configurable per organisation.
Sick and family responsibility leave
Sick leave runs at 30 days per three-year cycle. The cycle start date is tracked per employee and resets on its own. Family responsibility leave is 3 days a year with no carry-over.
Termination payout
On termination, outstanding annual leave is added to the final run as a taxable lump sum and coded 3606 on the IRP5. No manual calculation, and no forgetting.
Exports and compliance
Every statutory output is generated from the same immutable run history, so what you file always reconciles to what you paid.
EMP201
After each run, open Exports and generate the EMP201. The file is SARS-formatted XML ready for eFiling, aggregating PAYE, UIF, SDL and ETI across everyone in the run.
IRP5 and IT3(a)
Certificates generate at year-end for everyone who earned during the tax year, with taxable income, deductions and fringe benefits mapped to the correct SARS source codes.
Bank EFT files
Approved runs export as bank-ready payment files for FNB, Standard Bank, Absa, Nedbank and Capitec, plus a universal CSV. One record per employee. Account numbers are decrypted at the moment the file is written and never stored in plain text.
Employment letters
Salary confirmation and employment letters generate on demand from either the employee portal or the payroll dashboard, carrying current salary, employment date and leave balance.
Developer API
The REST API lets you pull payroll data into your own systems. Every endpoint takes an API key as a bearer token, over HTTPS only.
Authentication
Authorization: Bearer vp_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
All requests must be HTTPS.
Keys are scoped to a single organisation.
Rotate them from Settings, API keys.Payroll endpoints
GET /api/v1/{orgSlug}/payroll
List payroll runs
GET /api/v1/{orgSlug}/payroll/{runId}
One run, with full line items
POST /api/v1/{orgSlug}/payroll
Create a draft run
POST /api/v1/{orgSlug}/payroll/{runId}/approve
Approve a run, must be a different userEmployee endpoints
GET /api/v1/{orgSlug}/employees
List employees, paginated
GET /api/v1/{orgSlug}/employees/{id}
One employee record
POST /api/v1/{orgSlug}/employees
Create an employee
PATCH /api/v1/{orgSlug}/employees/{id}
Update employee detailsWebhooks
VerityPay posts to your registered endpoint on these events:
payroll.run.approved, run approved and payslips generatedemployee.created, new employee addedleave.approved, leave request approvedleave.balance.low, employee balance below three days
Errors and rate limits
120 requests a minute per key. Errors return JSON with code, message and details.
{
"code": "PAYROLL_ALREADY_APPROVED",
"message": "This payroll run has already been approved.",
"details": { "runId": "clx..." }
}Security and POPIA
Personal information is encrypted at the application layer before it reaches the database. SA ID numbers and bank account numbers are AES-256 encrypted at field level and are never stored in plain text.
POPIA
VerityPay acts as an Operator for the personal information it processes on behalf of your organisation, which is the Responsible Party. Purpose limitation, data minimisation and retention rules are applied as POPIA requires.
Data retention
Payroll runs and payslips are kept for five years after the tax year they fall in, in line with SARS record-keeping rules. Employee records are kept for three years after employment ends. Deletion requests are actioned within 30 days where the law allows it.