VerityPay Documentation
Everything you need to run payroll, stay SARS-compliant, and manage your South African workforce.
Overview
VerityPay is South African payroll software designed for SARS compliance. It handles the full gross-to-net payroll pipeline including PAYE (annualised method), UIF, SDL, and ETI — and generates SARS-ready EMP201 XML and bank EFT files automatically.
Every customer account is an Organisation. All data — employees, payroll runs, leave records, documents — is strictly scoped to your organisation. No other customer can access your data.
Getting Started
Set up VerityPay and run your first payroll in under an hour.
Register your organisation
Create an account at veritypay.co.za/register. Provide your organisation name, registration number, and PAYE reference number. Your organisation slug becomes part of your dashboard URL (e.g. /acme-corp).
Configure pay types
Go to Settings → Pay Types to define your salary components: basic salary, travel allowances, housing, commissions. Mark each as taxable or non-taxable. These become selectable when running payroll.
Add employees
Add employees manually via Employees → New Employee, or bulk-import via CSV (Growth plan and above). Each employee requires: SA ID or passport number, banking details, tax details, and employment start date.
Run your first payroll
Go to Payroll → New Run. Select the pay period and employees, enter gross earnings per pay type, then click Calculate. VerityPay computes PAYE, UIF, SDL, and ETI automatically.
Review, approve, and export
A second admin reviews and approves the run (two-person rule enforced by the system). Download payslips (PDF), bank EFT file (CSV), and EMP201 XML for SARS eFiling.
Core Concepts
Organisations
An Organisation is your company on VerityPay. It has a unique slug (e.g. acme-corp) used in all dashboard and portal URLs. All data is scoped to your organisation — employees, payroll runs, tax settings, and reports. Multiple admins can be invited with the Owner or Payroll Admin role.
Employees
Each employee record contains:
- Identity: SA ID number or passport (AES-256 encrypted at rest)
- Employment: start date, department, job title, employment type
- Payroll profile: pay type allocations, UIF opt-out status where applicable
- Banking: bank name, account number (AES-256 encrypted), account type
- Tax: PAYE directive number if applicable, medical aid credits
- Leave balances: annual, sick, and family responsibility days
Pay Types
Pay types are reusable income and deduction components configured per organisation. Examples: "Basic Salary" (taxable), "Travel Allowance" (partially taxable), "Medical Aid Employee Contribution" (deduction). Custom pay types are created in Settings → Pay Types.
Payroll Runs
A payroll run is an immutable record of one pay period. Once approved and completed it cannot be edited. Corrections are handled by creating a new correction run for the affected period. Each run records calculatedById and approvedById — these must be different users (two-person rule).
Payroll Processing
The payroll engine follows a strict gross-to-net pipeline to ensure SARS compliance and auditability.
Three Gross Definitions
SARS requires different income bases for different contributions:
| Gross Type | Includes | Used For |
|---|---|---|
| gross_for_paye | All taxable income | PAYE calculation |
| gross_for_uif | Basic + regular commission + allowances — excludes bonuses and overtime | UIF calculation |
| gross_for_sdl | Everything — no exclusions | SDL calculation |
Two-Person Approval Rule
Every payroll run requires two different administrators: one to calculate and one to approve. The system enforces calculatedById ≠ approvedById at the database level. This mirrors South African corporate governance best practices and reduces payroll fraud risk.
Idempotency
Every financial operation is assigned an idempotency key stored in the database. Duplicate requests (e.g. double-submit due to network error) are safely de-duplicated and will not create double payments.
Tax Calculations
All tax calculations are implemented as pure, stateless functions with no database access or side effects — making them independently testable and auditable. SARS 2025/26 tables are used.
PAYE — Annualised Method
VerityPay uses the SARS-prescribed annualised method:
- Annualise monthly gross:
monthly_gross × 12 - Find the applicable SARS tax bracket
- Apply:
bracket_base + (annualised_gross − bracket_floor) × bracket_rate - Subtract applicable rebates (primary, secondary, tertiary)
- Divide annual tax by 12 to get monthly PAYE
2025/26 Rebates
2025/26 Tax-Free Thresholds
UIF
Unemployment Insurance Fund contributions are calculated at 1% employee + 1% employer, capped at R177.12/month each (ceiling remuneration R17,712/month). UIF excludes bonuses, overtime pay, retrenchment pay, and retirement lump sums.
SDL
Skills Development Levy is 1% employer only, payable if your organisation's total annual payroll exceeds R500,000. SDL applies to all remuneration with no exclusions. VerityPay tracks your rolling annual payroll and applies SDL only once the threshold is crossed.
ETI
Employment Tax Incentive reduces the employer's monthly PAYE liability for qualifying employees. Qualifying criteria: aged 18–29, earning R2,000–R6,500 per month, within first 24 months of employment at your organisation, employer not in default with SARS. VerityPay automatically identifies qualifying employees and calculates the ETI reduction each month.
Leave Management
VerityPay implements full BCEA (Basic Conditions of Employment Act) leave. Balances accrue monthly and are tracked per employee.
| Leave Type | Entitlement | Carry Over | Notes |
|---|---|---|---|
| Annual | 15 working days/year | Yes | Accrues monthly. Paid out on termination (taxable, IRP5 code 3606). |
| Sick | 30 days / 3-year cycle | Within cycle | Resets at start of new 3-year cycle from employment date. |
| Family Responsibility | 3 days/year | No | Resets on employment anniversary. Not carried over or paid out. |
On termination, VerityPay automatically calculates outstanding annual leave and adds it as a taxable line item on the final payslip (IRP5 code 3606, as required by SARS).
Employee Portal
Every organisation gets a self-service employee portal at /portal/[your-org-slug]. Employees log in with their work email.
Payslips
View and download PDF payslips for all past pay periods.
Leave Requests
Submit annual, sick, and family responsibility leave. Track approval status in real time.
Profile
Update contact details and banking information. All PII is encrypted at rest.
POPIA Data Rights
Download a complete export of personal data, or submit a deletion request (Section 23 of POPIA).
Compliance & Reports
EMP201 Monthly Returns
After each payroll run, VerityPay generates an EMP201-compatible XML file containing PAYE, UIF, and SDL totals for the month. Download from Reports → [run] → EMP201 XML and upload directly to SARS eFiling.
IRP5 Annual Reconciliation
At tax year-end (February), VerityPay generates IRP5 certificates for all employees — including all income codes, deductions, and employer contributions for the year. Export as XML for SARS e@syFile™ submission (Growth plan and above).
Bank EFT Files
VerityPay generates salary payment CSV files in the native formats of the four major South African banks:
Download the EFT file from any completed payroll run and upload it directly to your business banking portal. No manual re-entry of employee banking details required.
Integrations
Xero
Connect VerityPay to your Xero account via Settings → Integrations. Once connected, payroll journals are automatically pushed to Xero after each approved run — debit wages expense, credit payables — saving manual double-entry. The integration uses OAuth 2.0 and respects your Xero chart of accounts.
CSV Employee Import
Available on the Growth plan and above. Download the VerityPay employee CSV template from Employees → Import, fill in your employee data, and upload. The importer validates SA ID numbers, bank account details, and required fields before saving. Errors are shown per row — no partial imports.
Email & SMS Notifications
Payslip notifications are sent automatically to employees by email (Resend) and SMS (Africa's Talking) after a run is approved. Notification preferences are configurable per organisation in Settings → Notifications.
Developer API
VerityPay exposes a REST API for programmatic access. All endpoints are organisation-scoped and require a valid API key.
Authentication
All API requests require a Bearer token in the Authorization header. Generate your API key in Settings → Integrations.
Authorization: Bearer YOUR_API_KEY Content-Type: application/json
Base URL
https://app.veritypay.co.za/api/v1
Endpoints
/:orgSlug/irp5Returns IRP5 data for all employees in the organisation for the specified tax year.
Query Parameters
yearTax year (e.g. 2025). Defaults to current year.Example Request
curl -X GET \ "https://app.veritypay.co.za/api/v1/acme-corp/irp5?year=2025" \ -H "Authorization: Bearer YOUR_API_KEY"
/:orgSlug/invitationsInvite a new admin or payroll user to the organisation. An email is sent to the provided address with a secure invitation link.
Request Body
{
"email": "jane@acme.co.za",
"role": "payroll_admin" // "owner" | "payroll_admin"
}Example Request
curl -X POST \
"https://app.veritypay.co.za/api/v1/acme-corp/invitations" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"jane@acme.co.za","role":"payroll_admin"}'Rate Limits
The API is rate-limited to 100 requests per minute per API key. Exceeding this returns a 429 Too Many Requests response. Use the Retry-After header value to determine when to retry.
JavaScript / TypeScript SDK
A fully typed SDK is available for Node.js and browser environments:
npm install @veritypay/sdk
import { VerityPayClient } from '@veritypay/sdk'
const client = new VerityPayClient({
apiKey: process.env.VERITYPAY_API_KEY,
orgSlug: 'acme-corp',
})
// Fetch IRP5 data for 2025
const irp5 = await client.irp5.list({ year: 2025 })
// Invite a payroll admin
await client.invitations.create({
email: 'jane@acme.co.za',
role: 'payroll_admin',
})Webhook Events
VerityPay can POST event notifications to your endpoint when key events occur. Configure your webhook URL in Settings → Integrations.
| Event | Triggered When |
|---|---|
| payroll.run.approved | A payroll run is approved and locked |
| payroll.run.exported | EFT or EMP201 file is downloaded |
| employee.created | New employee record is saved |
| employee.terminated | Employee is marked as terminated |
| leave.approved | Leave request is approved by admin |
Security & POPIA
Data Encryption
All personally identifiable information — SA ID numbers, bank account numbers, passport numbers — is encrypted with AES-256 at the application layer before being written to the database. Database administrators cannot read raw PII values.
Role-Based Access Control
OwnerFull access including billing, user management, and organisation settings.
Payroll AdminManage employees, run payroll, and access reports. Cannot change billing or delete the organisation.
EmployeeAccess to own payslips, leave requests, and profile via the Employee Portal only.
POPIA Compliance
- Employees can download a full export of their personal data from the portal
- Employees can submit a POPIA deletion request (Section 23)
- Data is retained only as long as required by SARS obligations (5 years)
- No data is sold or shared with third parties beyond the processors listed in our Privacy Policy
- All data is hosted in South Africa
Reporting a Vulnerability
If you discover a security vulnerability in VerityPay, please disclose it responsibly by emailing security@veritypay.co.za. Do not create a public GitHub issue for security findings. We will respond within 48 hours.