CentraPoint

API

Invoices API

Create invoices with per-line VAT, send them with a pay link, record offline payments and cancel them.

On this page

Overview#

Create invoices from your system, let CentraPoint email them with a secure pay link, and keep them up to date as money arrives, whether through a gateway or offline (EFT, cash). Requires a plan that includes Invoicing; pay links also need the Payment links feature.

Invoice endpoints
EndpointPurpose
POST /api/v1/invoicesCreate (idempotent on externalReference)
GET /api/v1/invoicesList, filter by customer, reference or status
GET /api/v1/invoices/{id}Get one invoice
POST /api/v1/invoices/{id}/sendEmail it with a pay link
POST /api/v1/invoices/{id}/paymentsRecord an offline payment
POST /api/v1/invoices/{id}/cancelVoid an unpaid invoice

The invoice object#

Invoice
{
  "id": "cmg2i9n0v0005inv0001abcd",
  "number": "INV-000042",
  "status": "sent",
  "externalReference": "ORDER-1001",
  "customer": {
    "id": "cmg2c0s7t0003cust0001abcd",
    "externalReference": "CRM-1001",
    "email": "[email protected]"
  },
  "currency": "ZAR",
  "issueDate": "2026-09-24T22:00:00.000Z",
  "dueDate": "2026-10-08T21:59:59.000Z",
  "lines": [
    {
      "description": "Website hosting - October",
      "quantity": 1,
      "unitPrice": 434.78,
      "taxRate": 15,
      "amount": 434.78
    },
    {
      "description": "Domain renewal (zero-rated)",
      "quantity": 1,
      "unitPrice": 120,
      "taxRate": 0,
      "amount": 120
    }
  ],
  "subtotal": 554.78,
  "taxAmount": 65.22,
  "total": 620,
  "amountPaid": 0,
  "amountDue": 620,
  "paidAt": null,
  "payUrl": "https://app.centrapoint.co.za/pay/Xb7kP2qR9sLm4TvWz8Yc",
  "notes": "Payment due within 14 days.",
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:05:00.000Z",
  "updatedAt": "2026-09-25T08:05:00.000Z"
}
Invoice fields
FieldTypeDescription
idrequiredstringCentraPoint invoice ID.
numberrequiredstringSequential invoice number, e.g. INV-000042.
statusrequiredstringSee Statuses.
externalReferencerequiredstring | nullYour ID for the invoice.
customerrequiredobject{ id, externalReference, email }
currencyrequiredstringISO 4217 code.
issueDate, dueDaterequiredstringISO 8601 UTC timestamps (dates are interpreted in South African time).
linesrequiredobject[]description, quantity, unitPrice (excl. VAT), taxRate (%), amount (excl. VAT).
subtotal, taxAmount, totalrequirednumberTotals excluding VAT, VAT, and including VAT.
amountPaid, amountDuerequirednumberPaid so far, and the outstanding balance.
paidAtrequiredstring | nullWhen the invoice was fully paid.
payUrlrequiredstring | nullHosted payment page for the balance. See Pay links.
notesrequiredstring | nullPrinted on the invoice.
metadatarequiredobjectYour key/value data (rules).
createdAt, updatedAtrequiredstring

Statuses#

Invoice statuses
statusMeaning
draftCreated but not sent. Nothing paid.
sentSent (or payable). Nothing paid.
overduePast the due date. Nothing paid. Set by a daily job.
partially_paidSome money received, balance outstanding (reported instead of draft/sent/overdue).
paidFully paid.
cancelledVoided.

Create an invoice#

POST/api/v1/invoices
Create invoice fields
FieldTypeDescription
customerIdoptionalstringThe customer's CentraPoint ID. Send exactly one of customerId or customer.
customeroptionalobject{ "id": "…" } or { "externalReference": "…" } of an existing customer. Create customers first with the Customers API. Send exactly one of customerId or customer.
linesrequiredobject[]1–200 lines: description (1–1000 chars), quantity (> 0), unitPrice (≥ 0, excl. VAT), optional taxRate (0–100, default: your organisation's VAT rate).
externalReferenceoptionalstring1–190 chars. Makes creation idempotent; see below.
currencyoptionalstringISO 4217 code, default ZAR. Invalid codes are rejected with 400. No gateway is required (invoices can be paid offline), but payUrl is only created when a gateway accepts the currency.
issueDateoptionalstring (YYYY-MM-DD)Default today.
dueDateoptionalstring (YYYY-MM-DD)Default: today plus your invoice due-days setting.
notesoptionalstringUp to 4000 chars. Default: your invoice terms.
metadataoptionalobjectKey/value data.
sendoptionalbooleanDefault false (draft). true creates it as sent and emails it to the customer.
curl -X POST "https://app.centrapoint.co.za/api/v1/invoices" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 7d0c9b1e-2f4a-4c8e-b6d3-1a5e9f2c7b40" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "externalReference": "CRM-1001"
    },
    "externalReference": "ORDER-1001",
    "dueDate": "2026-10-08",
    "lines": [
      {
        "description": "Website hosting - October",
        "quantity": 1,
        "unitPrice": 434.78
      },
      {
        "description": "Domain renewal (zero-rated)",
        "quantity": 1,
        "unitPrice": 120,
        "taxRate": 0
      }
    ],
    "metadata": {
      "crmId": "0061x00000AbCdE"
    },
    "send": true
  }'

