CentraPoint

API

API reference

Endpoint reference generated from the CentraPoint OpenAPI 3.1 specification, with code samples.

On this page

CentraPoint API v1.8.1 · OpenAPI 3.1.0 · Base URL https://app.centrapoint.co.za

The CentraPoint REST API lets your systems manage customers and invoices, create hosted payment links, subscriptions and EFT orders, check the status of payments and read reconciliation results. Every API key may make 120 requests per minute; responses report usage in X-RateLimit-* headers. All requests are authenticated with a tenant-scoped API key sent as a Bearer token. API access requires a plan that includes the REST API (Growth or higher).

Outbound webhooks that CentraPoint sends to your endpoints are described in the webhooks section. Gateway notification URLs (/api/webhooks/{type}) are called by payment gateways, not by API clients, and are therefore not part of this specification.

Download the machine-readable specification: openapi.json. Import it into Postman, Insomnia or a code generator.

GET/api/v1/payment-links

Returns your organisation's payment links, newest first, each with the payments made through it (up to 50 per link). Filter by externalReference to find the link for one of your orders and discover its payment references.

Query parameters
FieldTypeDescription
externalReferencestring

Only links with exactly this external reference (leading/trailing whitespace ignored).

limitinteger

Maximum number of links to return, 1–100. Invalid or missing values fall back to 20; values out of range are clamped.

≥ 1 · ≤ 100 · default 20

200Matching links.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredPaymentLinkWithPayments[]
Show fields
data fields
FieldTypeDescription
idrequiredstring

Payment link ID.

urlrequiredstring (uri)

Hosted payment page to send to the payer: https://app.centrapoint.co.za/pay/{token}.

titlerequiredstring
descriptionrequiredstring | null
amountrequirednumber

Amount after rounding to 2 decimal places.

currencyrequiredstring

Upper-case ISO 4217 code.

externalReferencerequiredstring | null

Your identifier, as supplied when the link was created.

returnUrlrequiredstring (uri) | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

recurringrequirednull | object
Show fields
recurring fields
FieldTypeDescription
frequencyrequiredstring
amountrequirednumber
singleUserequiredboolean

Whether the link deactivates after its first successful payment.

activerequiredboolean

False once deactivated (in the dashboard, or after a single-use link is paid).

expiresAtrequiredstring (date-time) | null
paidCountrequiredinteger

Number of successful payments made through the link.

createdAtrequiredstring (date-time)
paymentsrequiredLinkPayment[]

Checkout attempts made through the link, newest first. Each attempt is a transaction with its own reference.

Show fields
payments fields
FieldTypeDescription
referencerequiredstring

Payment reference. Use it with GET /api/v1/transactions/{reference}.

statusrequiredstring

complete is the only status that means money was received. refunded / partially_refunded are set when a refund is recorded in the dashboard.

One of: pending, complete, failed, cancelled, refunded, partially_refunded

amountrequirednumber
currencyrequiredstring
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
subscriptionnull | object

The latest subscription started by this link, or null.

