Step 1 : Post from merchant website

After the user confirms his purchase and has chosen Ozow as his preferred payment method, you will need to post the following variables to https://pay.ozow.com/.

🤚

Please note

Variables 18-26 are not commonly used and can be ignored unless you specifically require that functionality.

Post variables

PropertyTypeReq.Description
1.SiteCodeString (50)YesA unique code for the site currently in use. A site code is generated when adding a site in the Ozow merchant admin section.
2.CountryCodeString (2)YesThe ISO 3166-1 alpha-2 code for the user's country. The country code will determine which banks will be displayed to the customer. Please note only South African (ZA) banks are currently supported by Ozow.
3.CurrencyCodeString (3)YesThe ISO 4217 three-letter code for the transaction currency. Please note only the South African Rand (ZAR) is currently supported by Ozow, so any currency conversion must take place before posting to the Ozow site.
4.AmountDecimal
(9,2)
YesThe transaction amount. The amount is in the currency specified by the currency code posted.
5.TransactionReferenceString (50)YesThe merchant's reference for the transaction.
6.BankReferenceString (20)YesThe reference that will be pre-populated in the "their reference" field in the customers online banking site. This is the payment reference that appears on the merchant’s bank statement and can be used for recon purposes. Only alphanumeric characters, spaces, and dashes are allowed.
7.Optional1
8.Optional2
9.Optional3
10.Optional4
11.Optional5
String (50)NoOptional fields the merchant can post for additional information they would need passed back in the response. These are also stored with the transaction details by Ozow, and can be useful for filtering transactions in the merchant admin section.
12.CustomerString (100)NoThe customer’s name or identifier.
13.CancelUrlString (150)NoThe URL to which the redirect result should be posted to if the customer cancels the payment. This is also the page the customer will be redirected to. This URL can also be set for the applicable merchant site in the merchant admin section. If a value is set in the merchant admin and sent in the post, the posted value will be redirected to if the payment is cancelled.
14.ErrorUrlString (150) NoThe URL to which the redirect result should be posted if an error occurs while trying to process the payment. This is also the page the customer will be redirected to. This URL can also be set for the applicable merchant site in the merchant admin section. If a value is set in the merchant admin and sent in the post, the posted value will be redirected to if an error occurred while processing the payment.
15.SuccessUrlString (150) No The URL to which the redirect result should be posted to if the payment is successful. This is also be the page the customer gets redirected to. This URL can also be set for the applicable merchant site in the merchant admin section. If a value is set
in the merchant admin and sent in the post, the posted value will be redirected to if the payment was successful.

Please note that it is not sufficient to assume that the payment was successful simply because the customer has been redirected back to this page. It is highly recommended that you check the response fields as well as the transaction status using our check transaction status API call.
16.NotifyUrl String (150)NoThe URL that the notification result should be posted to. The result will post regardless of the outcome of the transaction. This URL can also be set for the applicable merchant site in the
merchant admin section. If a value is set in the merchant admin and sent in the post, the notification result will be sent to the posted value. Find out more in the notification response section in step 2.
17.IsTestbool YesAccepted values are true or false. Send true to test your request posting and response handling. If set to true you will be redirected to select whether you would like a successful or unsuccessful redirect response sent back.

Please note that notification responses are sent for test transactions and the online banking payment is skipped.
18.SelectedBankIdGuidNoIf the 'SelectedBankId' field is populated by the Merchant, the Customer will be redirected to the Ozow login page of the selected bank. However, if the field is left empty, the Customer will be presented with Ozow bank selection screen.

Allowed values are:

