API flows
Authentication
To authenticate, include the mandatory authentication
object, containing the userId
, password
, and entityId
fields, in the request body. The authentication
object verifies that the request originated from a valid merchant using a valid payment method for a specific currency.
Payment flow
The Payments API supports both synchronous and asynchronous payment flows:
-
Synchronous flow: In this flow, you send all the required parameters in the request and receive a final transaction status response without requiring any extra customer input. 1Voucher uses a synchronous flow. For this payment flow, you have full control over the user interface that you use to collect the required parameters.
-
Asynchronous flow: In this flow, the transaction enters a pending state before the final state. You must use webhooks and the transaction status endpoint to query the transaction's final status. The two types of asynchronous flows are:
- Custom user interface: You collect the required customer information using your custom user interface and make the payment request. In the response, you get a second factor (waiting or OTP) page that you must load until the payment completes, for example, Capitec Pay, blink by Emtel, M-PESA, Mobicred, and so on.
- Payment service provider user interface: You execute a payment request and receive back a URL which you must load to show the user interface required for the customer to complete the transaction, for example, EFTsecure, Payflex, ZeroPay, InstantEFT, FinChoicePay, and so on. For this flow, you have limited control over the user interface used to collect the required customer information.
The following section describes an asynchronous flow:

Payment flow.
- The merchant initiates the call to create a new transaction by making a request to the
/payments
endpoint. - The Payments API returns a response with a
000.200.000
result code indicating that it has created the transaction, placed it in a pending state, and is now awaiting payment. - The Payments API sends a webhook to the merchant with the same result code, informing them that the transaction moved from processing to pending. The merchant should expect webhooks whenever the transaction changes status.
- The merchant must redirect the customer to the URL in the
redirect
object. Some payment methods use GET requests, for which you must include the parameters as query strings. Others use POST requests, for which you must include the parameters in the request body asx-www-form-urlencoded
content. - The payment method user interface displays to capture the customer's payment information.
- The customer submits the required information.
- The Payments API redirects back to the URL specified in
shopperResultUrl
in the original payment request. - The merchant executes the transaction status API request to retrieve the final transaction status.
- The Payments API sends a webhook to the merchant notifying them of the outcome of the transaction. For successful transactions, the webhook has the
000.000.000
result code.
Refund flow
The refund flow uses the same endpoint as the debit flow, but the refund endpoint requires the original Peach unique ID as a path parameter, for example, /payments/{unique_transaction_id}/
and you must set the payment type to RF
.

Refund flow.
- The merchant makes a request to the refund endpoint with the Peach unique ID of the original transaction.
- For asynchronous refunds, the Payments API returns a pending result code (
000.200.000
) and the transaction transitions to a final state when the PSP has processed the refund.
For synchronous refunds, the Payments API returns either a successful or failure result code. The merchant receives a webhook for each transaction status change. The merchant can use the transaction status API call to verify the status of a transaction at any time.
Transaction status flow
You can send two transaction status requests per minute per transaction.

Transaction status flow.
- The merchant sends a transaction status request to the Payments API.
- The Payments API responds, with the result code indicating the status of the transaction.
Webhook flow
Webhooks provide updates on any changes in the state of the transaction. The Payments API sends them regardless of whether the transaction succeeded or failed. You must decrypt the encrypted webhook request body to process the transaction data.