Show fields
subscription fields
FieldTypeDescription
idrequiredstring
statusrequiredstring
Example
{
  "data": [
    {
      "id": "cmg1k2x3y0001abcd1234efgh",
      "url": "https://app.centrapoint.co.za/pay/Xb7kP2qR9sLm4TvWz8Yc",
      "title": "Website hosting - October",
      "description": "Monthly hosting for example.co.za",
      "amount": 499,
      "currency": "ZAR",
      "externalReference": "ORDER-1001",
      "singleUse": true,
      "active": false,
      "expiresAt": "2026-10-31T21:59:59.000Z",
      "paidCount": 1,
      "createdAt": "2026-09-25T08:10:02.114Z",
      "payments": [
        {
          "reference": "CP-20260925-9F3A1C7B",
          "status": "complete",
          "amount": 499,
          "currency": "ZAR",
          "paidAt": "2026-09-25T08:14:03.512Z",
          "createdAt": "2026-09-25T08:12:47.020Z"
        },
        {
          "reference": "CP-20260925-41D07E2A",
          "status": "cancelled",
          "amount": 499,
          "currency": "ZAR",
          "paidAt": null,
          "createdAt": "2026-09-25T08:11:15.873Z"
        }
      ],
      "returnUrl": null,
      "metadata": {},
      "recurring": null,
      "subscription": null
    }
  ]
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "API access is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
curl -X GET "https://app.centrapoint.co.za/api/v1/payment-links?externalReference=ORDER-1001" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"
POST/api/v1/payment-links

Creates a hosted payment link at /pay/{token}. When customerEmail is supplied, the link is attached to the existing customer with that email address in your organisation, or a new customer is created (subject to your plan's customer limit).

Requires the API and Payment links features on your plan, and an account that is not read-only (suspended, cancelled or expired trial).

Pass externalReference (your order ID) so you can later find the link and the payment references made through it with GET /api/v1/payment-links?externalReference=.

Unknown body fields are ignored. This endpoint is not idempotent: retrying a request creates another link.

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

application/json · required

Request body fields
FieldTypeDescription
titlerequiredstring

Shown to the payer. Leading and trailing whitespace is trimmed before the length check.

1–100 chars

descriptionstring

Optional longer text shown under the title on the payment page.

max 255 chars

amountrequirednumber

Amount in major units (e.g. 499.00 rand). Rounded to 2 decimal places. Gateways may enforce their own minimums or whole-unit amounts.

> 0 · ≤ 10 000 000

currencystring

ISO 4217 currency code, upper-cased by the server. Must be a valid ISO 4217 code and accepted by at least one of your enabled checkout gateways (or, for once-off links, by your Manual EFT gateway); otherwise the request fails with 400 invalid_request.

default "ZAR"

externalReferencestring

Your own identifier for this link, e.g. your order or invoice number. Trimmed before validation. Not required to be unique. Use it with GET /api/v1/payment-links?externalReference= to find the link and its payment references later.

1–100 chars

returnUrlstring (uri)

Where to send the payer after a final outcome. Must be https and on an origin allow-listed under Settings → API keys → Allowed return URLs. CentraPoint appends reference and status (complete, failed or cancelled) query parameters. Never trust the redirect: confirm server-side.

max 1000 chars

metadataMetadataInput

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerIdstring

Attach an existing customer (takes precedence over customerEmail).

recurringobject

Start a gateway-managed subscription when the link is paid. Requires a plan with recurring billing and an enabled gateway that supports it (PayFast, Netcash Pay Now); only such gateways are offered to the payer.

Show fields
recurring fields
FieldTypeDescription
frequencyrequiredstring

One of: monthly, quarterly, biannually, annually

amountnumber

Amount of each later collection. Defaults to the link amount.

> 0 · ≤ 10 000 000

productIdstring

ID of a product in your organisation. Recurring products start a gateway-managed subscription at checkout (plan and gateway permitting).

invoiceIdstring

ID of an invoice in your organisation. Successful payments are applied to the invoice.

customerEmailstring (email)

Attach the link to a customer. Matched case-insensitively against existing customers; a new customer is created if none exists.

customerFirstNamestring

Used only when a new customer is created. Defaults to the part of the email before @.

max 100 chars

customerLastNamestring

Used only when a new customer is created.

max 100 chars

singleUseboolean

When true, the link is deactivated after its first successful payment.

default true

expiresAtstring (date-time)

ISO 8601 timestamp with Z or a UTC offset (e.g. 2026-10-31T23:59:59+02:00), including seconds. Must be in the future and at most 1 year ahead. After this moment the link cannot be paid.

201Payment link created.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
201 response fields
FieldTypeDescription
idrequiredstring

Payment link ID.

urlrequiredstring (uri)

Hosted payment page to send to the payer: https://app.centrapoint.co.za/pay/{token}.

titlerequiredstring
descriptionrequiredstring | null
amountrequirednumber

Amount after rounding to 2 decimal places.

currencyrequiredstring

Upper-case ISO 4217 code.

externalReferencerequiredstring | null

Your identifier, as supplied when the link was created.

returnUrlrequiredstring (uri) | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

recurringrequirednull | object
Show fields
recurring fields
FieldTypeDescription
frequencyrequiredstring
amountrequirednumber
singleUserequiredboolean

Whether the link deactivates after its first successful payment.

activerequiredboolean

False once deactivated (in the dashboard, or after a single-use link is paid).

expiresAtrequiredstring (date-time) | null
paidCountrequiredinteger

Number of successful payments made through the link.

createdAtrequiredstring (date-time)
Example
{
  "id": "cmg1k2x3y0001abcd1234efgh",
  "url": "https://app.centrapoint.co.za/pay/Xb7kP2qR9sLm4TvWz8Yc",
  "title": "Website hosting - October",
  "description": "Monthly hosting for example.co.za",
  "amount": 499,
  "currency": "ZAR",
  "externalReference": "ORDER-1001",
  "singleUse": true,
  "active": true,
  "expiresAt": "2026-10-31T21:59:59.000Z",
  "paidCount": 0,
  "createdAt": "2026-09-25T08:10:02.114Z",
  "returnUrl": "https://shop.example.co.za/checkout/done",
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "recurring": null
}
400The body failed validation (`issues` lists each problem), or a business rule failed: unknown product/invoice, invalid or unsupported currency, or `expiresAt` not in the future / more than 1 year ahead.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Validation failure
{
  "error": "invalid_request",
  "message": "Invalid body",
  "issues": [
    {
      "origin": "number",
      "code": "too_small",
      "minimum": 0,
      "inclusive": false,
      "path": [
        "amount"
      ],
      "message": "Too small: expected number to be >0"
    }
  ]
}
Unknown product
{
  "error": "invalid_request",
  "message": "Product not found"
}
Currency not accepted
{
  "error": "invalid_request",
  "message": "None of your enabled payment gateways accept USD. Enable a gateway that supports USD first."
}
Expiry in the past
{
  "error": "invalid_request",
  "message": "expiresAt must be in the future"
}
returnUrl origin not allowed
{
  "error": "invalid_request",
  "message": "returnUrl origin https://shop.example.co.za is not allowed - add it under Settings > API keys > Allowed return URLs"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Your plan does not include the API or payment links (`plan_restricted`), a plan quota such as the customer limit was reached (`plan_limit`), or the account is read-only (`account_restricted`).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
planRestricted
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
planLimit
{
  "error": "plan_limit",
  "message": "Customers limit reached (2000/2000) on the Growth plan. Upgrade under Settings > Billing."
}
accountRestricted
{
  "error": "account_restricted",
  "message": "Your free trial has ended. Choose a plan to continue."
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
413Request body larger than 100 000 characters.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Request body too large"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
curl -X POST "https://app.centrapoint.co.za/api/v1/payment-links" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Pro plan",
    "amount": 499,
    "externalReference": "SUB-ACME-PRO",
    "customerId": "cmg2c0s7t0003cust0001abcd",
    "recurring": {
      "frequency": "monthly"
    },
    "singleUse": true
  }'
GET/api/v1/payment-links/{id}

Returns one payment link in your organisation with the payments made through it (newest first, up to 100).

Path parameters
FieldTypeDescription
idrequiredstring

Payment link ID returned when the link was created.

200The payment link.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring

Payment link ID.

urlrequiredstring (uri)

Hosted payment page to send to the payer: https://app.centrapoint.co.za/pay/{token}.

titlerequiredstring
descriptionrequiredstring | null
amountrequirednumber

Amount after rounding to 2 decimal places.

currencyrequiredstring

Upper-case ISO 4217 code.

externalReferencerequiredstring | null

Your identifier, as supplied when the link was created.

returnUrlrequiredstring (uri) | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

recurringrequirednull | object
Show fields
recurring fields
FieldTypeDescription
frequencyrequiredstring
amountrequirednumber
singleUserequiredboolean

Whether the link deactivates after its first successful payment.

activerequiredboolean

False once deactivated (in the dashboard, or after a single-use link is paid).

expiresAtrequiredstring (date-time) | null
paidCountrequiredinteger

Number of successful payments made through the link.

createdAtrequiredstring (date-time)
paymentsrequiredLinkPayment[]

Checkout attempts made through the link, newest first. Each attempt is a transaction with its own reference.

Show fields
payments fields
FieldTypeDescription
referencerequiredstring

Payment reference. Use it with GET /api/v1/transactions/{reference}.

statusrequiredstring

complete is the only status that means money was received. refunded / partially_refunded are set when a refund is recorded in the dashboard.

One of: pending, complete, failed, cancelled, refunded, partially_refunded

amountrequirednumber
currencyrequiredstring
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
subscriptionnull | object

The latest subscription started by this link, or null.

Show fields
subscription fields
FieldTypeDescription
idrequiredstring
statusrequiredstring
Example
{
  "id": "cmg1k2x3y0001abcd1234efgh",
  "url": "https://app.centrapoint.co.za/pay/Xb7kP2qR9sLm4TvWz8Yc",
  "title": "Website hosting - October",
  "description": "Monthly hosting for example.co.za",
  "amount": 499,
  "currency": "ZAR",
  "externalReference": "ORDER-1001",
  "singleUse": true,
  "active": false,
  "expiresAt": "2026-10-31T21:59:59.000Z",
  "paidCount": 1,
  "createdAt": "2026-09-25T08:10:02.114Z",
  "payments": [
    {
      "reference": "CP-20260925-9F3A1C7B",
      "status": "complete",
      "amount": 499,
      "currency": "ZAR",
      "paidAt": "2026-09-25T08:14:03.512Z",
      "createdAt": "2026-09-25T08:12:47.020Z"
    },
    {
      "reference": "CP-20260925-41D07E2A",
      "status": "cancelled",
      "amount": 499,
      "currency": "ZAR",
      "paidAt": null,
      "createdAt": "2026-09-25T08:11:15.873Z"
    }
  ],
  "returnUrl": null,
  "metadata": {},
  "recurring": null,
  "subscription": null
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "API access is not included in your plan"
}
404No payment link with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Payment link not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
curl -X GET "https://app.centrapoint.co.za/api/v1/payment-links/cmg1k2x3y0001abcd1234efgh" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

List customers#

GET/api/v1/customers

Newest first.

Query parameters#

Query parameters
FieldTypeDescription
externalReferencestring

Exact match on your customer ID.

emailstring

Exact match (case-insensitive).

limitinteger

1–100, default 20. Out-of-range values are clamped; invalid values fall back to 20.

≥ 1 · ≤ 100 · default 20

Responses#

200Customers.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredCustomer[]
Show fields
data fields
FieldTypeDescription
idrequiredstring
accountCoderequiredstring

Customer account code assigned by CentraPoint.

externalReferencerequiredstring | null

Your ID for the customer.

emailrequiredstring
firstNamerequiredstring
lastNamerequiredstring | null
companyrequiredstring | null
vatNumberrequiredstring | null
phonerequiredstring | null
addressrequiredstring | null
activerequiredboolean
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "data": [
    {
      "id": "cmg2c0s7t0003cust0001abcd",
      "accountCode": "CUS-00042",
      "externalReference": "CRM-1001",
      "email": "[email protected]",
      "firstName": "Thandi",
      "lastName": "Nkosi",
      "company": "Nkosi Trading (Pty) Ltd",
      "vatNumber": "4123456789",
      "phone": "+27821234567",
      "address": "12 Long Street, Cape Town, 8001",
      "active": true,
      "metadata": {
        "crmId": "0061x00000AbCdE"
      },
      "createdAt": "2026-09-25T08:00:00.000Z",
      "updatedAt": "2026-09-25T08:00:00.000Z"
    }
  ]
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access (or the feature) is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/customers" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Create or upsert a customer#

POST/api/v1/customers

Without externalReference: creates a customer (201). With externalReference: upsert keyed on it — updates the customer with that reference (200), otherwise adopts an existing customer with the same email and no reference (200), otherwise creates one (201). Available on any plan with API access; creating counts towards your customer limit.

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json · required

Request body fields
FieldTypeDescription
externalReferencestring

Your ID. When set, the request is an upsert keyed on it.

1–190 chars

emailrequiredstring (email)

Stored lower-cased.

max 200 chars

firstNamerequiredstring

1–100 chars

lastNamestring | null

max 100 chars

companystring | null

max 200 chars

vatNumberstring | null

max 30 chars

phonestring | null

max 30 chars

addressstring | null

max 1000 chars

metadataMetadataInput | null

Responses#

200Existing customer updated (upsert).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
200 response fields
FieldTypeDescription
idrequiredstring
accountCoderequiredstring

Customer account code assigned by CentraPoint.

externalReferencerequiredstring | null

Your ID for the customer.

emailrequiredstring
firstNamerequiredstring
lastNamerequiredstring | null
companyrequiredstring | null
vatNumberrequiredstring | null
phonerequiredstring | null
addressrequiredstring | null
activerequiredboolean
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2c0s7t0003cust0001abcd",
  "accountCode": "CUS-00042",
  "externalReference": "CRM-1001",
  "email": "[email protected]",
  "firstName": "Thandi",
  "lastName": "Nkosi",
  "company": "Nkosi Trading (Pty) Ltd",
  "vatNumber": "4123456789",
  "phone": "+27821234567",
  "address": "12 Long Street, Cape Town, 8001",
  "active": true,
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:00:00.000Z",
  "updatedAt": "2026-09-25T08:00:00.000Z"
}
201Customer created.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
201 response fields
FieldTypeDescription
idrequiredstring
accountCoderequiredstring

Customer account code assigned by CentraPoint.

externalReferencerequiredstring | null

Your ID for the customer.

emailrequiredstring
firstNamerequiredstring
lastNamerequiredstring | null
companyrequiredstring | null
vatNumberrequiredstring | null
phonerequiredstring | null
addressrequiredstring | null
activerequiredboolean
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2c0s7t0003cust0001abcd",
  "accountCode": "CUS-00042",
  "externalReference": "CRM-1001",
  "email": "[email protected]",
  "firstName": "Thandi",
  "lastName": "Nkosi",
  "company": "Nkosi Trading (Pty) Ltd",
  "vatNumber": "4123456789",
  "phone": "+27821234567",
  "address": "12 Long Street, Cape Town, 8001",
  "active": true,
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:00:00.000Z",
  "updatedAt": "2026-09-25T08:00:00.000Z"
}
400Validation failed or invalid metadata.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Invalid body",
  "issues": [
    {
      "code": "invalid_format",
      "format": "email",
      "path": [
        "email"
      ],
      "message": "Invalid email address"
    }
  ]
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API, customer limit reached (`plan_limit`), or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_limit",
  "message": "Customers limit reached (2000/2000) on the Growth plan. Upgrade under Settings > Billing."
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/customers" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
  -H "Content-Type: application/json" \
  -d '{
    "externalReference": "CRM-1001",
    "email": "[email protected]",
    "firstName": "Thandi",
    "lastName": "Nkosi",
    "company": "Nkosi Trading (Pty) Ltd",
    "vatNumber": "4123456789",
    "phone": "+27821234567",
    "metadata": {
      "crmId": "0061x00000AbCdE"
    }
  }'