• ABSA – 3284A0AD-BA78-4838-8C2B-102981286A2B
• Capitec – 913999FA-3A32-4E3D-82F0-A1DF7E9E4F7B
• FNB – 4816019C-3314-4C80-8B6B-B2CD16DCC4EC
• Nedbank – D3889DF6-CDAC-4861-9D64-2B100FB7ED07
• Standard Bank – AD8127C6-316D-459C-ADCC-E62A214251FC
• Investec – 4B45BE85-B616-4BD1-9027-F8FCF8F9AF7B
• African Bank – 33A0840B-0CF4-4B8C-86E0-EC6C4BE8C60E
• Tymebank – 28FCC8FA-985B-480B-82FD-7D09BC19C9D0
• Bidvest Bank Grow – E022DFC8-FF4A-4425-A074-C65D07E8F09C
• Cash Voucher – 42F71BF8-0E09-43D5-A6EB-4F7370CB5B20
19.BankIdGuidNoThe bank that the payment should be made to. Merchant needs to be enabled to send through banking details (18 - 21) in the post, for most merchants this is set up when creating the merchant account.

Allowed values are:

• ABSA – 3284A0AD-BA78-4838-8C2B-102981286A2B
• Capitec – 913999FA-3A32-4E3D-82F0-A1DF7E9E4F7B
• FNB – 4816019C-3314-4C80-8B6B-B2CD16DCC4EC
• Nedbank – D3889DF6-CDAC-4861-9D64-2B100FB7ED07
• Standard Bank – AD7D8DA4-1723-4066-94BB-6662D845E483
• Investec – 4B45BE85-B616-4BD1-9027-F8FCF8F9AF7B
• African Bank – 33A0840B-0CF4-4B8C-86E0-EC6C4BE8C60E
• Tymebank – 28FCC8FA-985B-480B-82FD-7D09BC19C9D0
• Bidvest Bank Grow – E022DFC8-FF4A-4425-A074-C65D07E8F09C
20.BankAccountNumberString (20)NoThe bank account number the payment should be made to.
21.BranchCodeString (10)NoThe branch code for the bank account (19).
22.BankAccountNameString (50)NoThe name to be used for the bank account. Only alphanumeric characters and spaces allowed.
23.PayeeDisplayNameString (50)NoThe name shown on the site as the entity being paid (not in banking screens).
24.ExpiryDateUtcString (19)NoPayment will not be allowed to be made after this date. Date should be UTC and value should be formatted as yyyy-MM-dd HH:mm e.g. 2015-08-11 16:02
25.AllowVariableAmountboolNoAllows the user to change the amount passed through before paying. This option must also be enabled for the site in the merchant admin portal to be used. Accepted values are true or false. DO NOT include false in the hash check string, just ignore instead.
26.VariableAmountMinDecimal (9,2)NoIf AllowVariableAmount is passed through as true, this will dictate the lowest acceptable amount the user can enter.
27.VariableAmountMaxDecimal (9,2)NoIf AllowVariableAmount is passed through as true, this will dictate the highest acceptable amount the user can enter.
28.CustomerIdentifierString (13) NoMerchants classified as high-risk must provide a valid South African identity number. It's important to note that this is an optional field for all other merchants. For more details, please reach out to [email protected].
29. CustomerCellphoneNumberString (10)NoMerchant can provide customer cellphone number for faster login on certain banks. DO NOT include in the hash check string, just ignore instead.
30.HashCheckString (250) YesSHA512 hash used to ensure that certain fields in the message have not been altered after the hash was generated. Check the generate hash section below for more details on how to generate the hash.

Follow these steps to generate the hash check:

  1. Concatenate the post variables (excluding HashCheck and Token) in the order they appear in the post variables table.
  2. Append your private key to the concatenated string. Your private key can be found in merchant details section of the merchant admin site.
  3. Convert the concatenated string to lowercase.
  4. Generate a SHA512 hash of the lowercase concatenated string.

Hash check example

