CentraPoint

API

Payment links API

Create, list and retrieve hosted payment links, and find the payment references made through them.

On this page

A payment link is a CentraPoint-hosted page (https://app.centrapoint.co.za/pay/…) where a payer enters their details, chooses a payment method from your enabled gateways and pays. Create links from your system, send the url to the payer, and use the list/get endpoints to find the payments made through each link.

Payment link endpoints
EndpointPurpose
POST /api/v1/payment-linksCreate a link
GET /api/v1/payment-linksList links, optionally by externalReference, with their payments
GET /api/v1/payment-links/{id}Get one link with its payments
POST/api/v1/payment-links

Requires an API key on a plan that includes the REST API and payment links, and an account that is not read-only. Returns 201 Created with the payment link object (without payments, since a new link has none).

Request body#

JSON object. Unknown fields are ignored.

Create payment link fields
FieldTypeDescription
titlerequiredstringShown to the payer. 1–100 characters after trimming whitespace.
amountrequirednumberAmount in major units (rand, not cents), greater than 0 and at most 10 000 000. Rounded to 2 decimal places. Must be a JSON number.
currencyoptionalstringISO 4217 code, e.g. ZAR, KES, NGN. Upper-cased by the server. Default ZAR. Must be accepted by one of your enabled checkout gateways. See Currency and amount.
externalReferenceoptionalstringYour own ID for this link, e.g. an order number. 1–100 characters after trimming. See External reference.
descriptionoptionalstringUp to 255 characters, shown under the title.
returnUrloptionalstringhttps URL to send the payer back to afterwards. Its origin must be allow-listed. See Return URL.
metadataoptionalobjectYour key/value data, echoed on transactions and webhooks. See Metadata.
recurringoptionalobject{ frequency, amount? } to start a card subscription. See Recurring links.
customerIdoptionalstringAttach an existing customer by ID (from the Customers API). Takes precedence over customerEmail.
customerEmailoptionalstring (email)Attach the link to a customer. See Customers.
customerFirstNameoptionalstringUp to 100 characters. Only used when a new customer is created.
customerLastNameoptionalstringUp to 100 characters. Only used when a new customer is created.
productIdoptionalstringID of a product in your organisation. See Products and invoices.
invoiceIdoptionalstringID of an invoice in your organisation.
singleUseoptionalbooleanDefault true. A single-use link is deactivated after its first successful payment. Set false for a reusable link (e.g. a donation or a fixed-price product page).
expiresAtoptionalstring (date-time)ISO 8601 timestamp with seconds and either Z or a UTC offset, e.g. 2026-10-31T23:59:59+02:00 or 2026-10-31T21:59:59Z. Must be in the future and no more than 1 year ahead. After this moment the link cannot be paid. Omit for no expiry.

External reference#

Set externalReference to the ID your system already uses for the thing being paid (order, booking, account statement). CentraPoint stores it on the link, returns it on the link and on every transaction made through it, and lets you look the link up by it:

Find by external reference
GET /api/v1/payment-links?externalReference=ORDER-1001

This is the recommended way to discover the payment references for your order. External references are not required to be unique; if you create several links with the same value, the list returns all of them, newest first.

Return URL#

By default the payer ends on CentraPoint's payment result page. Pass returnUrl to send them back to your site once the payment has a final outcome:

  1. An administrator allow-lists your origin (e.g. https://shop.example.co.za) under Settings → API keys → Allowed return URLs. Only https origins are accepted.
  2. Create the link with returnUrl on that origin (up to 1000 characters; any #fragment is dropped). Otherwise the request fails with 400, e.g. returnUrl origin … is not allowed.
  3. After the payment, the result page redirects the payer to your URL with reference and status (complete, failed or cancelled) added as query parameters, e.g. https://shop.example.co.za/checkout/done?reference=CP-20260925-9F3A1C7B&status=complete. From the cancel page, the payer gets a "Return to …" button with status=cancelled.

Metadata#

metadata stores your own key/value data on the link (up to 50 string values). It is returned on the link, on every transaction made through it, on payment.* webhooks and on subscriptions started by it. See the metadata rules.

Recurring links#

Add "recurring": { "frequency": "monthly" } to start a gateway-managed card subscription when the link is paid. frequency is monthly, quarterly, biannually or annually; optional amount is what each later collection charges (default: the link amount).

  • Requires a plan with recurring billing and an enabled gateway that supports it: PayFast or Netcash Pay Now.
  • Only recurring-capable gateways are offered to the payer on the link.
  • The resulting subscription can be read and cancelled with the Subscriptions API. See the Recurring billing guide.

Bank transfer (EFT) at checkout#

If you have a Manual EFT gateway, once-off links in a currency it supports also offer Bank transfer (EFT). The payer gets an EFT order and its payer page for uploading proof; when your staff approve it, the link is paid and payment.complete carries the link's externalReference and metadata. Recurring links don't offer it. A once-off link can be created even if Manual EFT is your only gateway. See EFT at hosted checkout.

Customers#

Pass customerId to attach a customer you created with the Customers API. Otherwise, when you pass customerEmail, CentraPoint looks for a customer in your organisation with that email address (case-insensitive). If one exists, the link is attached to it and customerFirstName/customerLastName are ignored. Otherwise a new customer is created, with the first name defaulting to the part of the email before @. Creating a customer counts towards your plan's customer limit and can return 403 plan_limit.

When a link has a customer, the payment page pre-fills the payer's details. Without one, the payer enters their details and CentraPoint matches or creates the customer at checkout.

Currency and amount#

  • The currency 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, e.g. None of your enabled payment gateways accept USD. Enable a gateway that supports USD first. Check each gateway's currencies in the Gateways reference.
  • The payer only sees payment methods whose gateway supports the link's currency.
  • Gateways can impose their own rules at checkout: for example M-Pesa only accepts whole Kenyan shilling amounts, and PayFast only accepts ZAR.
  • The amount is fixed; the payer cannot change it.

Products and invoices#

  • productId links the payment to a product. If the product is a recurring product, checkout starts a gateway-managed subscription, which needs a gateway with recurring support (PayFast) and a plan that includes recurring billing.
  • invoiceId applies successful payments to that invoice; the invoice becomes paid once fully paid. Links for paid or cancelled invoices cannot be paid.
  • IDs must belong to your organisation, otherwise the request fails with 400 invalid_request and Product not found / Invoice not found. Product and invoice IDs are available in the dashboard; v1 has no endpoints to list them.

Code samples#

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": "Website hosting - October",
    "description": "Monthly hosting for example.co.za",
    "amount": 499,
    "currency": "ZAR",
    "externalReference": "ORDER-1001",
    "customerEmail": "[email protected]",
    "customerFirstName": "Thandi",
    "customerLastName": "Nkosi",
    "returnUrl": "https://shop.example.co.za/checkout/done",
    "metadata": {
      "cartId": "c_8841"
    },
    "singleUse": true,
    "expiresAt": "2026-10-31T23:59:59+02:00"
  }'
201 Created
{
  "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",
  "returnUrl": "https://shop.example.co.za/checkout/done",
  "metadata": {
    "cartId": "c_8841"
  },
  "recurring": null,
  "singleUse": true,
  "active": true,
  "expiresAt": "2026-10-31T21:59:59.000Z",
  "paidCount": 0,
  "createdAt": "2026-09-25T08:10:02.114Z"
}

Send an Idempotency-Key header so a retried request returns the same link instead of creating another.

Payment link fields
FieldTypeDescription
idrequiredstringPayment link ID.
urlrequiredstringHosted payment page. Send this to the payer.
titlerequiredstringTitle shown to the payer.
descriptionrequiredstring | nullDescription shown to the payer.
amountrequirednumberAmount after rounding.
currencyrequiredstringUpper-case currency code.
externalReferencerequiredstring | nullYour ID, as supplied on creation.
returnUrlrequiredstring | nullWhere the payer is sent afterwards.
metadatarequiredobjectYour key/value data; {} when empty.
recurringrequiredobject | null{ frequency, amount } for recurring links.
subscriptionoptionalobject | nullList and get responses: { id, status } of the latest subscription started by the link, or null.
singleUserequiredbooleanWhether the link deactivates after the first successful payment.
activerequiredbooleanFalse once deactivated in the dashboard or after a single-use link is paid.
expiresAtrequiredstring | nullExpiry as an ISO 8601 UTC timestamp, or null.
paidCountrequiredintegerNumber of successful payments through the link.
createdAtrequiredstringISO 8601 UTC creation time.
paymentsoptionalobject[]List and get responses only. Checkout attempts through the link, newest first, each with reference, status, amount, currency, paidAt and createdAt. Every attempt (including cancelled or failed ones) has its own reference.
GET/api/v1/payment-links

Returns your organisation's links, newest first, as { "data": [ … ] }. Each link includes up to 50 of its most recent payments.

List query parameters
FieldTypeDescription
externalReferenceoptionalstringOnly links with exactly this external reference (surrounding whitespace ignored).
limitoptionalinteger1–100, default 20. Out-of-range values are clamped; invalid values fall back to 20.
curl -X GET "https://app.centrapoint.co.za/api/v1/payment-links?externalReference=ORDER-1001" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"
200 OK
{
  "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",
      "returnUrl": "https://shop.example.co.za/checkout/done",
      "metadata": {
        "cartId": "c_8841"
      },
      "recurring": null,
      "singleUse": true,
      "active": false,
      "expiresAt": "2026-10-31T21:59:59.000Z",
      "paidCount": 1,
      "createdAt": "2026-09-25T08:10:02.114Z",
      "subscription": null,
      "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"
        }
      ]
    }
  ]
}