Get a customer#

GET/api/v1/customers/{id}

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The customer.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
accountCoderequiredstring

Customer account code assigned by CentraPoint.

externalReferencerequiredstring | null

Your ID for the customer.

emailrequiredstring
firstNamerequiredstring
lastNamerequiredstring | null
companyrequiredstring | null
vatNumberrequiredstring | null
phonerequiredstring | null
addressrequiredstring | null
activerequiredboolean
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2c0s7t0003cust0001abcd",
  "accountCode": "CUS-00042",
  "externalReference": "CRM-1001",
  "email": "[email protected]",
  "firstName": "Thandi",
  "lastName": "Nkosi",
  "company": "Nkosi Trading (Pty) Ltd",
  "vatNumber": "4123456789",
  "phone": "+27821234567",
  "address": "12 Long Street, Cape Town, 8001",
  "active": true,
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:00:00.000Z",
  "updatedAt": "2026-09-25T08:00:00.000Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access (or the feature) is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No customer with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Customer not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/customers/cmg2c0s7t0003cust0001abcd" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Update a customer#

PATCH/api/v1/customers/{id}

Partial update. Omitted fields are unchanged; null clears optional fields; metadata replaces the whole map. Unknown fields are rejected. Idempotency-Key is not used (PATCH is naturally repeatable).

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Request body#

application/json · required

Request body fields
FieldTypeDescription
externalReferencestring | null

Must not be used by another customer.

1–190 chars

emailstring (email)

Stored lower-cased.

max 200 chars

firstNamestring

1–100 chars

lastNamestring | null

max 100 chars

companystring | null

max 200 chars

vatNumberstring | null

max 30 chars

phonestring | null

max 30 chars

addressstring | null

max 1000 chars

metadataMetadataInput | null
activeboolean

Responses#

200Updated customer.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
accountCoderequiredstring

Customer account code assigned by CentraPoint.

externalReferencerequiredstring | null

Your ID for the customer.

emailrequiredstring
firstNamerequiredstring
lastNamerequiredstring | null
companyrequiredstring | null
vatNumberrequiredstring | null
phonerequiredstring | null
addressrequiredstring | null
activerequiredboolean
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2c0s7t0003cust0001abcd",
  "accountCode": "CUS-00042",
  "externalReference": "CRM-1001",
  "email": "[email protected]",
  "firstName": "Thandi",
  "lastName": "Nkosi",
  "company": "Nkosi Trading (Pty) Ltd",
  "vatNumber": "4123456789",
  "phone": "+27821234567",
  "address": "12 Long Street, Cape Town, 8001",
  "active": true,
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:00:00.000Z",
  "updatedAt": "2026-09-25T08:00:00.000Z"
}
400Validation failed, unknown field, or externalReference used by another customer.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Another customer already has that externalReference"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Account is read-only (suspended, cancelled or trial ended), or a plan feature/quota is missing.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "account_restricted",
  "message": "Your free trial has ended. Choose a plan to continue."
}
404No customer with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Customer not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X PATCH "https://app.centrapoint.co.za/api/v1/customers/cmg2c0s7t0003cust0001abcd" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+27829876543",
    "company": null,
    "active": true
  }'

List invoices#

GET/api/v1/invoices

Newest first. status=draft|sent|overdue returns only invoices with nothing paid; use partially_paid for those with part payments.

Query parameters#

Query parameters
FieldTypeDescription
customerIdstring
externalReferencestring
statusstring

One of: draft, sent, overdue, partially_paid, paid, cancelled

limitinteger

1–100, default 20. Out-of-range values are clamped; invalid values fall back to 20.

≥ 1 · ≤ 100 · default 20

Responses#

200Invoices.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredInvoice[]
Show fields
data fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "data": [
    {
      "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"
    }
  ]
}
400Unknown status.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "status must be one of draft, sent, overdue, paid, cancelled, partially_paid"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or invoicing, or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

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

Create an invoice#

POST/api/v1/invoices

Creates an invoice with per-line VAT (201). If externalReference matches an existing invoice, that invoice is returned unchanged with 200 (the body is not applied and it is not re-sent). A pay link for the balance is created when your plan includes payment links and a gateway accepts the currency. With send: true the invoice is created as sent and emailed. Requires the Invoicing feature.

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json · required

Request body fields
FieldTypeDescription
customerIdstring

The customer's CentraPoint ID. Send exactly one of customerId or customer.

customerobject | object

The customer, by CentraPoint ID or by your externalReference. Send exactly one of customerId or customer.

Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencestring

Your ID for the invoice. If an invoice with this reference exists, it is returned unchanged with 200.

1–190 chars

currencystring

ISO 4217 code (validated). No gateway is required: invoices can be paid offline, but payUrl is only created when a gateway accepts the currency.

default "ZAR"

issueDatestring (date)

YYYY-MM-DD (South African time). Default today.

dueDatestring (date)

YYYY-MM-DD (South African time, end of day). Default: today plus your invoice due days setting.

linesrequiredobject[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring

1–1000 chars

quantityrequirednumber

> 0 · ≤ 1 000 000

unitPricerequirednumber

Excluding VAT.

≥ 0 · ≤ 100 000 000

taxRatenumber

VAT %. Defaults to your organisation's VAT rate.

≥ 0 · ≤ 100

notesstring

Defaults to your invoice terms.

max 4000 chars

metadataMetadataInput

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

sendboolean

Create as sent and email it to the customer (with a pay link when possible). Otherwise it is created as a draft.

default false

Responses#

200An invoice with this externalReference already existed; returned unchanged.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "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"
}
201Invoice created.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
201 response fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "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"
}
400Validation failed, invalid ISO 4217 currency, customer not found, or totals invalid.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Customer not found"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or invoicing, or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/invoices" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
  -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
  }'

Get an invoice#

GET/api/v1/invoices/{id}

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The invoice.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "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"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or invoicing, or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No invoice with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Invoice not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

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, with a pay link for the balance when possible. A draft becomes sent. Paid or cancelled invoices cannot be sent. No body is required.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json

object

Responses#

200The invoice after sending.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
200 response fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "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"
}
400The invoice is in a state that does not allow this, or validation failed.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Invoice is paid"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or invoicing, or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No invoice with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Invoice not found"
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd/send" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31"

Cancel an invoice#

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

Voids an unpaid (or partially paid) invoice and deactivates its pay links. Cancelling an already cancelled invoice returns it unchanged. Paid invoices cannot be cancelled.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json

Request body fields
FieldTypeDescription
reasonstring

Appended to the invoice notes.

max 500 chars

Responses#

200The cancelled invoice.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
200 response fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2i9n0v0005inv0001abcd",
  "number": "INV-000042",
  "status": "cancelled",
  "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": null,
  "notes": "Payment due within 14 days.",
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:05:00.000Z",
  "updatedAt": "2026-09-25T08:05:00.000Z"
}
400The invoice is in a state that does not allow this, or validation failed.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Paid invoices cannot be cancelled - record a refund or credit instead"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or invoicing, or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No invoice with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Invoice not found"
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd/cancel" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Order cancelled by customer"
  }'

Record an offline payment#

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

Records money received outside CentraPoint's gateways (EFT, cash, card machine, wallet credit…). The invoice becomes paid when fully paid (pay links are deactivated) or partially_paid otherwise. Always send an Idempotency-Key so a retry does not record the payment twice.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json

Request body fields
FieldTypeDescription
amountrequirednumber

Must not exceed the outstanding balance.

> 0 · ≤ 100 000 000

methodrequiredstring

One of: eft, cash, card, wallet, other

referencestring

Your reference, e.g. a bank statement reference.

max 190 chars

paidAtstring (date-time)

ISO 8601 with Z or an offset. Default now. Cannot be in the future.

Responses#

201Payment recorded; the updated invoice.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
201 response fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2i9n0v0005inv0001abcd",
  "number": "INV-000042",
  "status": "paid",
  "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": 620,
  "amountDue": 0,
  "paidAt": "2026-10-02T08:15:00.000Z",
  "payUrl": null,
  "notes": "Payment due within 14 days.",
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "createdAt": "2026-09-25T08:05:00.000Z",
  "updatedAt": "2026-09-25T08:05:00.000Z"
}
400The invoice is in a state that does not allow this, or validation failed.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Amount exceeds the outstanding balance of 620.00"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or invoicing, or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No invoice with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Invoice not found"
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/invoices/cmg2i9n0v0005inv0001abcd/payments" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 620,
    "method": "eft",
    "reference": "FNB 2026-10-02 NKOSI",
    "paidAt": "2026-10-02T10:15:00+02:00"
  }'

List subscriptions#

GET/api/v1/subscriptions

Gateway-managed subscriptions started by recurring payment links, newest first.

Query parameters#

Query parameters
FieldTypeDescription
externalReferencestring

The payment link's externalReference.

limitinteger

1–100, default 20. Out-of-range values are clamped; invalid values fall back to 20.

≥ 1 · ≤ 100 · default 20

Responses#

200Subscriptions.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredSubscription[]
Show fields
data fields
FieldTypeDescription
idrequiredstring
statusrequiredstring

One of: active, paused, cancelled

frequencyrequiredstring | null

One of: monthly, quarterly, biannually, annually, null

amountrequirednumber | null

Amount of each collection.

currencyrequiredstring
gatewayrequiredstring

Gateway that bills the subscription, e.g. payfast, netcash_paynow.