SiteCode: TSTSTE0001
CountryCode: ZA
CurrencyCode: ZAR
Amount: 25.00
TransactionReference: 123
BankReference: ABC123
CancelUrl: http://demo.ozow.com/cancel.aspx
ErrorUrl: http://demo.ozow.com/error.aspx
SuccessUrl: http://demo.ozow.com/success.aspx
NotifyUrl: http://demo.ozow.com/notify.aspx
IsTest: false

  1. TSTSTE0001ZAZAR25.00123ABC123http://demo.ozow.com/cancel.aspxhttp://demo.ozow.com/cancel.ashttp://demo.ozow.com/success.aspxhttp://demo.ozow.com/notify.aspxfalse
  2. TSTSTE0001ZAZAR25.00123ABC123http://demo.ozow.com/cancel.aspxhttp://demo.ozow.com/cancel.aspxhttp://demo.ozow.com/success.aspxhttp://demo.ozow.com/notify.aspxfalse[YOUR PRIVATE KEY]
  3. tstste0001zazar25.00123abc123[http://demo.ozow.com/cancel.aspxhttp://demo.ozow.com/cancel.aspxht]http://demo.ozow.com/success.aspx(http://demo.ozow.com/notify.aspxfalse[your private key]
  4. eedcba106cd8fef3ba6cec5ec80de7d7d7fc90343028bf95b908718c671d0fe885ca08b206d788de009d237a93c18e66edf6ede3f5ca7057e23474106465dcc6
using System.Security.Cryptography;
using System.Text;
using System;

GenerateRequestHash();
void GenerateRequestHash()
{
	string siteCode = "[YOUR SITE CODE]";
	string countryCode = "ZA";
	string currencyCode = "ZAR";
	decimal amount = 25.01M;
	string transactionReference = "123";
	string bankReference = "ABC123";
	string cancelUrl = "http://mydomain.com/cancel.html";
	string errorUrl = "http://mydomain.com/error.html";
	string successUrl = "http://mydomain.com/success.html";
	string notifyUrl = "http://mydomain/notify.html";
	string privateKey = "[YOUR PRIVATE KEY]";
	bool isTest = false;
	string inputString = string.Concat(siteCode, countryCode, currencyCode, amount, transactionReference, bankReference, cancelUrl, errorUrl, successUrl, notifyUrl, isTest, privateKey);
	string calculatedHashResult = GenerateRequestHashCheck(inputString);
	Console.WriteLine($"Hashcheck: {calculatedHashResult}");
}

string GenerateRequestHashCheck(string inputString)
{
	var stringToHash = inputString.ToLower();
	Console.WriteLine($"Before Hashcheck: {stringToHash}");
	return GetSha512Hash(stringToHash);
}

string GetSha512Hash(string stringToHash)
{
	using (SHA512 alg = new SHA512CryptoServiceProvider())
	{
		var bytes = alg.ComputeHash(Encoding.UTF8.GetBytes(stringToHash));
		var sb = new StringBuilder();
		foreach (var b in bytes)
		{
			var hex = b.ToString("x2");
			sb.Append(hex);
		}

		return sb.ToString();
	}
}
<?php

function generate_request_hash() {
    $siteCode = "[YOUR SITE CODE]";
    $countryCode = "ZA";
    $currencyCode = "ZAR";
    $amount = 25.01;
    $transactionReference = "123";
    $bankReference = "ABC123";
    $cancelUrl = "http://mydomain.com/cancel.html";
    $errorUrl = "http://mydomain.com/error.html";
    $successUrl = "http://mydomain.com/success.html";
    $notifyUrl = "http://mydomain/notify.html";
    $privateKey = "[YOUR PRIVATE KEY]";
    $isTest = "false";
    
    $inputString = $siteCode . $countryCode . $currencyCode . $amount . $transactionReference . $bankReference . $cancelUrl . $errorUrl . $successUrl . $notifyUrl . $isTest . $privateKey;
    
    $calculatedHashResult = generate_request_hash_check($inputString);
    echo "Hashcheck: " . $calculatedHashResult . "\n";
}

function generate_request_hash_check($inputString) {
    $stringToHash = strtolower($inputString);
    echo "Before Hashcheck: " . $stringToHash . "\n";
    return get_sha512_hash($stringToHash);
}

function get_sha512_hash($stringToHash) {
    $bytes = hash('sha512', $stringToHash, true);
    $hex = bin2hex($bytes);
    return $hex;
}

generate_request_hash();

?>
const crypto = require("crypto");

function generateRequestHash() {
  const siteCode = "[YOUR SITE CODE]";
  const countryCode = "ZA";
  const currencyCode = "ZAR";
  const amount = 25.01;
  const transactionReference = "123";
  const bankReference = "ABC123";
  const cancelUrl = "http://mydomain.com/cancel.html";
  const errorUrl = "http://mydomain.com/error.html";
  const successUrl = "http://mydomain.com/success.html";
  const notifyUrl = "http://mydomain/notify.html";
  const privateKey = "[YOUR PRIVATE KEY]";
  const isTest = false;

  const inputString = `${siteCode}${countryCode}${currencyCode}${amount}${transactionReference}${bankReference}${cancelUrl}${errorUrl}${successUrl}${notifyUrl}${isTest}${privateKey}`;

  const calculatedHashResult = generateRequestHashCheck(inputString);
  console.log(`Hashcheck: ${calculatedHashResult}`);
}

function generateRequestHashCheck(inputString) {
  const stringToHash = inputString.toLowerCase();
  console.log(`Before Hashcheck: ${stringToHash}`);
  return getSha512Hash(stringToHash);
}

function getSha512Hash(stringToHash) {
  const hash = crypto.createHash("sha512");
  hash.update(stringToHash);
  return hash.digest("hex");
}

generateRequestHash();

import hashlib
import string

def generate_request_hash():
    site_code = '[YOUR SITE CODE]'
    country_code = 'ZA'
    currency_code = 'ZAR'
    amount = 25.01
    transaction_reference = '123'
    bank_reference = 'ABC123'
    cancel_url = 'http://mydomain.com/cancel.html'
    error_url = 'http://mydomain.com/error.html'
    success_url = 'http://mydomain.com/success.html'
    notify_url = 'http://mydomain/notify.html'
    private_key = '[YOUR PRIVATE KEY]'
    is_test = False

    input_string = site_code + country_code + currency_code + str(amount) + transaction_reference + bank_reference + cancel_url + error_url + success_url + notify_url + str(is_test) + private_key
    input_string = input_string.lower()
    calculated_hash_result = generate_request_hash_check(input_string)
    print(f"Hashcheck: {calculated_hash_result}")

def generate_request_hash_check(input_string):
    print(f"Before Hashcheck: {input_string}")
    return get_sha512_hash(input_string)

def get_sha512_hash(input_string):
    sha = hashlib.sha512()
    sha.update(input_string.encode())
    return sha.hexdigest()

generate_request_hash()

Generate payment URL using API

https://api.ozow.com/PostPaymentRequest
This method is called when you want to generate a payment URL that will be included in an email or SMS.

Parameters

PropertyTypeReq.Description
ApiKey (Http request header value)String (50)YesMerchant's API key, this value is available in the Ozow merchant admin section.
Content-Type (Http request header value)String (50)YesFormat of your post data object. Available values:

• application/json – post data object is a JSON string
• application/xml - post data object is a XML string
Accept (Http request header value)String (50)YesDetermines the format the response is returned in. Available values:

• application/json - Response is returned as JSON
• application/xml - Response is returned as XML
Post data objectString (JSON
/ XML)
YesApplicable post variables found in post variables table above as either a serialised json object or XML element e.g. { "SiteCode":
"TSTSTE0001", …, "HashCheck":
"6b46c27agfd4656fg3534gfd435”}

If you are using this to generate a link that will be used for SMS, email or for QR codes you need to pass an extra Boolean variable in the post data object i.e. GenerateShortUrl with a value of true. This extra field
should not be used to generate the hash. e.g. { …, "
GenerateShortUrl ": true }
<?php

$curl = curl_init();

$data = [
    "countryCode" => "ZA",
    "amount" => "0.01",
    "transactionReference" => "Test1",
    "bankReference" => "Test1",
    "cancelUrl" => "http://test.i-pay.co.za/responsetest.php",
    "currencyCode" => "ZAR",
    "errorUrl" => "http://test.i-pay.co.za/responsetest.php",
    "isTest" => false,
    "notifyUrl" => "http://test.i-pay.co.za/responsetest.php",
    "siteCode" => "[YOUR SITECODE]",
    "successUrl" => "http://test.i-pay.co.za/responsetest.php",
    "hashCheck" => "[GENERATED HASH]"
];

curl_setopt_array($curl, array(
  CURLOPT_URL => 'https://api.ozow.com/postpaymentrequest',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 0,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_POSTFIELDS => json_encode($data),
  CURLOPT_HTTPHEADER => array(
    'Accept: application/json',
    'ApiKey:[API KEY HERE]',
    'Content-Type: application/json'
  ),
));

$response = curl_exec($curl);

curl_close($curl);
echo $response;

?>
var client = new RestClient("https://api.ozow.com/postpaymentrequest");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("ApiKey", "[API KEY HERE]");
request.AddHeader("Content-Type", "application/json");

var data = new
{
	countryCode = "ZA",
	amount = "0.01",
	transactionReference = "Test1",
	bankReference = "Test1",
	cancelUrl = "http://test.i-pay.co.za/responsetest.php",
	currencyCode = "ZAR",
	errorUrl = "http://test.i-pay.co.za/responsetest.php",
	isTest = false,
	notifyUrl = "http://test.i-pay.co.za/responsetest.php",
	siteCode = "[YOUR SITECODE]",
	successUrl = "http://test.i-pay.co.za/responsetest.php",
	hashCheck = "[GENERATED HASH]"
};

var json = JsonConvert.SerializeObject(data);
request.AddParameter("application/json", json, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
import json
import requests

url = "https://api.ozow.com/postpaymentrequest"

headers = {
	"Accept": "application/json",
	"ApiKey": "[API KEY HERE]",
	"Content-Type": "application/json"
	}
	
data = {
	"countryCode": "ZA",
	"amount": "0.01",
	"transactionReference": "Test1",
	"bankReference": "Test1",
	"cancelUrl": "http://test.i-pay.co.za/responsetest.php",
	"currencyCode": "ZAR",
	"errorUrl": "http://test.i-pay.co.za/responsetest.php",
	"isTest": False,
	"notifyUrl": "http://test.i-pay.co.za/responsetest.php",
	"siteCode": "[YOUR SITECODE]",
	"successUrl": "http://test.i-pay.co.za/responsetest.php",
	"hashCheck": "[GENERATED HASH]"
	}

response = requests.post(url, headers=headers, json=data)

print(response.text)
const data = {
	countryCode: "ZA",
	amount: "0.01",
	transactionReference: "Test1",
	bankReference: "Test1",
	cancelUrl: "http://test.i-pay.co.za/responsetest.php",
	currencyCode: "ZAR",
	errorUrl: "http://test.i-pay.co.za/responsetest.php",
	isTest: false,
	notifyUrl: "http://test.i-pay.co.za/responsetest.php",
	siteCode: "[YOUR SITECODE]",
	successUrl: "http://test.i-pay.co.za/responsetest.php",
	hashCheck: "[GENERATED HASH]"
};

const options = {
	method: 'POST',
	headers: {
	'Accept': 'application/json',
	'ApiKey': '[API KEY HERE]',
	'Content-Type': 'application/json',
	},
	body: JSON.stringify(data)
};

fetch('https://api.ozow.com/postpaymentrequest', options)
.then(response => response.text())
.then(data => console.log(data))
.catch(error => console.error(error));

Response

PaymentRequestResult - A successful call will return a PaymentRequestResult object. The PaymentRequestResult object is described below.

Property TypeDescription
PaymentRequestIdString (50)Ozow's unique identifier for the payment request.
URLString (50) Generated URL that allows payment for the posted variables used to create the payment request.

The payment Url you'll receive from the API is dynamic. Please do not hard code it into your integrations as it might change.
ErrorMessageString (50) Error message generated when validating the request

Sample response JSON

{
    "paymentRequestId": "00000000-0000-0000-0000-000000000000",
    "url": "https://pay.ozow.com/00000000-0000-0000-0000-000000000000/Secure",
    "errorMessage": null
}