Guides
Tax & PDF documents
Configure VAT or other sales tax, understand how tax-inclusive and exclusive amounts are calculated, brand your documents and download invoice, receipt, refund and statement PDFs.
On this page
Tax settings#
Set up VAT (or GST, sales tax and so on) under Settings → Tax. You need the tax:write permission to change it; tax:read lets a user view it.
| Setting | Rules | Used for |
|---|---|---|
| Charge tax on invoices | On or off | When off, the default rate is 0%. |
| Tax name | Required, up to 30 characters (e.g. VAT, GST) | Labels on documents: the tax column, totals and the registration line. |
| Rate (%) | 0 to 100, stored to 2 decimals | Default rate for new invoice lines. |
| Prices entered on invoices | Exclude tax (tax is added on top) or Include tax (tax is part of the price) | The default for dashboard invoices, subscription invoices and hosted checkout. |
| Tax registration number | Optional, up to 50 characters | Printed as VAT No: 4123456789 on invoices, receipts, refund notes and statements. |
The page shows a live example of a R 100.00 price with your settings, and a Change history of every save (when, who, name, rate, inclusive or exclusive, and registration number). There is one rate per account; invoices can still carry different rates per line through the API (see below).
Before you save tax settings#
Until the Tax page is saved for the first time, CentraPoint uses the VAT rate and VAT number from Settings → Company settings, named "VAT", with prices exclusive of tax (tax is on when the rate is above 0). Saving the Tax page takes over from then on, and keeps those company settings in step.
How tax is calculated#
Tax is worked out per invoice line, then added up. Amounts are rounded to 2 decimals (half up) at each step:
- Line amount =
round2(quantity × unitPrice). - Line rate = the line's own
taxRateif given, else the default rate. - Line tax:
- exclusive:
round2(amount × rate / 100) - inclusive:
round2(amount × rate / (100 + rate))
- exclusive:
- Tax = sum of line taxes. Gross = sum of line amounts.
- exclusive: subtotal = gross; total =
round2(subtotal + tax) - inclusive: subtotal (net) =
round2(gross − tax); total = gross
- exclusive: subtotal = gross; total =
The invoice's headline taxRate is the rate of the line with the largest amount. Lines with an empty description or a quantity of 0 are dropped, unit prices cannot be negative, and the total must be greater than zero.
Worked example#
Two lines at a default rate of 15%: 3 × R 33.33 (standard rate) and 1 × R 10.00 with taxRate: 0 (zero-rated).
| Exclusive (tax on top) | Inclusive (tax in the price) | |
|---|---|---|
| Line 1 amount | 3 × 33.33 = 99.99 | 3 × 33.33 = 99.99 |
| Line 1 tax | round2(99.99 × 15 / 100) = round2(14.9985) = 15.00 | round2(99.99 × 15 / 115) = round2(13.0422) = 13.04 |
| Line 2 amount / tax | 10.00 / 0.00 | 10.00 / 0.00 |
| Subtotal | 109.99 | 109.99 − 13.04 = 96.95 |
| Tax | 15.00 | 13.04 |
| Total | 124.99 | 109.99 |
| Headline taxRate | 15 (line 1 is the largest) | 15 |
Where the default applies#
| Invoice created by | Rate | Inclusive or exclusive |
|---|---|---|
| Dashboard (Invoices → New) | The default rate for every line when Apply tax is ticked, else 0% | Prices include tax is pre-ticked from your setting; you can change it per invoice |
| POST /api/v1/invoices | Per-line taxRate, else the default rate | taxInclusive in the request; defaults to false, whatever your setting |
| Subscription billing | The default rate | Follows your setting. With inclusive prices the net unit price is chosen so the invoice total equals the plan price exactly |
taxInclusive on the Invoices API#
When you create an invoice with POST /api/v1/invoices, tax follows these rules:
taxInclusive(boolean, optional) says whether your line prices already include tax. It defaults tofalse: tax is added on top. Your tenant's inclusive or exclusive setting is not used by the API.lines[].taxRate(0–100, optional) sets a line's rate and always wins over the default.- Lines without
taxRateuse your tenant default: the Tax settings rate when tax is on, 0 when it is off (or the legacy company VAT rate if the Tax page was never saved).
curl -X POST "https://app.centrapoint.co.za/api/v1/invoices" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
-H "Idempotency-Key: 5b0e7c1a-3d2f-4e8b-9a6c-1f4d2e7b8c90" \
-H "Content-Type: application/json" \
-d '{
"customer": {
"externalReference": "CRM-1001"
},
"taxInclusive": true,
"lines": [
{
"description": "Hosting (3 months)",
"quantity": 3,
"unitPrice": 33.33
},
{
"description": "Zero-rated item",
"quantity": 1,
"unitPrice": 10,
"taxRate": 0
}
]
}'With a 15% default this gives the inclusive column of the worked example: subtotal 96.95, tax 13.04, total 109.99. The same request without taxInclusive gives the exclusive column: total 124.99.
Branding on documents#
On plans with Custom branding, Settings → Branding controls how PDFs, payment pages, the customer portal and emails look. It shows a live preview of an invoice and the payment page.
| Setting | Rules | Where it shows |
|---|---|---|
| Logo | PNG, JPEG or WebP, up to 2 MB, no SVG. A wide image around 600 × 150 px works best. | Top of every PDF (PNG and JPEG only; WebP logos are not shown on PDFs), payment pages, portal. Without a logo the company name is shown. |
| Icon | Square, at least 256 × 256 px, same formats | Compact places such as checkout headers and the portal browser tab. |
| Display name | Up to 150 characters, optional | Replaces your company name on documents and payment pages. |
| Primary colour | Hex, e.g. #0f5fbf | Accents on PDFs, buttons on payment pages and emails. |
| Secondary colour | Hex, optional | Secondary accents on PDFs. |
| PDF font size | 80% to 130% | Text size on PDFs. |
| PDF template | Modern, Classic or Minimal | Modern: accent bands and a filled table header. Classic: double rules and a dark table header. Minimal: thin lines and lots of white space. |
| PDF footer | Up to 1000 characters | Bottom of every PDF page, e.g. registration and banking details. |
| Payment terms | Up to 2000 characters | Invoices and statements. |
| Notes | Up to 2000 characters | Receipts, and invoices that have no notes of their own. |
Without custom branding, documents use the Modern template, a dark slate colour (#0f172a), your company name instead of a logo, and no footer, payment terms or notes. Company address, email and phone come from Settings → Company settings, and the tax registration line from Settings → Tax.
PDF documents#
Four branded A4 documents are generated on demand from live data:
Invoice#
- Title: PRO FORMA INVOICE for pro forma invoices, TAX INVOICE when the invoice has tax and you have a tax registration number, otherwise INVOICE. The dashboard's printable invoice page uses the same title.
- Invoice number, issue and due dates, the customer's account code and status (paid, overdue and so on).
- Bill-to block with the customer's name, billing email, address and their VAT number if set.
- Lines with quantity, unit price and amount, plus a tax-rate column when the invoice has tax. Invoices that mix rates list the tax per rate ("VAT @ 15% on …").
- Subtotal ("Subtotal (excl. VAT)" on inclusive invoices), tax, total, and paid and balance due once something is paid. Inclusive invoices add "Prices include VAT."
- Payment terms, and notes (the invoice's notes, else your branding notes).
Receipt#
PAYMENT RECEIPT for a payment that completed (also after a full or partial refund). The receipt number is the payment reference. It shows the date paid, payment method, related invoice, who paid, the amount (with any coupon discount), and the tax contained in the payment: the payment's own tax amount, else the invoice's tax share of this payment, else, for a direct sale with tax-inclusive settings, the tax in the amount. Refunds against the payment are listed, followed by your branding notes.
Refund note#
REFUND NOTE with the refund number, date, original payment reference and date, invoice, amount, the tax refunded (in proportion to the refunded share of the payment), reason and refund method.
Statement#
STATEMENT of a customer's account in one currency for a period: opening balance, then invoices (debits), payments against them, both online and recorded offline (credits), and refunds (debits), with a running and closing balance, and your payment terms. Dates are South African days. The default period is the last 90 days, the maximum is 5 years, and the currency defaults to that of the customer's latest invoice. Drafts and cancelled invoices are left out.
Getting the PDFs#
| Document | Dashboard | Customer portal | Payer | API |
|---|---|---|---|---|
| Invoice | Invoice page → Download PDF (Print opens a printable page) | Invoices → PDF (issued invoices only) | Attached to the invoice email | GET /api/v1/invoices/{id}/pdf |
| Receipt | Transaction page → Download receipt | Payments → Receipt | Download receipt link after paying; attached to the receipt email | GET /api/v1/receipts/{id}?format=pdf |
| Refund note | Transaction page → refunds → PDF | - | - | GET /api/v1/refunds/{id}?format=pdf |
| Statement | Customer page → statement (choose dates) | Statement → Download PDF | - | - |
The payer's receipt link appears on the payment result page once a payment is complete. It is a signed link, so a payment ID or reference alone cannot be used to fetch someone else's receipt. See Customer portal for portal access.
PDF API endpoints#
All three need an API key on a plan with the REST API and return the PDF as a download: Content-Type: application/pdf, Content-Disposition: attachment; filename="…" and Cache-Control: private, no-store. Errors are JSON in the usual error format.
/api/v1/invoices/{id}/pdfThe invoice PDF by invoice ID. Requires the Invoicing plan feature (403 plan_restricted otherwise). 404 when the invoice is not found. File name: Invoice-INV-000123.pdf.
/api/v1/receipts/{id}?format=pdfThe receipt PDF, looked up by transaction ID or payment reference. Only payments that are complete, partially refunded or refunded have receipts (404 otherwise). Without format=pdf the endpoint returns the receipt as JSON (see Receipts & refunds). File name: Receipt-CP-20260925-9F3A1C7B.pdf.
/api/v1/refunds/{id}?format=pdfThe refund note PDF, looked up by refund ID or refund number (404 when not found). Without format=pdf it returns the refund as JSON. File name: Refund-RF-000012.pdf.
# Invoice
curl -f -o invoice.pdf "https://app.centrapoint.co.za/api/v1/invoices/cmg2c0s7t0009inv0001abcd/pdf" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY"
# Receipt, by payment reference
curl -f -o receipt.pdf "https://app.centrapoint.co.za/api/v1/receipts/CP-20260925-9F3A1C7B?format=pdf" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY"
# Refund note, by refund number
curl -f -o refund.pdf "https://app.centrapoint.co.za/api/v1/refunds/RF-000012?format=pdf" \
-H "Authorization: Bearer $CENTRAPOINT_API_KEY"PDFs in emails#
The invoice email attaches the invoice PDF, and the receipt email attaches the receipt PDF. Receipt emails are sent once per completed payment when Email customers a receipt when a payment completes is on under Settings → Company settings. If a PDF cannot be generated, the email is still sent without it. Resending an email from the email log does not include attachments. See Email & templates.