paymentLinkIdrequiredstring | null

The recurring payment link that started it.

externalReferencerequiredstring | null

That link's externalReference.

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "data": [
    {
      "id": "cmg2s5b8k0007sub0001abcd",
      "status": "active",
      "frequency": "monthly",
      "amount": 499,
      "currency": "ZAR",
      "gateway": "payfast",
      "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
      "externalReference": "SUB-ACME-PRO",
      "metadata": {
        "plan": "pro"
      },
      "createdAt": "2026-09-25T08:14:04.000Z",
      "updatedAt": "2026-09-25T08:14:04.000Z"
    }
  ]
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access (or the feature) is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/subscriptions" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Get a subscription#

GET/api/v1/subscriptions/{id}

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The subscription.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
statusrequiredstring

One of: active, paused, cancelled

frequencyrequiredstring | null

One of: monthly, quarterly, biannually, annually, null

amountrequirednumber | null

Amount of each collection.

currencyrequiredstring
gatewayrequiredstring

Gateway that bills the subscription, e.g. payfast, netcash_paynow.

paymentLinkIdrequiredstring | null

The recurring payment link that started it.

externalReferencerequiredstring | null

That link's externalReference.

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2s5b8k0007sub0001abcd",
  "status": "active",
  "frequency": "monthly",
  "amount": 499,
  "currency": "ZAR",
  "gateway": "payfast",
  "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
  "externalReference": "SUB-ACME-PRO",
  "metadata": {
    "plan": "pro"
  },
  "createdAt": "2026-09-25T08:14:04.000Z",
  "updatedAt": "2026-09-25T08:14:04.000Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access (or the feature) is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No subscription with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Subscription not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/subscriptions/cmg2s5b8k0007sub0001abcd" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Pause a subscription#

POST/api/v1/subscriptions/{id}/pause

Pauses future collections at the gateway and sends subscription.paused. Allowed from active. Supported on gateways that can pause subscriptions, e.g. PayFast. Repeating a call that already took effect returns 200 with the subscription unchanged (the Idempotency-Key header is not used). An invalid transition returns 409 invalid_state and nothing changes. No body is required.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The subscription (status `paused`).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
statusrequiredstring

One of: active, paused, cancelled

frequencyrequiredstring | null

One of: monthly, quarterly, biannually, annually, null

amountrequirednumber | null

Amount of each collection.

currencyrequiredstring
gatewayrequiredstring

Gateway that bills the subscription, e.g. payfast, netcash_paynow.

paymentLinkIdrequiredstring | null

The recurring payment link that started it.

externalReferencerequiredstring | null

That link's externalReference.

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2s5b8k0007sub0001abcd",
  "status": "paused",
  "frequency": "monthly",
  "amount": 499,
  "currency": "ZAR",
  "gateway": "payfast",
  "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
  "externalReference": "SUB-ACME-PRO",
  "metadata": {
    "plan": "pro"
  },
  "createdAt": "2026-09-25T08:14:04.000Z",
  "updatedAt": "2026-09-25T08:14:04.000Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Account is read-only (suspended, cancelled or trial ended), or a plan feature/quota is missing.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "account_restricted",
  "message": "Your free trial has ended. Choose a plan to continue."
}
404No subscription with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Subscription not found"
}
409`invalid_state`: not allowed from the current status. `unsupported`: the subscription's gateway can't do this, e.g. Netcash Pay Now subscriptions can only be cancelled.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
invalidState
{
  "error": "invalid_state",
  "message": "Subscription is cancelled"
}
unsupported
{
  "error": "unsupported",
  "message": "Netcash Pay Now does not support pausing subscriptions"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
502The gateway rejected or failed the request. Nothing changed; retry later.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "gateway_error",
  "message": "The payment gateway did not accept the request (pausing). Please try again."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/subscriptions/cmg2s5b8k0007sub0001abcd/pause" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Resume a subscription#

POST/api/v1/subscriptions/{id}/resume

Resumes a paused subscription at the gateway and sends subscription.resumed. Allowed from paused. Supported on gateways that can pause subscriptions, e.g. PayFast. Repeating a call that already took effect returns 200 with the subscription unchanged (the Idempotency-Key header is not used). An invalid transition returns 409 invalid_state and nothing changes. No body is required.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The subscription (status `active`).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
statusrequiredstring

One of: active, paused, cancelled

frequencyrequiredstring | null

One of: monthly, quarterly, biannually, annually, null

amountrequirednumber | null

Amount of each collection.

currencyrequiredstring
gatewayrequiredstring

Gateway that bills the subscription, e.g. payfast, netcash_paynow.

paymentLinkIdrequiredstring | null

The recurring payment link that started it.

externalReferencerequiredstring | null

That link's externalReference.

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2s5b8k0007sub0001abcd",
  "status": "active",
  "frequency": "monthly",
  "amount": 499,
  "currency": "ZAR",
  "gateway": "payfast",
  "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
  "externalReference": "SUB-ACME-PRO",
  "metadata": {
    "plan": "pro"
  },
  "createdAt": "2026-09-25T08:14:04.000Z",
  "updatedAt": "2026-09-25T08:14:04.000Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Account is read-only (suspended, cancelled or trial ended), or a plan feature/quota is missing.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "account_restricted",
  "message": "Your free trial has ended. Choose a plan to continue."
}
404No subscription with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Subscription not found"
}
409`invalid_state`: not allowed from the current status. `unsupported`: the subscription's gateway can't do this, e.g. Netcash Pay Now subscriptions can only be cancelled.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
invalidState
{
  "error": "invalid_state",
  "message": "Subscription is cancelled"
}
unsupported
{
  "error": "unsupported",
  "message": "Netcash Pay Now does not support resuming subscriptions"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
502The gateway rejected or failed the request. Nothing changed; retry later.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "gateway_error",
  "message": "The payment gateway did not accept the request (resuming). Please try again."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/subscriptions/cmg2s5b8k0007sub0001abcd/resume" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Cancel a subscription#

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

Stops future collections at the gateway and sends subscription.cancelled. Allowed from active or paused. Repeating a call that already took effect returns 200 with the subscription unchanged (the Idempotency-Key header is not used). An invalid transition returns 409 invalid_state and nothing changes. No body is required.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The cancelled subscription.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
statusrequiredstring

One of: active, paused, cancelled

frequencyrequiredstring | null

One of: monthly, quarterly, biannually, annually, null

amountrequirednumber | null

Amount of each collection.

currencyrequiredstring
gatewayrequiredstring

Gateway that bills the subscription, e.g. payfast, netcash_paynow.

paymentLinkIdrequiredstring | null

The recurring payment link that started it.

externalReferencerequiredstring | null

That link's externalReference.

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example
{
  "id": "cmg2s5b8k0007sub0001abcd",
  "status": "cancelled",
  "frequency": "monthly",
  "amount": 499,
  "currency": "ZAR",
  "gateway": "payfast",
  "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
  "externalReference": "SUB-ACME-PRO",
  "metadata": {
    "plan": "pro"
  },
  "createdAt": "2026-09-25T08:14:04.000Z",
  "updatedAt": "2026-09-25T08:14:04.000Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Account is read-only (suspended, cancelled or trial ended), or a plan feature/quota is missing.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "account_restricted",
  "message": "Your free trial has ended. Choose a plan to continue."
}
404No subscription with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Subscription not found"
}
409`invalid_state`: not allowed from the current status. `unsupported`: the gateway can't cancel through CentraPoint.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_state",
  "message": "Subscription is cancelled"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
502The gateway rejected or failed the request. Nothing changed; retry later.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "gateway_error",
  "message": "The payment gateway did not accept the cancellation. Please try again."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/subscriptions/cmg2s5b8k0007sub0001abcd/cancel" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

List EFT orders#

GET/api/v1/eft-orders

Newest first.

Query parameters#

Query parameters
FieldTypeDescription
externalReferencestring
customerIdstring
statusstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

limitinteger

1–100, default 20. Out-of-range values are clamped; invalid values fall back to 20.

≥ 1 · ≤ 100 · default 20

Responses#

200EFT orders.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredEftOrder[]
Show fields
data fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example
{
  "data": [
    {
      "id": "cmg3e1f2t0009eft0001abcd",
      "reference": "EFT-7K3Q9P2M",
      "status": "awaiting_review",
      "amount": 1250,
      "currency": "ZAR",
      "description": "Order #1001",
      "externalReference": "ORDER-1001",
      "metadata": {
        "cartId": "c_8841"
      },
      "customer": {
        "id": "cmg2c0s7t0003cust0001abcd",
        "externalReference": "CRM-1001"
      },
      "bankDetails": {
        "bankName": "FNB",
        "accountName": "Example Traders (Pty) Ltd",
        "accountNumber": "62000000000",
        "branchCode": "250655",
        "accountType": "current"
      },
      "paymentReference": "EFT-7K3Q9P2M",
      "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
      "proofs": [
        {
          "id": "cmg3p0r0f0011prf0001abcd",
          "fileName": "proof.pdf",
          "contentType": "application/pdf",
          "size": 184213,
          "source": "payer",
          "createdAt": "2026-09-25T09:12:00.000Z"
        }
      ],
      "rejectionReason": null,
      "expiresAt": "2026-10-02T08:00:00.000Z",
      "reviewedAt": null,
      "paidAt": null,
      "createdAt": "2026-09-25T08:00:00.000Z"
    }
  ]
}
400Unknown status.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "status must be one of awaiting_payment, awaiting_review, paid, rejected, expired, cancelled"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or payment links, or the account is read-only (writes).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/eft-orders" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Create an EFT order#

