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#
- Your system creates an EFT order. CentraPoint returns your bank details and a unique deposit reference.
- The payer transfers the exact amount using that reference, then uploads proof of payment (through your app or site).
- 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#
- In the dashboard go to Settings → Payment providers and add Manual EFT (bank transfer).
- Enter the bank, account holder, account number, universal branch code (6 digits) and account type. These are shown to payers on every order.
- Optionally set the deposit reference prefix (2–6 letters, default
EFT, giving references likeEFT-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#
| Status | What it means | What happens next |
|---|---|---|
awaiting_payment | Order issued; no proof yet. | Proof upload → awaiting_review. Past expiresAt → expired. |
awaiting_review | Proof received; staff notified by email. | Approve → paid. Reject → rejected. Never expires while waiting for review. |
rejected | Staff rejected the proof, with a reason. | New proof → awaiting_review. Past expiresAt → expired. |
paid | Staff approved; the payment is complete. | Final. |
expired | Expired unpaid. Checked every 10 minutes. | Staff can still approve it if the money arrives late. |
cancelled | Cancelled 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'sproofs(API uploadsapi, staff uploadsdashboard). notifyPayer: trueon 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
paidand 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 asrejectionReasonand sent ineft.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#
| Event | When |
|---|---|
eft.proof_received | Proof was uploaded; the order is awaiting review. |
eft.rejected | Staff rejected the proof. Tell the payer and ask for new proof. |
eft.expired | The order expired unpaid. |
eft.cancelled | The order was cancelled through the API or the dashboard. |
payment.complete | Staff approved. data.eftOrderId and data.externalReference identify the order. Fulfil now. |
payment.cancelled | The 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_paymentorrejectedthat 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
externalReferenceandmetadata), 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.completecarriespaymentLinkId, the link'sexternalReferenceandmetadata, andeftOrderId; invoices also sendinvoice.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
expiresAtto 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.