There is no pagination cursor in v1; narrow results with externalReference.

GET/api/v1/payment-links/{id}

Returns one link with up to 100 of its most recent payments. Links in other organisations return 404 not_found (Payment link not found). Like the list, it includes subscription.

curl -X GET "https://app.centrapoint.co.za/api/v1/payment-links/cmg1k2x3y0001abcd1234efgh" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"
200 OK
{
  "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",
  "returnUrl": "https://shop.example.co.za/checkout/done",
  "metadata": {
    "cartId": "c_8841"
  },
  "recurring": null,
  "singleUse": true,
  "active": false,
  "expiresAt": "2026-10-31T21:59:59.000Z",
  "paidCount": 1,
  "createdAt": "2026-09-25T08:10:02.114Z",
  "subscription": null,
  "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"
    }
  ]
}

Errors#

Payment link errors
StatuserrorWhen
400invalid_requestCreate only: body is not valid JSON or fails validation (issues included); unknown customerId/productId/invoiceId; returnUrl not https or origin not allowed; invalid metadata; recurring not available; invalid currency or one none of your gateways accept; expiresAt not in the future or more than 1 year ahead; amount rounds to 0.
401unauthorizedMissing, malformed, unknown or revoked API key.
403plan_restrictedPlan does not include the REST API, or (create) payment links.
403plan_limitCreate only: creating the customer would exceed your plan's customer limit.
403account_restrictedCreate only: account is suspended, cancelled or its trial has ended.
409idempotency_conflictCreate only: Idempotency-Key reused with a different body.
413invalid_requestCreate only: request body larger than 100 000 characters.
404not_foundGet only: no link with this ID in your organisation.
429rate_limitedMore than 120 requests per minute with this API key. Honour Retry-After.
500internal_errorUnexpected server error. Safe to retry reads; see Errors before retrying a create.

See Errors & rate limits for the error body format.

A link can be paid while all of these are true:

  • It is active (not deactivated in the dashboard, and not a single-use link that has been paid).
  • expiresAt has not passed.
  • Its invoice, if any, is not paid or cancelled.
  • Your account is not read-only, and you have not reached your plan's monthly transaction limit.

Otherwise the payer sees a "Payment unavailable" message. v1 has no endpoints to update or deactivate links; do that in the dashboard under Payment links.