POST/api/v1/eft-orders

Issues a unique deposit reference and returns your bank details for the payer (201). Requires an enabled Manual EFT gateway, the Payment links feature and API access. Idempotent on externalReference for open orders (200).

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json · required

Request body fields
FieldTypeDescription
amountrequirednumber

> 0 · ≤ 100 000 000

currencystring

One of ZAR, NAD, BWP, LSL, SZL.

default "ZAR"

customerIdstring
customerobject | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
descriptionstring

max 1000 chars

externalReferencestring

Your ID. If an open order (awaiting_payment, awaiting_review or rejected) with this reference exists, it is returned with 200 instead of creating another; a different amount or currency is a 400.

1–190 chars

metadataMetadataInput

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

expiresAtstring (date-time)

At least 5 minutes and at most 90 days ahead. Default: the gateway's expiry days (7 by default).

notifyPayerboolean

Email the customer the bank details and payUrl when the order is created. Requires a customer with an email address (400 otherwise). Not re-sent when an existing open order is returned.

default false

Responses#

200An open order with this externalReference already existed; returned unchanged.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example
{
  "id": "cmg3e1f2t0009eft0001abcd",
  "reference": "EFT-7K3Q9P2M",
  "status": "awaiting_payment",
  "amount": 1250,
  "currency": "ZAR",
  "description": "Order #1001",
  "externalReference": "ORDER-1001",
  "metadata": {
    "cartId": "c_8841"
  },
  "customer": {
    "id": "cmg2c0s7t0003cust0001abcd",
    "externalReference": "CRM-1001"
  },
  "bankDetails": {
    "bankName": "FNB",
    "accountName": "Example Traders (Pty) Ltd",
    "accountNumber": "62000000000",
    "branchCode": "250655",
    "accountType": "current"
  },
  "paymentReference": "EFT-7K3Q9P2M",
  "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
  "proofs": [],
  "rejectionReason": null,
  "expiresAt": "2026-10-02T08:00:00.000Z",
  "reviewedAt": null,
  "paidAt": null,
  "createdAt": "2026-09-25T08:00:00.000Z"
}
201Order created.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
201 response fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example
{
  "id": "cmg3e1f2t0009eft0001abcd",
  "reference": "EFT-7K3Q9P2M",
  "status": "awaiting_payment",
  "amount": 1250,
  "currency": "ZAR",
  "description": "Order #1001",
  "externalReference": "ORDER-1001",
  "metadata": {
    "cartId": "c_8841"
  },
  "customer": {
    "id": "cmg2c0s7t0003cust0001abcd",
    "externalReference": "CRM-1001"
  },
  "bankDetails": {
    "bankName": "FNB",
    "accountName": "Example Traders (Pty) Ltd",
    "accountNumber": "62000000000",
    "branchCode": "250655",
    "accountType": "current"
  },
  "paymentReference": "EFT-7K3Q9P2M",
  "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
  "proofs": [],
  "rejectionReason": null,
  "expiresAt": "2026-10-02T08:00:00.000Z",
  "reviewedAt": null,
  "paidAt": null,
  "createdAt": "2026-09-25T08:00:00.000Z"
}
400Validation failed, Manual EFT not set up or not available, unsupported currency, customer not found, expiresAt out of range, or an open order for this externalReference has a different amount. `notifyPayer` without a customer email address.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Manual EFT is not set up. Add a 'Manual EFT (bank transfer)' gateway with your bank details under Settings > Payment providers."
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan lacks the API or payment links, monthly transaction limit reached (`plan_limit`), or account read-only.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/eft-orders" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1250,
    "customer": {
      "externalReference": "CRM-1001"
    },
    "description": "Order #1001",
    "externalReference": "ORDER-1001",
    "metadata": {
      "cartId": "c_8841"
    },
    "notifyPayer": true
  }'

Get an EFT order#

GET/api/v1/eft-orders/{id}

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The order.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example
{
  "id": "cmg3e1f2t0009eft0001abcd",
  "reference": "EFT-7K3Q9P2M",
  "status": "awaiting_review",
  "amount": 1250,
  "currency": "ZAR",
  "description": "Order #1001",
  "externalReference": "ORDER-1001",
  "metadata": {
    "cartId": "c_8841"
  },
  "customer": {
    "id": "cmg2c0s7t0003cust0001abcd",
    "externalReference": "CRM-1001"
  },
  "bankDetails": {
    "bankName": "FNB",
    "accountName": "Example Traders (Pty) Ltd",
    "accountNumber": "62000000000",
    "branchCode": "250655",
    "accountType": "current"
  },
  "paymentReference": "EFT-7K3Q9P2M",
  "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
  "proofs": [
    {
      "id": "cmg3p0r0f0011prf0001abcd",
      "fileName": "proof.pdf",
      "contentType": "application/pdf",
      "size": 184213,
      "source": "payer",
      "createdAt": "2026-09-25T09:12:00.000Z"
    }
  ],
  "rejectionReason": null,
  "expiresAt": "2026-10-02T08:00:00.000Z",
  "reviewedAt": null,
  "paidAt": null,
  "createdAt": "2026-09-25T08:00:00.000Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or payment links, or the account is read-only (writes).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No EFT order with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "EFT order not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/eft-orders/cmg3e1f2t0009eft0001abcd" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Upload proof of payment#

POST/api/v1/eft-orders/{id}/proof

multipart/form-data with one file field. The type is detected from the file's bytes: PDF, PNG or JPEG only; at most 10 MB; at most 10 files per order. Allowed while the order is awaiting_payment, awaiting_review or rejected (and not past its expiry, unless already in review). Moves the order to awaiting_review, notifies your staff and sends eft.proof_received. Uploading an identical file again is harmless (deduplicated by content hash). The Idempotency-Key header is not used on this endpoint.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Request body#

multipart/form-data · required

Multipart fields
FieldTypeDescription
filerequiredstring (binary)

PDF, PNG or JPEG, max 10 MB.

Responses#

200The order after the upload.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example
{
  "id": "cmg3e1f2t0009eft0001abcd",
  "reference": "EFT-7K3Q9P2M",
  "status": "awaiting_review",
  "amount": 1250,
  "currency": "ZAR",
  "description": "Order #1001",
  "externalReference": "ORDER-1001",
  "metadata": {
    "cartId": "c_8841"
  },
  "customer": {
    "id": "cmg2c0s7t0003cust0001abcd",
    "externalReference": "CRM-1001"
  },
  "bankDetails": {
    "bankName": "FNB",
    "accountName": "Example Traders (Pty) Ltd",
    "accountNumber": "62000000000",
    "branchCode": "250655",
    "accountType": "current"
  },
  "paymentReference": "EFT-7K3Q9P2M",
  "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
  "proofs": [
    {
      "id": "cmg3p0r0f0011prf0001abcd",
      "fileName": "proof.pdf",
      "contentType": "application/pdf",
      "size": 184213,
      "source": "payer",
      "createdAt": "2026-09-25T09:12:00.000Z"
    }
  ],
  "rejectionReason": null,
  "expiresAt": "2026-10-02T08:00:00.000Z",
  "reviewedAt": null,
  "paidAt": null,
  "createdAt": "2026-09-25T08:00:00.000Z"
}
400Missing file, empty or unsupported file type, order not open or expired, or too many proofs.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Proof must be a PDF, PNG or JPEG file"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or payment links, or the account is read-only (writes).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No EFT order with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "EFT order not found"
}
413File larger than 10 MB.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "File is larger than 10 MB"
}
415Body is not multipart/form-data.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "Send multipart/form-data with a 'file' field"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/eft-orders/cmg3e1f2t0009eft0001abcd/proof"   -H "Authorization: Bearer $CENTRAPOINT_API_KEY"   -F "[email protected];type=application/pdf"

Cancel an EFT order#

POST/api/v1/eft-orders/{id}/cancel

Cancels an unpaid order (awaiting_payment, awaiting_review or rejected) and its pending transaction, and sends eft.cancelled and payment.cancelled. Cancelling a cancelled order returns it unchanged. No body is required.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Request headers#

Request headers
FieldTypeDescription
Idempotency-Keystring

Optional, up to 200 characters. Keys are scoped to your organisation, the HTTP method and the exact request path (e.g. POST /api/v1/invoices/{id}/send for one specific invoice). Retrying with the same key and the same body within 24 hours returns the stored response (with Idempotent-Replayed: true) instead of repeating the operation. Same key with a different body returns 409 idempotency_conflict. 5xx responses are not stored.

max 200 chars

Request body#

application/json

object

Responses#

200The cancelled order.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Idempotent-Replayed – `true` when this response is a replay of an earlier request with the same Idempotency-Key.
200 response fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example
{
  "id": "cmg3e1f2t0009eft0001abcd",
  "reference": "EFT-7K3Q9P2M",
  "status": "cancelled",
  "amount": 1250,
  "currency": "ZAR",
  "description": "Order #1001",
  "externalReference": "ORDER-1001",
  "metadata": {
    "cartId": "c_8841"
  },
  "customer": {
    "id": "cmg2c0s7t0003cust0001abcd",
    "externalReference": "CRM-1001"
  },
  "bankDetails": {
    "bankName": "FNB",
    "accountName": "Example Traders (Pty) Ltd",
    "accountNumber": "62000000000",
    "branchCode": "250655",
    "accountType": "current"
  },
  "paymentReference": "EFT-7K3Q9P2M",
  "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
  "proofs": [],
  "rejectionReason": null,
  "expiresAt": "2026-10-02T08:00:00.000Z",
  "reviewedAt": null,
  "paidAt": null,
  "createdAt": "2026-09-25T08:00:00.000Z"
}
400The order is paid or expired.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "EFT order is paid"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or payment links, or the account is read-only (writes).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No EFT order with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "EFT order not found"
}
409The Idempotency-Key was already used with a different request body.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "idempotency_conflict",
  "message": "This Idempotency-Key was already used with a different request body"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X POST "https://app.centrapoint.co.za/api/v1/eft-orders/cmg3e1f2t0009eft0001abcd/cancel" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31"

