CentraPoint

API

EFT orders API

Issue unique deposit references for bank transfers, upload proof of payment and track each order until your team approves it.

On this page

Overview#

An EFT order asks a payer to transfer a fixed amount into your own bank account using a unique deposit reference. The payer (or your system) uploads proof of payment, and your team approves the deposit in the dashboard once it reflects. Approval completes the payment like any other, so you receive payment.complete and receipts and accounting sync happen as usual. See the Accepting EFT with proof of payment guide for the full flow.

Requires API access, the Payment links plan feature, and an enabled Manual EFT (bank transfer) gateway with your bank details.

EFT order endpoints
EndpointPurpose
POST /api/v1/eft-ordersCreate (idempotent on externalReference for open orders)
GET /api/v1/eft-ordersList, filter by reference, customer or status
GET /api/v1/eft-orders/{id}Get one order
POST /api/v1/eft-orders/{id}/proofUpload proof of payment (multipart)
POST /api/v1/eft-orders/{id}/cancelCancel an unpaid order

The EFT order object#

EFT order
{
  "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"
}
EFT order fields
FieldTypeDescription
idrequiredstringEFT order ID.
referencerequiredstringUnique deposit reference, e.g. EFT-7K3Q9P2M: your prefix (default EFT) and 8 characters without the easily confused 0, O, 1, I and L. It is also the transaction reference.
paymentReferencerequiredstringWhat the payer must type as the payment reference (same as reference).
payUrlrequiredstringSigned public payer page with the bank details, reference and a proof upload. No login needed; a tampered link returns 404. Share it instead of building your own upload.
statusrequiredstringSee Statuses.
amount, currencyrequirednumber, stringAmount to transfer. Currencies: ZAR, NAD, BWP, LSL, SZL.
bankDetailsrequiredobjectbankName, accountName, accountNumber, branchCode, accountType from your Manual EFT gateway. Show them to the payer.
descriptionrequiredstring | null
externalReferencerequiredstring | nullYour ID.
metadatarequiredobjectYour key/value data (rules).
customerrequiredobject | null{ id, externalReference }
proofsrequiredobject[]id, fileName, contentType, size (bytes), source and createdAt of each uploaded file, oldest first. source is api (your system), dashboard (your staff) or payer (the payer on the payer page).
rejectionReasonrequiredstring | nullWhy staff rejected the latest proof.
expiresAtrequiredstring | nullAfter this, an order still awaiting payment (or rejected) expires. The payer gets one reminder about 48 hours before.
reviewedAtrequiredstring | nullWhen staff approved or rejected it.
paidAtrequiredstring | nullWhen the payment completed (status paid).
createdAtrequiredstring

Statuses#

EFT order statuses
statusMeaningNext
awaiting_paymentCreated; waiting for the payer to transfer and send proof. Staff may approve it without proof.awaiting_review, expired, cancelled, paid
awaiting_reviewProof uploaded; waiting for your staff. Does not expire.paid, rejected, cancelled
rejectedStaff rejected the proof (rejectionReason). The payer can upload new proof until expiry.awaiting_review, expired, cancelled, paid
paidApproved; the payment is complete.–
expiredPassed expiresAt without proof (or after a rejection). Staff can still approve it if the money arrives.paid
cancelledCancelled through the API or dashboard.–

Create an EFT order#

POST/api/v1/eft-orders
Create EFT order fields
FieldTypeDescription
amountrequirednumberGreater than 0, at most 100 000 000. Rounded to cents.
currencyoptionalstringDefault ZAR. Must be one the Manual EFT gateway supports (ZAR, NAD, BWP, LSL, SZL).
customeroptionalobject{ "id": "…" } or { "externalReference": "…" }.
customerIdoptionalstringAlternative to customer; send one, not both.
descriptionoptionalstringUp to 1000 characters.
externalReferenceoptionalstring1–190 characters. See idempotency below.
metadataoptionalobjectKey/value data.
expiresAtoptionalstring (date-time)ISO 8601 with Z or an offset; 5 minutes to 90 days ahead. Default: the gateway's expiry days (7 unless configured).
notifyPayeroptionalbooleanDefault false. Email the customer the bank details and payUrl when the order is created. Needs a customer with an email address, otherwise 400. Not re-sent when an existing open order is returned.
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",
    "metadata": {
      "cartId": "c_8841"
    },
    "notifyPayer": true
  }'

Returns 201 with the order. Either send the payer to payUrl (or set notifyPayer to email it), or show bankDetails, the exact amount and the paymentReference in your own app and upload the proof through the API.

List EFT orders#

GET/api/v1/eft-orders
List query parameters
FieldTypeDescription
externalReferenceoptionalstringExact match.
customerIdoptionalstring
statusoptionalstringOne of the statuses above.
limitoptionalinteger1–100, default 20. Newest first.
curl -X GET "https://app.centrapoint.co.za/api/v1/eft-orders?status=awaiting_review" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY"

Get an EFT order#

GET/api/v1/eft-orders/{id}
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

Send multipart/form-data with one field named file. On success the order moves to awaiting_review, your staff are emailed, eft.proof_received is sent, and the updated order is returned (200).

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"

Proof rules#

  • PDF, PNG or JPEG, detected from the file's bytes; the file name and declared content type are ignored. Anything else is rejected with 400.
  • At most 10 MB per file (413 otherwise) and 10 files per order.
  • Deduplicated: an identical file is not stored twice, and while the order is already awaiting review a repeat upload doesn't notify anyone again, so retries are safe. (This endpoint does not use the Idempotency-Key header.)
  • Allowed while the order is awaiting_payment, awaiting_review or rejected, and not past expiresAt (unless already in review). After a rejection, uploading new proof moves the order back to awaiting_review and clears rejectionReason.
  • A non-multipart body returns 415; a missing file field returns 400.

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. No body is needed. Cancelling a cancelled order returns it unchanged; paid and expired orders return 400.

curl -X POST "https://app.centrapoint.co.za/api/v1/eft-orders/cmg3e1f2t0009eft0001abcd/cancel" \
  -H "Authorization: Bearer $CENTRAPOINT_API_KEY" \
  -H "Idempotency-Key: 8b0d2f4a-6c8e-4a1c-b3e5-7f9a1c3e5b7d"

Webhook events#

EFT webhook events
EventWhendata
eft.proof_receivedProof was uploaded (API or dashboard)EFT order
eft.rejectedStaff rejected the proofEFT order (with rejectionReason)
eft.expiredThe order expired unpaidEFT order
eft.cancelledThe order was cancelled (API or dashboard)EFT order
payment.completeStaff approved the order. data.eftOrderId identifies it.Payment
payment.cancelledThe order was cancelled or expiredPayment

See Webhooks for signatures and delivery.

Errors#

EFT order errors
StatuserrorWhen
400invalid_requestValidation failed; notifyPayer without a customer email; Manual EFT not set up or not available on your plan; unsupported currency; customer not found; expiresAt out of range; open order with a different amount; bad or missing proof file; order not open or expired.
403plan_restricted / plan_limit / account_restrictedNo API access or payment links; monthly transaction limit reached (create); account read-only (writes).
404not_foundNo EFT order with this ID in your organisation.
409idempotency_conflictIdempotency-Key reused with a different body (create, cancel).
413 / 415invalid_requestProof larger than 10 MB / body not multipart.
401 / 429 / 500unauthorized / rate_limited / internal_errorSee Errors