Webhook flow.
- The merchant receives a webhook with a result code indicating the updated transaction status.
- The merchant returns a
200
status code response acknowledging the webhook.
To decrypt the webhook, see these examples. Some of the decryption examples are specific to AES 256, you must change these for AES 128 to match the relevant Peach Payments decryption key.
Webhook events
Peach Payments sends webhooks for certain events, including, but not limited to:
- Pending
- Successful
- Cancelled
- Failed
After decryption, the webhook payload resembles the following:
{
"id":"02f2ef804c4f4713ab053661cba98d4z",
"referencedId":"",
"paymentType":"DB",
"paymentBrand":"EFTSECURE",
"amount":"1.0",
"merchantTransactionId":"EFT_Testdb7532d8-de64-4952-a37e-844774412a6d",
"merchantInvoiceId":null,
"merchantAccountId":"28f0a55c50e911eb88ef02de7a5a0a6z",
"descriptor":"",
"currency":"ZAR",
"presentationAmount":"1.0",
"presentationCurrency":"ZAR",
"result":{
"code":"000.200.000",
"description":"transaction pending"
},
"resultDetails":{
"clearingInstituteName":"EFT",
"ExtendedDescription":"Payment process started.",
"AcquirerResponse":"PENDING"
},
"connectorTxID1":null,
"authentication":{
"entityId":"8ac7a4ca77a64c9c0177af52972c13bz"
},
"card":{
"bin":null,
"last4Digits":null,
"holder":null,
"type":null,
"expiryMonth":null,
"expiryYear":null
},
"timestamp":"2023-07-20T11:12:26.510635Z",
"customer":{
"givenName":"Grace",
"surname":"Nkosi",
"merchantCustomerId":null,
"sex":"",
"mobile":null,
"email":null,
"status":null,
"phone":null
},
"shipping":{
"street1":null,
"street2":null,
"city":null,
"country":null,
"state":null,
"postcode":null,
"company":null
},
"billing":{
"street1":null,
"street2":null,
"city":null,
"sex":"",
"country":null,
"state":null,
"postcode":null,
"company":null
},
"shopify":{
"orderId":null,
"accountId":null,
"signature":null,
"testMode":null
},
"bankAccount":{
"holder":null,
"bankName":null,
"bankCode":null
},
"recon":{
"authCode":null,
"ciMerchantNumber":null,
"resultCode":null,
"rrn":null,
"stan":null
},
"merchant":{
"apiUsername":"api.user",
"eftId":"12345"
},
"customParameters":{
"PEACH_MERCHANT_ID":"e098a59e50e411eb88ef02de7a5a0a6z"
}
}
{
"id":"02f2ef804c4f4713ab053661cba98d4z",
"referencedId":"",
"paymentType":"DB",
"paymentBrand":"EFTSECURE",
"amount":"1.0",
"merchantTransactionId":"EFT_Testdb7532d8-de64-4952-a37e-844774412a6d",
"merchantInvoiceId":null,
"merchantAccountId":"28f0a55c50e911eb88ef02de7a5a0a6z",
"descriptor":"",
"currency":"ZAR",
"presentationAmount":"1.0",
"presentationCurrency":"ZAR",
"result":{
"code":"000.000.000",
"description":"Transaction succeeded'"
},
"resultDetails":{
"clearingInstituteName":"EFT",
"ExtendedDescription":"n/a",
"AcquirerResponse":1
},
"connectorTxID1":"105035601",
"authentication":{
"entityId":"8ac7a4ca77a64c9c0177af52972c13bz"
},
"card":{
"bin":null,
"last4Digits":null,
"holder":null,
"type":null,
"expiryMonth":null,
"expiryYear":null
},
"timestamp":"2023-07-20T11:17:33.874611Z",
"customer":{
"givenName":"Grace",
"surname":"Nkosi",
"merchantCustomerId":null,
"sex":"",
"mobile":null,
"email":null,
"status":null,
"phone":null
},
"shipping":{
"street1":null,
"street2":null,
"city":null,
"country":null,
"state":null,
"postcode":null,
"company":null
},
"billing":{
"street1":null,
"street2":null,
"city":null,
"sex":"",
"country":null,
"state":null,
"postcode":null,
"company":null
},
"shopify":{
"orderId":null,
"accountId":null,
"signature":null,
"testMode":null
},
"bankAccount":{
"holder":null,
"bankName":null,
"bankCode":null
},
"recon":{
"authCode":null,
"ciMerchantNumber":null,
"resultCode":null,
"rrn":null,
"stan":null
},
"merchant":{
"apiUsername":"api.user",
"eftId":"12345"
},
"customParameters":{
"PEACH_MERCHANT_ID":"e098a59e50e411eb88ef02de7a5a0a6z"
}
}
{
"id":"aa4751285ca048b5b9516beb94b6cd5z",
"referencedId":"",
"paymentType":"DB",
"paymentBrand":"EFTSECURE",
"amount":"1.0",
"merchantTransactionId":"EFT_Test702d3324-97c4-4b04-b87a-7db8dc728fbe",
"merchantInvoiceId":null,
"merchantAccountId":"28f0a55c50e911eb88ef02de7a5a0a6z",
"descriptor":"",
"currency":"ZAR",
"presentationAmount":"1.0",
"presentationCurrency":"ZAR",
"result":{
"code":"100.396.101",
"description":"Cancelled by user"
},
"resultDetails":{
"clearingInstituteName":"EFT",
"ExtendedDescription":"Aborted during payment",
"AcquirerResponse":0
},
"connectorTxID1":"105037083",
"authentication":{
"entityId":"8ac7a4ca77a64c9c0177af52972c13bz"
},
"card":{
"bin":null,
"last4Digits":null,
"holder":null,
"type":null,
"expiryMonth":null,
"expiryYear":null
},
"timestamp":"2023-07-20T11:30:16.445945Z",
"customer":{
"givenName":"Grace",
"surname":"Nkosi",
"merchantCustomerId":null,
"sex":"",
"mobile":null,
"email":null,
"status":null,
"phone":null
},
"shipping":{
"street1":null,
"street2":null,
"city":null,
"country":null,
"state":null,
"postcode":null,
"company":null
},
"billing":{
"street1":null,
"street2":null,
"city":null,
"sex":"",
"country":null,
"state":null,
"postcode":null,
"company":null
},
"shopify":{
"orderId":null,
"accountId":null,
"signature":null,
"testMode":null
},
"bankAccount":{
"holder":null,
"bankName":null,
"bankCode":null
},
"recon":{
"authCode":null,
"ciMerchantNumber":null,
"resultCode":null,
"rrn":null,
"stan":null
},
"merchant":{
"apiUsername":"api.user",
"eftId":"12345"
},
"customParameters":{
"PEACH_MERCHANT_ID":"e098a59e50e411eb88ef02de7a5a0a6z"
}
}
{
"id":"2d3014384d1b4d53b94203cf9e3e04fz",
"referencedId":"",
"paymentType":"DB",
"paymentBrand":"EFTSECURE",
"amount":"1.0",
"merchantTransactionId":"EFT_Test0b9836c4-e83f-4d23-81c0-287aa6159085",
"merchantInvoiceId":null,
"merchantAccountId":"28f0a55c50e911eb88ef02de7a5a0a6z",
"descriptor":"",
"currency":"ZAR",
"presentationAmount":"1.0",
"presentationCurrency":"ZAR",
"result":{
"code":"800.100.152",
"description":"transaction declined by authorization system"
},
"resultDetails":{
"clearingInstituteName":"EFT",
"ExtendedDescription":"Amount daily limit reached",
"AcquirerResponse":"0"
},
"connectorTxID1":null,
"authentication":{
"entityId":"8ac7a4ca77a64c9c0177af52972c13bz"
},
"card":{
"bin":null,
"last4Digits":null,
"holder":null,
"type":null,
"expiryMonth":null,
"expiryYear":null
},
"timestamp":"2023-07-20T11:37:59.649483Z",
"customer":{
"givenName":"Grace",
"surname":"Nkosi",
"merchantCustomerId":null,
"sex":"",
"mobile":null,
"email":null,
"status":null,
"phone":null
},
"shipping":{
"street1":null,
"street2":null,
"city":null,
"country":null,
"state":null,
"postcode":null,
"company":null
},
"billing":{
"street1":null,
"street2":null,
"city":null,
"sex":"",
"country":null,
"state":null,
"postcode":null,
"company":null
},
"shopify":{
"orderId":null,
"accountId":null,
"signature":null,
"testMode":null
},
"bankAccount":{
"holder":null,
"bankName":null,
"bankCode":null
},
"recon":{
"authCode":null,
"ciMerchantNumber":null,
"resultCode":null,
"rrn":null,
"stan":null
},
"merchant":{
"apiUsername":"api.user",
"eftId":"12345"
},
"customParameters":{
"PEACH_MERCHANT_ID":"e098a59e50e411eb88ef02de7a5a0a6z"
}
}
Example requests and responses
For sample requests and responses, see the interactive API playground or use the Peach Payments Postman collection:
Updated about 2 months ago