Get a transaction by reference#

GET/api/v1/transactions/{reference}

Returns the current state of a payment in your organisation, looked up by its CentraPoint payment reference. Transactions in other organisations are reported as not found.

Path parameters#

Path parameters
FieldTypeDescription
referencerequiredstring

CentraPoint payment reference, e.g. CP-20260925-9F3A1C7B. Recurring renewals use <original reference>-<gateway payment id>; debit order collections use <mandate account reference>-<YYYYMMDD>, e.g. DO7F3A1C9B2E-20261001.

Responses#

200The transaction.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
referencerequiredstring

CentraPoint payment reference.

statusrequiredstring

complete is the only status that means money was received. refunded / partially_refunded are set when a refund is recorded in the dashboard.

One of: pending, complete, failed, cancelled, refunded, partially_refunded

amountrequirednumber

Gross amount in major units.

feerequirednumber | null

Gateway fee, when the gateway reports it.

netrequirednumber | null

Amount after the gateway fee, when reported.

currencyrequiredstring
typerequiredstring

invoice when the link was for an invoice, recurring for subscription charges, debit_order for Netcash debit order collections, otherwise once. eft for Manual EFT orders.

One of: once, recurring, invoice, debit_order, eft

gatewayrequiredstring

Gateway type that processed the payment, e.g. payfast, paystack, mpesa, netcash.

descriptionrequiredstring | null

Usually the payment link title.

providerRefrequiredstring | null

The gateway's own ID for the payment (e.g. PayFast pf_payment_id).

payerEmailrequiredstring | null
paymentLinkIdrequiredstring | null

ID of the payment link the payment was made through, if any.

externalReferencerequiredstring | null

The payment link's externalReference, or the EFT order's.

eftOrderIdrequiredstring | null

EFT order the payment belongs to (Manual EFT).

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

renewalrequiredboolean

True for later collections of a subscription.

parentReferencerequiredstring | null

For renewals: reference of the first payment.

subscriptionIdrequiredstring | null

Subscription started by the payment link, if any.

refundedAmountrequirednumber

Total of non-failed refunds, 0 if none.

refundsrequiredRefund[]

Refunds recorded for this payment, oldest first. Failed refunds are excluded.

Show fields
refunds fields
FieldTypeDescription
refundNumberrequiredstring
amountrequirednumber
currencyrequiredstring
statusrequiredstring

Failed refunds are not returned.

One of: pending, processed

processedAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
invoicerequirednull | object
Show fields
invoice fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
invoiceNumberrequiredstring

Same as number; kept for compatibility.

statusrequiredstring

One of: draft, sent, paid, overdue, cancelled

externalReferencerequiredstring | null
paidAtrequiredstring (date-time) | null

Set when the transaction becomes complete.

createdAtrequiredstring (date-time)
Example
{
  "reference": "CP-20260925-9F3A1C7B",
  "status": "partially_refunded",
  "amount": 499,
  "fee": 14.47,
  "net": 484.53,
  "currency": "ZAR",
  "type": "once",
  "gateway": "payfast",
  "description": "Website hosting - October",
  "providerRef": "2458761",
  "payerEmail": "[email protected]",
  "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
  "externalReference": "ORDER-1001",
  "eftOrderId": null,
  "metadata": {
    "crmId": "0061x00000AbCdE"
  },
  "renewal": false,
  "parentReference": null,
  "subscriptionId": null,
  "refundedAmount": 100,
  "refunds": [
    {
      "refundNumber": "REF-7C21A9F0",
      "amount": 100,
      "currency": "ZAR",
      "status": "processed",
      "processedAt": "2026-09-26T09:30:00.000Z",
      "createdAt": "2026-09-26T09:29:41.000Z"
    }
  ],
  "invoice": null,
  "paidAt": "2026-09-25T08:14:03.512Z",
  "createdAt": "2026-09-25T08:12:47.020Z"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "API access is not included in your plan"
}
404No transaction with this reference exists in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Transaction not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/transactions/CP-20260925-9F3A1C7B" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

List reconciliation runs#

GET/api/v1/reconciliation/runs

Statement imports (Netcash statements and CSV uploads) with their results, newest first by start time. Requires the Reconciliation feature (Business plan and above).

Query parameters#

Query parameters
FieldTypeDescription
fromstring (date)

YYYY-MM-DD (South African time): runs started on or after this day.

tostring (date)

YYYY-MM-DD (South African time): runs started on or before this day.

limitinteger

1–100, default 20. Out-of-range values are clamped; invalid values fall back to 20.

≥ 1 · ≤ 100 · default 20

Responses#

200Runs.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredReconciliationRun[]
Show fields
data fields
FieldTypeDescription
idrequiredstring
sourcerequiredstring

One of: netcash_statement, csv_upload

statementDaterequiredstring (date-time) | null

End of the statement period (or its start when no end is known).

periodStartrequiredstring (date-time) | null
periodEndrequiredstring (date-time) | null
statusrequiredstring

balanced: nothing needs attention; exceptions: at least one item does.

One of: processing, failed, balanced, exceptions

lineCountrequiredinteger

Statement lines imported.

matchedrequiredinteger
exceptionsrequiredinteger

Items needing attention (mismatches, unmatched lines and not_received payments).

totalsrequiredReconciliationTotals

Absolute sums of the statement lines in each category.

Show fields
totals fields
FieldTypeDescription
receiptsrequirednumber
feesrequirednumber
refundsrequirednumber
payoutsrequirednumber
unpaidsrequirednumber
openingBalancerequirednumber | null

From the statement's opening balance line, if present.

closingBalancerequirednumber | null
errorrequiredstring | null
createdAtrequiredstring (date-time)
completedAtrequiredstring (date-time) | null
Example
{
  "data": [
    {
      "id": "cmg3r7c0n0013run0001abcd",
      "source": "netcash_statement",
      "statementDate": "2026-09-24T22:00:00.000Z",
      "periodStart": "2026-09-23T22:00:00.000Z",
      "periodEnd": "2026-09-24T22:00:00.000Z",
      "status": "exceptions",
      "lineCount": 42,
      "matched": 38,
      "exceptions": 2,
      "totals": {
        "receipts": 48250.5,
        "fees": 612.4,
        "refunds": 499,
        "payouts": 45000,
        "unpaids": 350
      },
      "openingBalance": 1203.55,
      "closingBalance": 3342.71,
      "error": null,
      "createdAt": "2026-09-25T02:00:03.000Z",
      "completedAt": "2026-09-25T02:04:11.000Z"
    }
  ]
}
400Bad date.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "invalid_request",
  "message": "from and to must be YYYY-MM-DD"
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or reconciliation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/reconciliation/runs" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Get a reconciliation run#

GET/api/v1/reconciliation/runs/{id}

The run summary plus its items: every statement line except ignored ones (fees, payouts and balances are only in totals), and for completed Netcash statement runs, not_received items.

Path parameters#

Path parameters
FieldTypeDescription
idrequiredstring

Responses#

200The run with items.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
idrequiredstring
sourcerequiredstring

One of: netcash_statement, csv_upload

statementDaterequiredstring (date-time) | null

End of the statement period (or its start when no end is known).

periodStartrequiredstring (date-time) | null
periodEndrequiredstring (date-time) | null
statusrequiredstring

balanced: nothing needs attention; exceptions: at least one item does.

One of: processing, failed, balanced, exceptions

lineCountrequiredinteger

Statement lines imported.

matchedrequiredinteger
exceptionsrequiredinteger

Items needing attention (mismatches, unmatched lines and not_received payments).

totalsrequiredReconciliationTotals

Absolute sums of the statement lines in each category.

Show fields
totals fields
FieldTypeDescription
receiptsrequirednumber
feesrequirednumber
refundsrequirednumber
payoutsrequirednumber
unpaidsrequirednumber
openingBalancerequirednumber | null

From the statement's opening balance line, if present.

closingBalancerequirednumber | null
errorrequiredstring | null
createdAtrequiredstring (date-time)
completedAtrequiredstring (date-time) | null
itemsrequiredReconciliationItem[]
Show fields
items fields
FieldTypeDescription
statusrequiredstring

One of: matched, amount_mismatch, exception, unmatched_receipt, unmatched_debit, not_received

referencerequiredstring | null

CentraPoint payment reference when matched, else the reference on the statement line.

externalReferencerequiredstring | null

From the payment link or EFT order.

expectedAmountrequirednumber | null

The CentraPoint transaction amount.

statementAmountrequirednumber | null

Signed: + money in, − money out. Null for not_received.