Returns 201 with the invoice object.

VAT and totals#

  • Each line's amount is quantity × unit price, rounded to cents; VAT is calculated per line at its own rate.
  • subtotal is the sum of line amounts, taxAmount the sum of line VAT, total their sum. The total must be greater than zero.
  • Use taxRate: 0 for zero-rated or exempt lines.

Idempotent creation#

If an invoice with the same externalReference already exists, the request returns that invoice with 200 and changes nothing: the new body is ignored and send is not repeated. Use this to make retries safe, or combine it with an Idempotency-Key.

When your plan includes payment links and one of your gateways accepts the invoice currency, CentraPoint creates a single-use pay link for the outstanding balance and returns it as payUrl. The link carries the invoice's externalReference. If the balance changes (a part payment), the next send creates a fresh link for the new balance.payUrl is null for paid or cancelled invoices, and when no link could be created. If you have a Manual EFT gateway, the pay link also offers Bank transfer (EFT), and it can be created even when Manual EFT is your only gateway; approving the payer's EFT order pays the invoice (see EFT at hosted checkout).

List invoices#

GET/api/v1/invoices
List query parameters
FieldTypeDescription
customerIdoptionalstringOnly this customer's invoices.
externalReferenceoptionalstringExact match.
statusoptionalstringdraft, sent, overdue (nothing paid yet), partially_paid, paid or cancelled.
limitoptionalinteger1–100, default 20.
curl -X GET "https://app.centrapoint.co.za/api/v1/invoices?status=partially_paid" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Get an invoice#

GET/api/v1/invoices/{id}
curl -X GET "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Send an invoice#

POST/api/v1/invoices/{id}/send

Emails the invoice to the customer, including a pay link for the balance when possible. A draft becomes sent. No body is needed. Paid and cancelled invoices can't be sent (400). Returns the updated invoice.

curl -X POST "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd/send" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: b21e6f0a-5c3d-4e8f-9a7b-2c1d0e3f4a56"

Record an offline payment#

POST/api/v1/invoices/{id}/payments

Records money received outside CentraPoint's gateways. Payments made through a pay link are recorded automatically; don't record them again.

Offline payment fields
FieldTypeDescription
amountrequirednumberGreater than 0 and not more than the outstanding balance.
methodrequiredstringeft, cash, card, wallet or other.
referenceoptionalstringUp to 190 chars, e.g. the bank statement reference.
paidAtoptionalstring (date-time)ISO 8601 with Z or an offset. Default now; cannot be in the future.
curl -X POST "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd/payments" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: c4a8e2f6-1b3d-4f5a-8c7e-9d0b2a4c6e81" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 620,
    "method": "eft",
    "reference": "FNB 2026-10-02 NKOSI",
    "paidAt": "2026-10-02T10:15:00+02:00"
  }'

Returns 201 with the updated invoice: paid when fully paid (its pay links are deactivated), otherwise partially_paid.

Cancel an invoice#

POST/api/v1/invoices/{id}/cancel

Voids an unpaid or partially paid invoice and deactivates its pay links. Optional body { "reason": "…" } (up to 500 chars) is added to the notes. Cancelling a cancelled invoice returns it unchanged. Paid invoices can't be cancelled (400); record a refund or credit instead. Money already received on a partially paid invoice is not refunded automatically.

curl -X POST "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd/cancel" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: e9f1a3c5-7b2d-4e6f-8a0c-3b5d7f9a1c24" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Order cancelled by customer"
  }'

Webhook events#

invoice.paid, invoice.partially_paid and invoice.cancelled are sent to your webhook endpoints with the invoice object as data, whether the money came through a gateway or was recorded offline.

Errors#

Invoice errors
StatuserrorWhen
400invalid_requestValidation failed; invalid ISO 4217 currency; customer not found; total not above zero; unknown status filter; invoice paid/cancelled (send, payments); amount above balance; paidAt in the future.
403plan_restricted / account_restrictedPlan lacks the API or Invoicing, or the account is read-only (writes).
404not_foundNo invoice with this ID in your organisation.
409idempotency_conflictIdempotency-Key reused with a different body.
401 / 429 / 500unauthorized / rate_limited / internal_errorSee Errors