Hlawula MoR is still in development. Payments on this site are demos and nobody is charged. Try the demo checkout

API reference

API reference

A JSON API over HTTPS. Every amount is an integer in cents of South African rand, and every country is a two-letter ISO code.

Overview

Base URLhttps://hlawula.co.za
FormatJSON in and out, camelCase field names
MoneyInteger cents, ZAR. 99900 is R 999.00
Errors4xx with { "error": "code", "message": "..." }
AuthNone in the demo. Secret keys per merchant are planned.
Error shape
{ "error": "card_invalid", "message": "Enter a valid card number." }

Checkout sessions

Create a session

POST/api/checkout/sessions

planIdstring, required

plan_starter, plan_pro or plan_scale.

emailstring

Buyer email. Shown on the invoice.

countrystring

Buyer country. Decides the tax line. Defaults to ZA.

Response 200
{
  "id": "cs_live_0015a4a0ff9d",
  "status": "open",
  "email": "thandi@example.co.za",
  "country": "ZA",
  "plan": { "id": "plan_pro", "name": "Pro", "priceCents": 99900, "interval": "month", "trialDays": 14 },
  "subtotalCents": 99900,
  "taxLines": [
    { "label": "VAT — 15%", "jurisdiction": "South Africa — SARS", "rate": 0.15, "amountCents": 14985, "collectedAndRemitted": true }
  ],
  "totalCents": 114885,
  "currency": "ZAR",
  "seller": { "legalName": "Hlawula MoR (Pty) Ltd", "registrationNumber": "2026/184220/07", "vatNumber": "4910263842" }
}

Errors: 400 unknown_plan.

Retrieve a session

GET/api/checkout/sessions/{id}

Returns the session in the same shape. 404 session_not_found if it doesn't exist.

Update a session

PUT/api/checkout/sessions/{id}

countrystring

New buyer country. Tax is recalculated.

emailstring

New buyer email.

Errors: 404 session_not_found, 400 already_paid.

Pay a session

POST/api/checkout/sessions/{id}/pay

methodstring

apple_pay, google_pay, samsung_pay, card, capitec_pay, absa_pay, nedbank_direct_eft or pay_by_bank. Defaults to card.

walletTokenstring

Wallets only. The encrypted token from the device.

cardNumber, expiry, cvc, namestring

Card only. Expiry as MM/YY.

mobilestring

Capitec Pay and Absa Pay. South African cellphone number.

bankstring

Pay by bank. One of Absa, Capitec, Discovery Bank, FNB, Investec, Nedbank, Standard Bank, TymeBank.

Response 200
{
  "outcome": "paid",
  "paymentMethod": { "id": "apple_pay", "name": "Apple Pay", "label": "apple pay" },
  "receipt": {
    "id": "txn_1061", "country": "ZA", "amountCents": 99900, "taxCents": 14985,
    "status": "succeeded", "method": "apple pay", "createdAt": "2026-11-09T11:50:36Z"
  },
  "invoice": {
    "number": "INV-2026-0341",
    "seller": "Hlawula MoR (Pty) Ltd",
    "vatNumber": "4910263842",
    "buyerEmail": "thandi@example.co.za",
    "buyerCountry": "ZA",
    "planName": "Pro",
    "subtotalCents": 99900,
    "lines": [ { "label": "VAT — 15%", "amountCents": 14985 } ],
    "totalCents": 114885,
    "issuedAt": "2026-11-09T11:50:36Z"
  }
}

Errors: 404 session_not_found, 400 already_paid, plus the payment method errors listed under Payment methods.

Payment methods

List payment methods

GET/api/payment-methods

countryquery string

Optional. Sets available on each method for this buyer country.

Response 200 (first two of eight)
[
  { "id": "apple_pay", "name": "Apple Pay", "kind": "wallet", "settlement": "Instant", "countries": null, "available": true },
  { "id": "capitec_pay", "name": "Capitec Pay", "kind": "bank_app", "settlement": "Instant", "countries": ["ZA"], "available": false }
]

kind is wallet, card, bank_app or bank_transfer. countries: null means available everywhere.

Subscriptions

List subscriptions

GET/api/subscriptions

All subscriptions, latest billing date first. See Subscriptions and dunning for the fields.

Retry a failed renewal

POST/api/subscriptions/{id}/retry

Response 200
{ "outcome": "recovered", "message": "Payment recovered via aggregator retry.", "subscription": { "id": "sub_1002", "status": "active" } }

outcome is recovered or failed. Errors: 404 subscription_not_found.

List plans

GET/api/plans

The plans buyers can subscribe to, with priceCents excluding tax.

Tax

Quote tax

GET/api/tax/quote

countryquery string, required

Buyer country.

amountquery integer, required

Amount in cents, zero or more.

Returns subtotalCents, taxLines and totalCents. Errors: 400 amount_invalid.

Payouts

List payouts

GET/api/payouts

All payouts, newest first, with gross, each deduction, net, status and bank reference.

Run a payout

POST/api/payouts/run

Pays out everything settled since the last payout. Errors: 400 nothing_to_settle.

Reporting

Dashboard summary

GET/api/summary

MRR, 30-day gross volume, active and past-due subscription counts, the next payout estimate and a 14-day revenue series.

Recent transactions

GET/api/transactions

The latest 25 payments with customer, country, amount, tax, method and status.

Seller details

GET/api/config

Hlawula's legal name, registration number, VAT number, settlement bank and aggregator.

Health check

GET/api/health

json
{ "status": "ok", "service": "hlawula-mor", "time": "2026-11-09T12:00:00Z" }

Planned

Secret API keys, webhooks for payment and subscription events, refunds, and idempotency keys on payments.