daterequiredstring (date-time) | null
descriptionrequiredstring | null
noterequiredstring | null
Example
{
  "id": "cmg3r7c0n0013run0001abcd",
  "source": "netcash_statement",
  "statementDate": "2026-09-24T22:00:00.000Z",
  "periodStart": "2026-09-23T22:00:00.000Z",
  "periodEnd": "2026-09-24T22:00:00.000Z",
  "status": "exceptions",
  "lineCount": 42,
  "matched": 38,
  "exceptions": 2,
  "totals": {
    "receipts": 48250.5,
    "fees": 612.4,
    "refunds": 499,
    "payouts": 45000,
    "unpaids": 350
  },
  "openingBalance": 1203.55,
  "closingBalance": 3342.71,
  "error": null,
  "createdAt": "2026-09-25T02:00:03.000Z",
  "completedAt": "2026-09-25T02:04:11.000Z",
  "items": [
    {
      "status": "matched",
      "reference": "CP-20260924-9F3A1C7B",
      "externalReference": "ORDER-1001",
      "expectedAmount": 499,
      "statementAmount": 499,
      "date": "2026-09-24T00:00:00.000Z",
      "description": "PAYNOW CP-20260924-9F3A1C7B",
      "note": null
    },
    {
      "status": "amount_mismatch",
      "reference": "CP-20260924-41D07E2A",
      "externalReference": "ORDER-1002",
      "expectedAmount": 1200,
      "statementAmount": 1100,
      "date": "2026-09-24T00:00:00.000Z",
      "description": "PAYNOW CP-20260924-41D07E2A",
      "note": "Amount differs: statement 1100.00 vs transaction 1200.00"
    },
    {
      "status": "not_received",
      "reference": "CP-20260920-7C21A9F0",
      "externalReference": "ORDER-0990",
      "expectedAmount": 250,
      "statementAmount": null,
      "date": null,
      "description": "Website hosting",
      "note": "Completed in CentraPoint but not on the statement after 3 days"
    }
  ]
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403Plan does not include the API or reconciliation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "This feature is not included in your plan"
}
404No run with this ID in your organisation.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "not_found",
  "message": "Reconciliation run not found"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}

Code samples#

curl -X GET "https://app.centrapoint.co.za/api/v1/reconciliation/runs/cmg3r7c0n0013run0001abcd" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"
GET/api/v1/accounting/referral-links

Returns tracked sign-up links for the accounting systems CentraPoint partners with, so you can show a "Don't have Xero? Sign up" link in your own app. Only active partner programmes are returned; the list can be empty. Each url is specific to your organisation. Available on any plan with API access: signing up for an accounting system does not require CentraPoint's accounting sync feature.

200Active referral links.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
200 response fields
FieldTypeDescription
datarequiredReferralLink[]
Show fields
data fields
FieldTypeDescription
connectorrequiredstring

Accounting connector type, e.g. xero, quickbooks, zoho_books, sage_one_za.

namerequiredstring

Display name of the accounting system.

programrequiredstring

Name of the partner programme.

urlrequiredstring (uri)

Signed CentraPoint redirect (/r/accounting/{connector}?s=…) that records the click for your organisation and forwards to the vendor's sign-up page. Works without a CentraPoint login; do not modify it.

Example
{
  "data": [
    {
      "connector": "xero",
      "name": "Xero",
      "program": "Xero App Partner",
      "url": "https://app.centrapoint.co.za/r/accounting/xero?s=cpQ2VudHJhUG9pbnQx.bG9uZy1zaWduYXR1cmUx"
    },
    {
      "connector": "zoho_books",
      "name": "Zoho Books",
      "program": "Zoho Affiliate",
      "url": "https://app.centrapoint.co.za/r/accounting/zoho_books?s=cpQ2VudHJhUG9pbnQx.c2Vjb25kLXNpZ25hdHVyZQ"
    }
  ]
}
401The API key is missing, malformed, unknown or revoked. No rate-limit headers are sent, because the key is not known.
missing
{
  "error": "unauthorized",
  "message": "Missing or malformed API key"
}
invalid
{
  "error": "unauthorized",
  "message": "Invalid API key"
}
403API access is not included in your plan.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "plan_restricted",
  "message": "API access is not included in your plan"
}
429More than 120 requests in the current 60-second window for this API key, or more than 600 from one client IP before authentication (message `Too many requests from this network`; headers then describe the IP window).

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
  • Retry-After – Seconds to wait before retrying.
Example
{
  "error": "rate_limited",
  "message": "Rate limit of 120 requests per minute exceeded for this API key"
}
500Unexpected server error. The details are logged by CentraPoint; the message is generic.

Headers

  • X-RateLimit-Limit – Requests allowed per 60-second window for this API key.
  • X-RateLimit-Remaining – Requests left in the current window.
  • X-RateLimit-Reset – Unix time (seconds) when the current window ends.
Example
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support."
}
curl -X GET "https://app.centrapoint.co.za/api/v1/accounting/referral-links" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Webhook events#

POSTSent by CentraPoint to your endpoint

Sent by CentraPoint to each HTTPS endpoint configured under Settings → Webhooks and subscribed to this event. Respond 2xx within 10 seconds. Failed deliveries are retried after 1m, 5m, 30m, 2h, 6h, 12h and 24h (8 attempts). Redirects are not followed. Deliveries may repeat and may arrive out of order.

  • payment.complete: Payment completed
  • payment.failed: Payment failed
  • payment.cancelled: Payment cancelled
  • payment.refunded: Payment fully refunded
  • payment.partially_refunded: Payment partially refunded
  • invoice.paid: Invoice fully paid
  • invoice.partially_paid: Invoice partially paid
  • invoice.cancelled: Invoice cancelled
  • eft.proof_received: EFT proof of payment received
  • eft.rejected: EFT proof rejected
  • eft.expired: EFT order expired
  • eft.cancelled: EFT order cancelled
  • reconciliation.completed: Reconciliation run completed
  • subscription.activated: Subscription activated (first payment completed)
  • subscription.charged: Subscription renewal charged
  • subscription.payment_failed: Subscription renewal failed
  • subscription.cancelled: Subscription cancelled
  • subscription.paused: Subscription paused
  • subscription.resumed: Subscription resumed

Headers#

Webhook headers
FieldTypeDescription
CentraPoint-Eventrequiredstring

Event type.

CentraPoint-Deliveryrequiredstring

Delivery ID (constant across retries of this delivery).

CentraPoint-Signaturerequiredstring

t=<unix seconds>,v1=<hex HMAC-SHA256(signing secret, "<t>.<raw body>")>. Reject if t is more than 5 minutes old.

Payload: payment.complete, payment.failed, payment.cancelled, payment.refunded, payment.partially_refunded#

WebhookEvent fields
FieldTypeDescription
idrequiredstring

Unique event ID (evt_…). Stable across retries, resends and endpoints; de-duplicate on it.

typerequiredstring

One of: payment.complete, payment.failed, payment.cancelled, payment.refunded, payment.partially_refunded

createdrequiredstring (date-time)
datarequiredWebhookPaymentData
Show fields
data fields
FieldTypeDescription
referencerequiredstring
statusrequiredstring

complete is the only status that means money was received. refunded / partially_refunded are set when a refund is recorded in the dashboard.

One of: pending, complete, failed, cancelled, refunded, partially_refunded

amountrequirednumber
currencyrequiredstring
typerequiredstring

One of: once, recurring, invoice, debit_order, eft

gatewayrequiredstring
providerRefrequiredstring | null
paymentLinkIdrequiredstring | null
externalReferencerequiredstring | null

The payment link's externalReference, or the EFT order's.

eftOrderIdrequiredstring | null

EFT order the payment belongs to (Manual EFT).

invoicerequirednull | object
Show fields
invoice fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring
externalReferencerequiredstring | null
customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

renewalrequiredboolean
parentReferencerequiredstring | null
subscriptionIdrequiredstring | null
refundedAmountrequirednumber
paidAtrequiredstring (date-time) | null
Example payload
{
  "id": "evt_3f9a1c7b2e4d6f8091a2b3c4",
  "type": "payment.complete",
  "created": "2026-09-25T08:14:04.201Z",
  "data": {
    "reference": "CP-20260925-9F3A1C7B",
    "status": "complete",
    "amount": 499,
    "currency": "ZAR",
    "type": "once",
    "gateway": "payfast",
    "providerRef": "2458761",
    "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
    "externalReference": "ORDER-1001",
    "eftOrderId": null,
    "invoice": null,
    "customer": {
      "id": "cmg2c0s7t0003cust0001abcd",
      "externalReference": "CRM-1001"
    },
    "metadata": {
      "crmId": "0061x00000AbCdE"
    },
    "renewal": false,
    "parentReference": null,
    "subscriptionId": null,
    "refundedAmount": 0,
    "paidAt": "2026-09-25T08:14:03.512Z"
  }
}

Payload: invoice.paid, invoice.partially_paid, invoice.cancelled#

InvoiceWebhookEvent fields
FieldTypeDescription
idrequiredstring

Unique event ID (evt_…).

typerequiredstring

One of: invoice.paid, invoice.partially_paid, invoice.cancelled

createdrequiredstring (date-time)
datarequiredInvoice
Show fields
data fields
FieldTypeDescription
idrequiredstring
numberrequiredstring
statusrequiredstring

partially_paid is reported for draft/sent/overdue invoices that have received some money.

One of: draft, sent, overdue, partially_paid, paid, cancelled

externalReferencerequiredstring | null
customerrequiredobject
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
emailrequiredstring
currencyrequiredstring
issueDaterequiredstring (date-time)
dueDaterequiredstring (date-time) | null
linesrequiredInvoiceLine[]
Show fields
lines fields
FieldTypeDescription
descriptionrequiredstring
quantityrequirednumber
unitPricerequirednumber

Excluding VAT.

taxRaterequirednumber

VAT percentage for this line.

