CentraPoint

Getting started

Idempotency, metadata & references

Idempotency-Key retries, metadata rules, payment reference formats and how references relate to payment links.

On this page

Payment references#

Every payment attempt is a transaction with a unique payment reference. CentraPoint generates the reference when the payer starts checkout, and sends it to the gateway as the merchant reference (for example PayFast's m_payment_id, Paystack's reference, DPO's CompanyRef). The reference is how you look up a payment with GET /api/v1/transactions/{reference}, and how gateway notifications are matched to transactions.

Reference format#

Format
CP-<YYYYMMDD>-<8 upper-case hex characters>

CP-20260925-9F3A1C7B
  • YYYYMMDD is the UTC date the checkout started.
  • The last part is random (4 bytes), so references are unguessable in practice and unique across the platform.
  • Payments created before 25 September 2026 have references in the older GSS-YYYYMMDD-XXXXXXXX format. They keep those references, remain valid for every API call, and are recognised by reconciliation alongside CP- references.
  • Treat references as opaque strings up to 190 characters. Do not parse the date out of them; use createdAt instead.

Recurring renewals#

With gateway-managed subscriptions (for example PayFast), each later charge re-uses the original merchant reference. CentraPoint records each renewal as its own transaction with the reference <original reference>-<gateway payment id> and type: "recurring", for example CP-20260925-9F3A1C7B-2458799.

Debit order references#

Debit order collections use the mandate's account reference plus the action date, for example DO7F3A1C9B2E-20261001. See Debit orders & reconciliation.

EFT order references#

EFT orders use a deposit reference such as EFT-7K3Q9P2M (your prefix plus 8 characters without 0, O, 1, I or L) as their payment reference.

A payment link and a transaction are different things:

Payment link versus transaction
Payment linkTransaction
Created byPOST /api/v1/payment-links (or the dashboard)The payer starting checkout on the link
Identifierid (and your optional externalReference)reference
How manyOneZero or more per link: every checkout attempt creates one (a retry after a failed or cancelled attempt creates another)

Finding the references for your order#

Recommended pattern:

  1. Create the link with externalReference set to your order ID ("ORDER-1001").
  2. When you need the outcome, call GET /api/v1/payment-links?externalReference=ORDER-1001 (or GET /api/v1/payment-links/{id} if you stored the link ID). Each link includes a payments array with the reference and status of every checkout attempt, newest first.
  3. Confirm the attempt that matters with GET /api/v1/transactions/{reference}. The transaction echoes paymentLinkId and externalReference, so you can check it belongs to your order.

Idempotency#

Networks fail: a request can time out after CentraPoint has already acted on it. GET and PATCH requests are safe to repeat. For POST requests, use an Idempotency-Key and/or an externalReference so a retry never creates a second link, invoice or payment.

The Idempotency-Key header#

Request header
Idempotency-Key: 3f6c2a4e-8d1b-4f7a-9c2e-5b1d0a7e6f31
  • Supported on the v1 POST endpoints: payment links, customers, invoices (create, send, cancel, payments) and EFT orders (create, cancel). POST /api/v1/subscriptions/{id}/cancel and the EFT proof upload ignore it; they are naturally safe to repeat.
  • Up to 200 characters. Generate a new unique value (such as a UUID) for each distinct operation, and reuse it only when retrying that operation.
  • Keys are remembered for 24 hours, scoped to your organisation, the HTTP method and the exact request path (for example POST /api/v1/invoices/inv_A/send). The same key on a different path, such as another invoice, is a separate key. A retry with the same key and the same body returns the original response (status and body) with the header Idempotent-Replayed: true, without doing the work again.
  • The same key with a different body returns 409 idempotency_conflict.
  • Successful and 4xx responses are stored and replayed. 5xx responses are not stored, so retrying after a server error runs the request again.
  • The body is compared byte for byte: serialise it the same way when retrying.

Idempotent by externalReference#

  • Invoices: POST /api/v1/invoices with an externalReference that already exists returns the existing invoice (200) and changes nothing.
  • Customers: POST /api/v1/customers with an externalReference is an upsert: repeated calls update the same customer.
  • EFT orders: POST /api/v1/eft-orders with the externalReference of an open order returns that order (200); a different amount or currency is a 400.
  • Payment links: externalReference is not unique, so repeating a create without an Idempotency-Key makes another link. After a timeout without a key, check GET /api/v1/payment-links?externalReference=<order id> before creating again. With singleUse: true (the default) and an expiresAt, a stray duplicate cannot be paid twice or indefinitely.

Metadata#

Payment links, customers, invoices and EFT orders accept metadata: your own key/value data, such as IDs from your CRM or cart. CentraPoint stores it and returns it; it never affects processing.

metadata
{
  "metadata": {
    "crmId": "0061x00000AbCdE",
    "cartId": "c_8841",
    "plan": "pro"
  }
}
Metadata rules
RuleLimit
ShapeA flat JSON object (no arrays or nested objects)
Keys1–40 characters: letters, digits and _ . : -; at most 50 keys
ValuesStrings up to 500 characters. Numbers and booleans are stored as strings; null values are dropped.
Total sizeAt most 4000 characters as JSON
  • Always returned as an object: {} when empty.
  • Payment link and EFT order metadata is echoed on their transactions and payment.* webhooks; payment link metadata also appears on subscriptions it starts.
  • On PATCH /api/v1/customers/{id}, metadata replaces the whole map; send null to clear it.
  • Don't store secrets or card data in metadata.

How CentraPoint de-duplicates gateway notifications#

Gateways often send the same notification more than once. CentraPoint applies each status change exactly once:

  • A notification that repeats the current status is recorded as a duplicate and ignored.
  • Status only moves forward: pending → cancelled → failed → complete. A late failed never overwrites complete, but a late complete does replace cancelled or failed.
  • Refunded transactions (refunded, partially_refunded) are not changed by gateway notifications.
  • Fulfilment (marking an invoice paid, deactivating a single-use link, storing a subscription token) runs only in the update that actually moves the status, even under concurrent notifications.