CentraPoint

Guides

Accepting EFT with proof of payment

Let customers pay by bank transfer into your own account, collect proof of payment, and approve deposits with one click.

On this page

How it works#

  1. Your system creates an EFT order. CentraPoint returns your bank details and a unique deposit reference.
  2. The payer transfers the exact amount using that reference, then uploads proof of payment (through your app or site).
  3. Your staff check the deposit and approve it in the dashboard. The payment completes and you get payment.complete.

No payment gateway or fees are involved: money goes straight into your bank account. The trade-off is a human review step, which the statement-match suggestion speeds up.

Set up the Manual EFT gateway#

  1. In the dashboard go to Settings → Payment providers and add Manual EFT (bank transfer).
  2. Enter the bank, account holder, account number, universal branch code (6 digits) and account type. These are shown to payers on every order.
  3. Optionally set the deposit reference prefix (2–6 letters, default EFT, giving references like EFT-7K3Q9P2M) and orders expire after (days) (1–90, default 7).

Requirements: API access and the Payment links plan feature. Supported currencies: ZAR, NAD, BWP, LSL, SZL. See the Manual EFT gateway reference.

Order lifecycle#

EFT order lifecycle
StatusWhat it meansWhat happens next
awaiting_paymentOrder issued; no proof yet.Proof upload → awaiting_review. Past expiresAt → expired.
awaiting_reviewProof received; staff notified by email.Approve → paid. Reject → rejected. Never expires while waiting for review.
rejectedStaff rejected the proof, with a reason.New proof → awaiting_review. Past expiresAt → expired.
paidStaff approved; the payment is complete.Final.
expiredExpired unpaid. Checked every 10 minutes.Staff can still approve it if the money arrives late.
cancelledCancelled by your system or staff.Final.

1. Create an order#

curl -X POST "https://app.centrapoint.co.za/api/v1/eft-orders" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 5e7a9c1b-3d5f-4a7c-9e1b-3d5f7a9c1e2b" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 1250,
    "customer": {
      "externalReference": "CRM-1001"
    },
    "description": "Order #1001",
    "externalReference": "ORDER-1001",
    "notifyPayer": true
  }'

Send the payer to the order's payUrl, or let CentraPoint email it with notifyPayer: true (the customer needs an email address). Or show bankDetails, the exact amount and the paymentReference in your own app. Either way, ask the payer to use the reference exactly. Creating again with the same externalReference while the order is open returns the same order, so you never issue two references for one purchase.

2. Collect proof of payment#

Letting payers upload proof themselves#

Every order has a payUrl: a CentraPoint-hosted page for the payer, so you don't have to build an upload yourself.

  • It shows the amount, the bank details and the reference, with copy buttons, and an upload for the proof of payment.
  • No login is needed. The link is signed: changing any part of it returns 404, so knowing an order ID or reference is not enough to open it.
  • It shows the order's state: confirmation after an upload, the rejection reason with a prompt to upload new proof, and "paid", "cancelled" or "expired" messages. Uploads close once the order can no longer take proof.
  • The same proof rules apply (PDF, PNG or JPEG, up to 10 MB). Uploads are rate-limited per network and per order. Payer uploads have source: "payer" in the order's proofs (API uploads api, staff uploads dashboard).
  • notifyPayer: true on create emails the payer the bank details and this link.

Uploading through the API#

If you collect the file in your own app, forward it to CentraPoint (PDF, PNG or JPEG, up to 10 MB):

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"
  • The file type is detected from its content, not its name. Screenshots in other formats (e.g. HEIC) are rejected.
  • Identical files are deduplicated, so retrying an upload is safe.
  • After a rejection, the payer can upload new proof until the order expires; it goes back to review.

Staff can also upload proof on the payer's behalf in the dashboard, for example when it arrives by email.

3. Staff review in the dashboard#

Staff and administrators receive an email for each proof. Under EFT orders in the dashboard they open the order, view the proof files and either:

  • Approve: the order becomes paid and the transaction completes through the normal payment engine (receipt email, payment.complete, accounting sync, invoice updates).
  • Reject with a reason: the order becomes rejected, the reason is returned as rejectionReason and sent in eft.rejected, and the payer may upload new proof.

Staff can also approve an order without proof, including one that is still awaiting payment or has already expired. This is intentional: your team often sees the deposit in the bank before (or instead of) the payer sending proof, and a late transfer should still be accepted.

Statement-match suggestion#

If you import bank or Netcash statements through reconciliation, CentraPoint looks for an unmatched incoming line with the same amount and the order reference in its reference or description (from one day before the order onwards). When it finds one, the review screen shows it and the button becomes Approve and match, which approves the order and marks that statement line as matched in one step.

4. Webhooks#

Webhooks for EFT orders
EventWhen
eft.proof_receivedProof was uploaded; the order is awaiting review.
eft.rejectedStaff rejected the proof. Tell the payer and ask for new proof.
eft.expiredThe order expired unpaid.
eft.cancelledThe order was cancelled through the API or the dashboard.
payment.completeStaff approved. data.eftOrderId and data.externalReference identify the order. Fulfil now.
payment.cancelledThe order was cancelled or expired.

eft.* events carry the EFT order object. See Webhooks for verification.

Payment reminders#

CentraPoint emails the payer one reminder for orders that are still unpaid, with no action needed from you:

  • About 48 hours before expiry, for orders in awaiting_payment or rejected that are at least a day old (so short-lived orders aren't reminded straight after creation).
  • It contains the bank details, the reference and the payer page link.
  • It goes to the email the payer entered at checkout if there is one, otherwise the customer's email. Orders with neither get no reminder.
  • Orders awaiting review are not reminded, and each order gets at most one reminder.

EFT at hosted checkout#

With a Manual EFT gateway set up, CentraPoint's own payment pages also offer Bank transfer (EFT) next to your card gateways, with no extra integration:

  • It appears on payment link pages and on invoice pay links for once-off payments in a currency Manual EFT supports. Recurring links don't offer it.
  • Choosing it creates an EFT order for that link or invoice (with the link's externalReference and metadata), emails the payer the instructions, and redirects them to the order's payer page.
  • The same payer (by email) coming back gets their existing open order rather than a new reference. Each payer of a multi-use link gets their own order.
  • When staff approve it, it counts as a payment of the link (paid count, single-use links close) and pays the invoice. payment.complete carries paymentLinkId, the link's externalReference and metadata, and eftOrderId; invoices also send invoice.paid.
  • Once-off links and invoice pay links can be created even when Manual EFT is your only gateway.

Good practice#

  • Fulfil on payment.complete, never on proof upload.
  • Set expiresAt to match your stock or quote validity. With at least three days, payers get the reminder with a day to spare.
  • Cancel orders you no longer want paid, so late transfers are spotted rather than approved by mistake.
  • Import statements daily so most approvals are one-click matches.