amountrequirednumber

quantity × unitPrice, excluding VAT.

subtotalrequirednumber
taxAmountrequirednumber
totalrequirednumber
amountPaidrequirednumber
amountDuerequirednumber

total − amountPaid.

paidAtrequiredstring (date-time) | null
payUrlrequiredstring (uri) | null

Hosted payment page for the outstanding balance, or null (paid/cancelled, no pay link yet, or neither a checkout gateway nor Manual EFT accepts the currency).

notesrequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
Example payload
{
  "id": "evt_8b2d4f6a0c1e3a5b7d9f1c2e",
  "type": "invoice.paid",
  "created": "2026-10-02T08:15:01.000Z",
  "data": {
    "id": "cmg2i9n0v0005inv0001abcd",
    "number": "INV-000042",
    "status": "paid",
    "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": 620,
    "amountDue": 0,
    "paidAt": "2026-10-02T08:15:00.000Z",
    "payUrl": null,
    "notes": "Payment due within 14 days.",
    "metadata": {
      "crmId": "0061x00000AbCdE"
    },
    "createdAt": "2026-09-25T08:05:00.000Z",
    "updatedAt": "2026-09-25T08:05:00.000Z"
  }
}

Payload: eft.proof_received, eft.rejected, eft.expired, eft.cancelled#

EftWebhookEvent fields
FieldTypeDescription
idrequiredstring
typerequiredstring

One of: eft.proof_received, eft.rejected, eft.expired, eft.cancelled

createdrequiredstring (date-time)
datarequiredEftOrder
Show fields
data fields
FieldTypeDescription
idrequiredstring
referencerequiredstring

Unique deposit reference, e.g. EFT-7K3Q9P2M (prefix configurable, 8 characters without 0/O/1/I/L). Also the payment reference of the order's transaction.

statusrequiredstring

One of: awaiting_payment, awaiting_review, paid, rejected, expired, cancelled

amountrequirednumber
currencyrequiredstring
descriptionrequiredstring | null
externalReferencerequiredstring | null
metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

customerrequirednull | object
Show fields
customer fields
FieldTypeDescription
idrequiredstring
externalReferencerequiredstring | null
bankDetailsrequiredobject

Your bank account from the Manual EFT gateway. Show these to the payer.

Show fields
bankDetails fields
FieldTypeDescription
bankNamerequiredstring
accountNamerequiredstring
accountNumberrequiredstring
branchCoderequiredstring
accountTyperequiredstring

One of: current, savings, transmission

paymentReferencerequiredstring

The reference the payer must use on the transfer (same as reference).

payUrlrequiredstring (uri)

Signed public payer page with the bank details, the reference and a proof-of-payment upload. No login needed; share it instead of building your own upload. A tampered link returns 404.

proofsrequiredobject[]
Show fields
proofs fields
FieldTypeDescription
idrequiredstring
fileNamerequiredstring
contentTyperequiredstring

One of: application/pdf, image/png, image/jpeg

sizerequiredinteger
sourcerequiredstring

Who uploaded it: your system via the API, staff in the dashboard, or the payer on the payer page.

One of: api, dashboard, payer

createdAtrequiredstring (date-time)
rejectionReasonrequiredstring | null
expiresAtrequiredstring (date-time) | null
reviewedAtrequiredstring (date-time) | null
paidAtrequiredstring (date-time) | null
createdAtrequiredstring (date-time)
Example payload
{
  "id": "evt_5c7e9a1b3d5f7a9c1e3b5d7f",
  "type": "eft.proof_received",
  "created": "2026-09-25T09:12:01.000Z",
  "data": {
    "id": "cmg3e1f2t0009eft0001abcd",
    "reference": "EFT-7K3Q9P2M",
    "status": "awaiting_review",
    "amount": 1250,
    "currency": "ZAR",
    "description": "Order #1001",
    "externalReference": "ORDER-1001",
    "metadata": {
      "cartId": "c_8841"
    },
    "customer": {
      "id": "cmg2c0s7t0003cust0001abcd",
      "externalReference": "CRM-1001"
    },
    "bankDetails": {
      "bankName": "FNB",
      "accountName": "Example Traders (Pty) Ltd",
      "accountNumber": "62000000000",
      "branchCode": "250655",
      "accountType": "current"
    },
    "paymentReference": "EFT-7K3Q9P2M",
    "payUrl": "https://app.centrapoint.co.za/eft/cmg3e1f2t0009eft0001abcd.Qm9ndXMtc2lnbmF0dXJlLWV4YW1wbGU",
    "proofs": [
      {
        "id": "cmg3p0r0f0011prf0001abcd",
        "fileName": "proof.pdf",
        "contentType": "application/pdf",
        "size": 184213,
        "source": "payer",
        "createdAt": "2026-09-25T09:12:00.000Z"
      }
    ],
    "rejectionReason": null,
    "expiresAt": "2026-10-02T08:00:00.000Z",
    "reviewedAt": null,
    "paidAt": null,
    "createdAt": "2026-09-25T08:00:00.000Z"
  }
}

Payload: reconciliation.completed#

ReconciliationWebhookEvent fields
FieldTypeDescription
idrequiredstring
typerequiredstring

One of: reconciliation.completed

createdrequiredstring (date-time)
datarequiredobject
Show fields
data fields
FieldTypeDescription
runIdrequiredstring
statusrequiredstring

One of: processing, failed, balanced, exceptions

exceptionsrequiredinteger
lineCountrequiredinteger
statementDaterequiredstring (date-time) | null
totalsrequiredReconciliationTotals

Absolute sums of the statement lines in each category.

Show fields
totals fields
FieldTypeDescription
receiptsrequirednumber
feesrequirednumber
refundsrequirednumber
payoutsrequirednumber
unpaidsrequirednumber
Example payload
{
  "id": "evt_5c7e9a1b3d5f7a9c1e3b5d7f",
  "type": "reconciliation.completed",
  "created": "2026-09-25T09:12:01.000Z",
  "data": {
    "runId": "cmg3r7c0n0013run0001abcd",
    "status": "exceptions",
    "exceptions": 2,
    "lineCount": 42,
    "statementDate": "2026-09-24T22:00:00.000Z",
    "totals": {
      "receipts": 48250.5,
      "fees": 612.4,
      "refunds": 499,
      "payouts": 45000,
      "unpaids": 350
    }
  }
}

Payload: subscription.activated, subscription.charged, subscription.payment_failed, subscription.cancelled, subscription.paused, subscription.resumed#

SubscriptionWebhookEvent fields
FieldTypeDescription
idrequiredstring
typerequiredstring

One of: subscription.activated, subscription.charged, subscription.payment_failed, subscription.cancelled, subscription.paused, subscription.resumed

createdrequiredstring (date-time)
datarequiredSubscriptionWebhookData
Show fields
data fields
FieldTypeDescription
idrequiredstring
statusrequiredstring

One of: active, paused, cancelled

frequencyrequiredstring | null

One of: monthly, quarterly, biannually, annually, null

amountrequirednumber | null

Amount of each collection.

currencyrequiredstring
gatewayrequiredstring

Gateway that bills the subscription, e.g. payfast, netcash_paynow.

paymentLinkIdrequiredstring | null

The recurring payment link that started it.

externalReferencerequiredstring | null

That link's externalReference.

metadatarequiredMetadata

Your own key/value data. Flat map of strings (numbers and booleans are converted to strings; null values are dropped). Up to 50 keys; keys 1–40 characters of letters, digits, _ . : -; values up to 500 characters; at most 4000 characters as JSON. Returned as {} when empty.

createdAtrequiredstring (date-time)
updatedAtrequiredstring (date-time)
subscriptionIdrequiredstring

Same as id.

paymentobject

activated / charged / payment_failed only: the payment that triggered the event.

Show fields
payment fields
FieldTypeDescription
referencerequiredstring
amountrequirednumber
currencyrequiredstring
statusrequiredstring

complete is the only status that means money was received. refunded / partially_refunded are set when a refund is recorded in the dashboard.

One of: pending, complete, failed, cancelled, refunded, partially_refunded

paidAtrequiredstring (date-time) | null
periodStartstring (date-time) | null

activated / charged / payment_failed only: when the paid period starts (the payment time). Null when the payment failed.

periodEndstring (date-time) | null

periodStart plus one billing interval. Null when periodStart is null.

Example payload
{
  "id": "evt_2a4c6e8f0b1d3f5a7c9e1b3d",
  "type": "subscription.activated",
  "created": "2026-10-25T08:14:05.000Z",
  "data": {
    "id": "cmg2s5b8k0007sub0001abcd",
    "status": "active",
    "frequency": "monthly",
    "amount": 499,
    "currency": "ZAR",
    "gateway": "payfast",
    "paymentLinkId": "cmg1k2x3y0001abcd1234efgh",
    "externalReference": "SUB-ACME-PRO",
    "metadata": {
      "plan": "pro"
    },
    "createdAt": "2026-09-25T08:14:04.000Z",
    "updatedAt": "2026-09-25T08:14:04.000Z",
    "subscriptionId": "cmg2s5b8k0007sub0001abcd",
    "payment": {
      "reference": "CP-20260925-9F3A1C7B",
      "amount": 499,
      "currency": "ZAR",
      "status": "complete",
      "paidAt": "2026-09-25T08:14:03.512Z"
    },
    "periodStart": "2026-09-25T08:14:03.512Z",
    "periodEnd": "2026-10-25T08:14:03.512Z"
  }
}

See the Webhooks guide for setup and signature verification code.