Preface
About
This document contains detailed explanation about how to integrate with PayFast API’s Based transactions functionality. This document also contains the details for online transactions.
Intended Audience
This document is for merchants, acquirers and developers who want to integrate with PayFast to perform a API’s based Transactions.
Integration scope
The merchant will implement all ecommerce functionality. PayFast’ service (Payfast) will be used only for payment processing.
PayFast – Go Cashless!
PayFast is focused to bring merchants on ecommerce platforms by offering a complete suite of solutions to all types of merchants from building a website, online store, mobile application, social media marketing to securing payment. PayFast will enable merchants to sell the products and services online, and receive their payment safely.
Key Features
- Simple, secure and low risk
- Offers easy integration and a broad application suite
- Directly charge from the customer’s Bank account, Debit Card and Wallets
- Guaranteed prompt payment to Merchants
- Integrates easily with Mobile and web based application
- Connects to a variety of Merchant organizations including retail stores, governments, etc.
How Payfast Works
PayFast has developed a flagship payment gateway solution called “PayFast” which is targeted towards merchants, schools and other corporate entities to accept payments digitally from customers by using multiple options such as Debit Cards and Account Numbers. It will be integrated directly with the client’s website to allow smooth transaction placements.
API Based Transaction
All retail stores can integrate with Payfast direct API’s for over the counter payments without redirection. After the payment process is completed, the merchant will get an intimation of the transaction status.
Integration Prerequisites
Merchants will be registered on PayFast prior to integration. After merchant sign up for PayFast account, following two unique values will be provided to merchant to operate: * MERCHANT_ID * SECURED_KEY These keys are used to get a one-time authentication token, which is used to authenticate payment requests to the “Payfast” payment gateway.
Getting Authentication Token
To initiate the transaction, the merchant needs to generate the Authentication Token from PayFast server. For fetching, the token developer needs to call the Authentication token API.
Let’s start with Scenarios
Scenario 1
Consider a typical ecommerce transaction where a customer enters card/account details and tries to pay via PayFast. In this scenario, a temporary transaction token (refer to this section) should be fetched (which will last for short period) and then a tokenized transaction API (refer to this section) will be called to initiate a payment request based on temporary token. In this process, an OTP will be sent to customer mobile number. This token cannot be used for recurring transaction.
Scenario 2
Consider a scenario where a mobile app wants its customer card information for monthly subscription. This is recurring model, where customer will store its instrument such as card details or account details for later use. It is recommended for merchant to get a temporary transaction (refer to this section) token against the card details and perform a small amount of transaction (refer to this section) (which will be refunded) to validate instrument details, based on temporary token. Again, an OTP will be sent to customer and once transaction gets success, merchant will add instruments details and will get the permanent transaction token (refer to this section) which could be used later on for recurring transaction API (refer to this section) and no OTP will be sent to customer.
Scenario 3
Consider a situation where merchant do not want a token against card/account details and want to perform a transaction with the instrument details on the fly. In this case, a simple transaction API (refer to section API Transaction) will serve the purpose. In this process, merchant would call "validate" (refer to section API Customer Account Validation) API to get the OTP for customer and it will be sent with other transaction parameter.
API End Points
This section contains the details of all APIs provided by PayFast. These APIs could be called by the merchants, acquirers and/or aggregators. These API’S are based on REST architecture and serve standard HTTP codes for the response payload.
Get Access Token
Following API will provide you the Authentication token, which will be used to call APIs. Merchant_id and Secured_key is mandatory to get the access token. This token will be sent on all the APIs with standard HTTP header ‘Authorization’.
curl -X POST \
/token \
-H 'content-type: application/x-www-form-urlencoded' \
-d 'merchant_id=<MERCHANT_ID>&grant_type=client_credentials&secured_key=<KEY>'
var client = new RestClient("<BASE_URL>/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
var data = null;
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "<BASE_URL>/token");
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
xhr.setRequestHeader("cache-control", "no-cache");
xhr.send(data);
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_PORT => "8443",
CURLOPT_URL => "<BASE_URL>/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/x-www-form-urlencoded"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
The above command following JSON structure:
{
"token": "<token>",
"refresh_token": "<refresh token>",
"code": "",
"message": null,
"expiry": <no.ofseconds>
}
HTTP Request
POST /token
Post Parameters
Parameter | Required | Description |
---|---|---|
merchant_id | Yes | Merchant ID |
secured_key | Yes | Secured Key |
grant_type | Yes | Grant type ( client_credentials ) |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Refresh Access Token
Any access token can be refreshed upon expiry. A refresh token is given along with original token.
curl -X POST \
<BASE_URL>/refreshtoken \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded'
var client = new RestClient("<BASE_URL>/refreshtoken");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
var request = require("request");
var options = { method: 'POST',
url: '<BASE_URL>/refreshtoken',
headers:
{ 'postman-token': 'd3aa4037-7744-58b6-9557-0094116be350',
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded' },
form: {} };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_PORT => "8443",
CURLOPT_URL => "<BASE_URL>/refreshtoken",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/x-www-form-urlencoded"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
The above command returns JSON structured like this:
{
"token": "<token>",
"refresh_token": "<refresh token>",
"code": "",
"message": null,
"expiry": <no.ofseconds>
}
HTTP Request
POST /refreshtoken
HTTP Header
Authorization: Bearer <token>
Post Parameters
Parameter | Required | Description |
---|---|---|
refresh_token | Yes | Refresh token |
grant_type | Yes | Grant type ( refresh_token ) |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Issuer/Banks
This API will provide the available list of issuer/bank.
curl -X GET \
<BASE_URL>/list/banks \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded'
var client = new RestClient("<BASE_URL>/list/banks");
var request = new RestRequest(Method.GET);
request.AddHeader("postman-token", "c9dd8d8f-7b5b-13f1-bfb0-2cc97549cd44");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
var request = require("request");
var options = { method: 'GET',
url: '<BASE_URL>/list/banks',
headers:
{
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_PORT => "8443",
CURLOPT_URL => "<BASE_URL>/list/banks",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/x-www-form-urlencoded"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
The above command returns following JSON structure:
{
"banks": [
{
"bank_code": "xxxxxxxx",
"name": "xxxxxxxxxxxxx",
“recurring_allowed”: true/false,
“otp_required”: true/false
},
……..
]"code": null,
"message": null
}
HTTP Request
GET /list/banks
HTTP Header
Authorization: Bearer <access token>
Query Parameter
Parameter | Required | Description |
---|---|---|
reserved_1 | Conditional | Reserved Field 1 |
customer_ip | Yes | IP address of the end user |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
Payment (Instrument) Types
This API will provide the Payment type (or account type, e.g. Account, Wallet or Debit Card) based on selected issuer/bank.
curl -X GET \
'<BASE_URL>/list/instruments?bank_code=<bank code>' \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded'
var client = new RestClient("<BASE_URL>/list/instruments?
bank_code=<bank code>");
var request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
var request = require("request");
var options = { method: 'GET',
url: '<BASE_URL>/list/instruments',
qs: { bank_code: '<bank code>' },
headers:
{
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_PORT => "8443",
CURLOPT_URL => "<BASE_URL>/list/instruments?bank_code=<bank code>",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/x-www-form-urlencoded"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
The above command returns following JSON structure:
{
"bankInstruments": [
{
"id": "xxxx",
"name": "xxxxxxx"
},
],
"code": "00",
"message": null
}
HTTP Request
GET /list/instruments
HTTP Header
Authorization: Bearer <access token>
Query Parameter
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank Code |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Issuer/Banks By Issuer Instrument ID
This API will provide the available list of issuer/bank based on instrument id.
curl -X GET \
'<BASE_URL>/list/instrumentbanks?instrument_id=1' \
-H 'cache-control: no-cache' \
-H 'content-type: application/x-www-form-urlencoded'
var client = new RestClient("<BASE_URL>/list/instrumentbanks
?instrument_id=1");
var request = new RestRequest(Method.GET);
request.AddHeader("postman-token", "55665a44-4f7e-450b-e6fc-357293e65d6f");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
IRestResponse response = client.Execute(request);
var request = require("request");
var options = { method: 'GET',
url: '<BASE_URL>/list/instrumentbanks',
qs: { instrument_id: '1' },
headers:
{
'cache-control': 'no-cache',
'content-type': 'application/x-www-form-urlencoded' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_PORT => "8443",
CURLOPT_URL => "<BASE_URL>/list/instrumentbanks?instrument_id=1",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/x-www-form-urlencoded"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
The above command returns following JSON structure:
{
"banks": [
{
"bank_code": "xxxxxxxx",
"name": "xxxxxxxxxxxxx",
"recurring_allowed": true/false,
"otp_required": true/false
},
],
"code": null,
"message": null
}
HTTP Request
GET /list/instrumentbanks
HTTP Header
Authorization: Bearer <access token>
Query Parameter
Parameter | Required | Description |
---|---|---|
instrument_id | Yes | Instrument Id |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Customer Account Validation
This API will be used if you choose to send OTP to registered mobile number of the customer with that respective Issuer/Bank.
# Example using a bank account
curl --location --request POST '<BASE_URL>/customer/validate' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'txnamt=<total amount>' \
--data-urlencode 'customer_mobile_no=<mobile number>' \
--data-urlencode 'customer_email_address=<email address>' \
--data-urlencode 'account_type_id=3' \
--data-urlencode 'bank_code=<bank code>' \
--data-urlencode 'cnic_number=<cnic number>' \
--data-urlencode 'account_number=<bank account number>' \
--data-urlencode 'order_date=<transaction date>' \
--data-urlencode 'otp_required=yes/no' \
--data-urlencode 'recurring_txn=yes/no'
// Example using a bank account
var client = new RestClient("<BASE_URL>/customer/validate");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("customer_mobile_no", "<mobile>");
request.AddParameter("customer_email_address", "<email>");
request.AddParameter("account_type_id", "3");
request.AddParameter("bank_code", "<bank code>");
request.AddParameter("cnic_number", "<cnic number>");
request.AddParameter("account_number", "<bank account number>");
request.AddParameter("order_date", "<transaction date>");
request.AddParameter("otp_required", "yes/no");
request.AddParameter("recurring_txn", "no");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
// Example using a card number
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/customer/validate',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'basket_id': '<basket_id>',
'txnamt': '<total amount>',
'customer_mobile_no': '<mobile>',
'customer_email_address': '<email>',
'account_type_id': '2', // 2 for card base transaction
'bank_code': '<bank code>',
'card_number': '<card_number>'
'expiry_month': '<expiry_month>',
'expiry_year': '<expiry_year>',
'cvv': '<CVV>',
'order_date': '<transaction date>',
'otp_required': 'yes/no',
'recurring_txn': 'no/yes'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
// Example using a card
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/customer/validate",
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 => "basket_id=<basket_id>&txnamt=<total amount>"
."&customer_mobile_no=<mobile>&customer_email_address=<email>&account_type_id=2&"
."bank_code=<bank code>&card_number=<card number>&expiry_month=<expiry_month>"
."&expiry_year=<expiry_year>&cvv=<CVV>"
."&order_date=<transaction date>&otp_required=yes/no&recurring_txn=yes/no",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
The above command returns following JSON structure:
{
"code": "",
"message": "",
"data_3ds_acsurl": "",
"data_3ds_pareq": "",
"data_3ds_html": "",
"data_3ds_secureid": "",
"data_3ds_gatewayrecommendation": "",
"transaction_id": ""
}
HTTP Request
POST /customer/validate
HTTP Header
Authorization: Bearer <access token>
Post Parameter
Common Parameters
Parameter | Required | Description |
---|---|---|
basket_id | Yes | Merchant's Basket ID/Order ID/Cart ID/Reference ID |
txnamt | Yes | Transaction total amount |
order_date | Yes | Merchant's order date (format: YYYY-MM-DD HH:mm:ss) |
customer_mobile_no | Yes | Customer's mobile number (format: 92-345XXXXXX ) |
customer_email_address | Yes | Customer's email address |
account_type_id | Yes | Account type id / Payment instrument id |
merCatCode | Yes | Merchant category code |
subMerId | No | Sub merchant id (for Acquirer) |
customer_ip | Yes | IP address of the end user |
subMerName | No | Sub merchant name (for Acquirer) |
subMerAbbr | No | Sub merchant abbreviation (for Acquirer) |
secured_hash | Conditional | Secured hash value |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Card Payment Parameters: (UPI,Master,VISA and Paypak Cards)
Parameter | Required | Description |
---|---|---|
card_number | Yes | Card Number (without spaces/hyphens) |
expiry_month | Yes | Card Expiry Month (e.g. 09 for September) |
expiry_year | Yes | Card Expiry Year (e.g. 2021 ) |
cvv | Yes | CVV Value |
data_3ds_pagemode | For 3DS | Pagemode for 3DS auth. Required value SIMPLE |
data_3ds_callback_url | For 3DS | Merchant's call back URL for 3DS auth. |
(Refer to 3DS for 3DS verification process)
Bank Account Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
account_title | No | Account Title |
cnic_number | Yes | Customer's CNIC number registered with Bank |
Wallet Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
account_title | No | Account Title |
cnic_number | Yes | Customer's CNIC number registered with Bank |
Initiate Transaction
This API will initiate payment/transaction request without token.
# Example using bank account
curl --location --request POST '<BASE_URL>/transaction' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'txnamt=<total a amount>' \
--data-urlencode 'customer_email_address=<email>' \
--data-urlencode 'account_type_id=3' \
--data-urlencode 'customer_mobile_no=<mobile>' \
--data-urlencode 'account_number=<account number>' \
--data-urlencode 'cnic_number=<cnic number>' \
--data-urlencode 'account_title=<account title>' \
--data-urlencode 'bank_code=<bank code>' \
--data-urlencode 'order_date=<transaction dat3>' \
--data-urlencode 'otp_required=yes/no' \
--data-urlencode 'recurring_txn=yes/no' \
--data-urlencode 'otp=<OTP>' \
--data-urlencode 'transaction_id=<transaction_id>'
// Example using bank account
var client = new RestClient("<BASE_URL>/transaction");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("customer_email_address", "<email>");
request.AddParameter("account_type_id", "3");
request.AddParameter("customer_mobile_no", "<mobile>");
request.AddParameter("account_number", "<bank account number>");
request.AddParameter("cnic_number", "<cnic number>");
request.AddParameter("account_title", "<account title>");
request.AddParameter("bank_code", "<bank code>");
request.AddParameter("order_date", "<transaction date>");
request.AddParameter("otp_required", "yes/no");
request.AddParameter("recurring_txn", "yes/no");
request.AddParameter("otp", "<OTP>");
request.AddParameter("transaction_id", "<transaction_id>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
// Example using bank account
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/transaction',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'basket_id': '<basket_id>',
'txnamt': '<total amount>',
'customer_email_address': '<email>',
'account_type_id': '3',
'customer_mobile_no': '<mobile>',
'account_number': '<bank account_number>',
'cnic_number': '<cnic_number>',
'account_title': '<account_title>',
'bank_code': '<bank code>',
'order_date': '<transaction date>',
'otp_required': 'yes/no',
'recurring_txn': 'yes/no',
'otp': '<OTP>',
'transaction_id': '<transaction_id>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
# Example using bank account
$client = new http\Client;
$request = new http\Client\Request;
$request->setRequestUrl('<BASE_URL>/transaction');
$request->setRequestMethod('POST');
$body = new http\Message\Body;
$body->append(new http\QueryString(array(
'basket_id' => '<basket_id>',
'txnamt' => '<total amount>',
'customer_email_address' => '<email>',
'account_type_id' => '3',
'customer_mobile_no' => '<mobile>',
'account_number' => 'bank account_number',
'cnic_number' => '<cnic_number>',
'account_title' => '<account title>',
'bank_code' => '<bank code>',
'order_date' => '<transaction date>',
'otp_required' => 'yes/no',
'recurring_txn' => 'yes/no',
'otp' => '<OTP>',
'transaction_id' => '')));$request->setBody($body);
$request->setOptions(array());
$request->setHeaders(array(
'Content-Type' => 'application/x-www-form-urlencoded',
'Authorization' => 'Bearer <access token>'
));
$client->enqueue($request)->send();
$response = $client->getResponse();
echo $response->getBody();
HTTP Request
`POST /transaction
HTTP Header
Authorization: Bearer <access token>
The above command returns following JSON structure:
{
"status_code": "",
"status_msg": "",
"rdv_message_key": "",
"basket_id": "",
"transaction_id": "<transaction id>",
"code": ""
}
Common Parameters
Parameter | Required | Description |
---|---|---|
basket_id | Yes | Merchant's Basket ID/Order ID/Cart ID/Reference ID |
txnamt | Yes | Transaction total amount |
order_date | Yes | Merchant's order date (format: YYYY-MM-DD HH:mm:ss) |
customer_mobile_no | Yes | Customer's mobile number (format: 92-345XXXXXX ) |
customer_email_address | Yes | Customer's email address |
account_type_id | Yes | Account type id / Payment instrument id |
merCatCode | Yes | Merchant category code |
customer_ip | Yes | IP address of the end user |
customer_ip | Yes | IP address of the end user |
subMerId | No | Sub merchant id (for Acquirer) |
subMerName | No | Sub merchant name (for Acquirer) |
subMerAbbr | No | Sub merchant abbreviation (for Acquirer) |
secured_hash | Conditional | Secured hash value |
otp | Conditional | Not required when issuer managed OTP |
transaction_id | Yes | received from customer validation response |
eci | Yes | Received from customer validation response |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Card Payment Parameters: (UPI,Master,VISA and Paypak Cards)
Parameter | Required | Description |
---|---|---|
card_number | Yes | Card Number (without spaces/hyphens) |
expiry_month | Yes | Card Expiry Month (e.g. 09 for September) |
expiry_year | Yes | Card Expiry Year (e.g. 2021 ) |
cvv | Yes | CVV Value |
data_3ds_pagemode | For 3DS | Pagemode for 3DS auth. Required value SIMPLE |
data_3ds_callback_url | For 3DS | Merchant's call back URL for 3DS auth. |
(Refer to 3DS for 3DS verification process)
Bank Account Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
cnic_number | Yes | Customer's CNIC number registered with Bank |
account_title | No | Account's title |
Wallet Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
cnic_number | Yes | Customer's CNIC number registered with Bank |
account_title | No | Account's title |
Temporary Transaction Token
Get a temporary payment request token, against card, wallet or account details. This token can be used to send a tokenized transaction.
curl --location --request POST '<BASE_URL>/transaction/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'merchant_user_id=<merchant's user id>' \
--data-urlencode 'user_mobile_number=<user mobile number>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'txnamt=<total amount>' \
--data-urlencode 'account_type=4' \
--data-urlencode 'bank_code=<bank code>' \
--data-urlencode 'cnic_number=<cnic_number>' \
--data-urlencode 'account_number=<account_number>' \
--data-urlencode 'account_title=<account title>'
var client = new RestClient("<BASE_URL>/transaction/token");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("merchant_user_id", "<merchant's user id>");
request.AddParameter("user_mobile_number", "<user mobile number>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("account_type", "4");
request.AddParameter("bank_code", "<bank code>");
request.AddParameter("cnic_number", "<cnic_number>");
request.AddParameter("account_number", "<account_number>");
request.AddParameter("account_title", "<account title>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/transaction/token',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'merchant_user_id': '<merchant's user id>',
'user_mobile_number': '<user mobile number>',
'basket_id': '<basket_id>',
'txnamt': '<total amount>',
'account_type': '4',
'bank_code': '<bank code>',
'cnic_number': '<cnic_number>',
'account_number': '<account_number>',
'account_title': '<account title>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/transaction/token",
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 => "merchant_user_id=<merchant's user id>&user_mobile_number=<user mobile number>&basket_id=<basket_id>&txnamt=<total amount>&account_type=4&bank_code=<bank code>&cnic_number=<cnic_number>&account_number=<account_number>&account_title=<account_title>",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
HTTP Request
POST /transaction/token
HTTP Header
Authorization: Bearer <access token>
The above command returns following JSON structure:
{
"status_code": "*****",
"status_msg": "*******",
"instrument_alias": "**********",
"instrument_token": "********",
"transaction_id": "<transaction id>",
"otp_required": true/false,
"eci": true/false,
"data_3ds_acsurl": <3DSVerificationURL>,
"data_3ds_pareq": <3DSRequestValue>,
"data_3ds_html": <3DSRedirectionHTMLPage>,
"data_3ds_secureid": <3DSecureID>,
"data_3ds_gatewayrecommendation": <3DSRecommendation>
}
Common Parameters
Parameter | Required | Description |
---|---|---|
basket_id | Yes | Merchant's Basket ID/Order ID/Cart ID/Reference ID |
txnamt | Yes | Transaction total amount |
order_date | Yes | Merchant's order date (format: YYYY-MM-DD HH:mm:ss) |
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
instrument_alias | No | Instrument alias |
account_type | Yes | Account type id/instrument type id |
secured_hash | Conditional | Secured hash value |
customer_ip | Yes | IP address of the end user |
merCatCode | Yes | Merchant category code |
subMerId | No | Sub merchant id (for Acquirer) |
subMerName | No | Sub merchant name (for Acquirer) |
subMerAbbr | No | Sub merchant abbreviation (for Acquirer) |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version (optional) |
Card Payment Parameters: (UPI,Master,VISA and Paypak Cards)
Parameter | Required | Description |
---|---|---|
card_number | Yes | Card Number (without spaces/hyphens) |
expiry_month | Yes | Card Expiry Month (e.g. 09 for September) |
expiry_year | Yes | Card Expiry Year (e.g. 2021 ) |
cvv | Yes | CVV Value |
data_3ds_pagemode | For 3DS | Pagemode for 3DS auth. Required value SIMPLE |
data_3ds_callback_url | For 3DS | Merchant's call back URL for 3DS auth. |
Bank Account Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
cnic_number | Yes | Customer's CNIC number registered with Bank |
account_title | No | Account's title |
Wallet Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
cnic_number | Yes | Customer's CNIC number registered with Bank |
account_title | No | Account's title |
Tokenized Transaction
Initiate a payment request based on “temporary” transaction token.
curl --location --request POST '<BASE_URL>/transaction/tokenized' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'instrument_token=<instrument token>' \
--data-urlencode 'transaction_id=<transaction_id>' \
--data-urlencode 'merchant_user_id=<merchant's user id>' \
--data-urlencode 'user_mobile_number=<user mobile number>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'order_date=<transaction date>' \
--data-urlencode 'txndesc=<description>' \
--data-urlencode 'txnamt=<total amount>' \
--data-urlencode 'otp=<OTP>'
var client = new RestClient("<BASE_URL>/transaction/tokenized");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("instrument_token", "<instrument token>");
request.AddParameter("transaction_id", "<transaction_id>");
request.AddParameter("merchant_user_id", "<merchant's user id>");
request.AddParameter("user_mobile_number", "<user mobile number>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("order_date", "<transaction date>");
request.AddParameter("txndesc", "<description>");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("otp", "<OTP>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/transaction/tokenized',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'instrument_token': '<instrument token>',
'transaction_id': '<transaction_id>',
'merchant_user_id': '<merchant's user id>',
'user_mobile_number': '<user mobile number>',
'basket_id': '<basket_id>',
'order_date': '<transaction date>',
'txndesc': '<description>',
'txnamt': '<total amount>',
'otp': '<OTP>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/transaction/tokenized",
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 => "instrument_token=<instrument token>&transaction_id=<transaction date>&merchant_user_id=<merchant's user id>&user_mobile_number=<user mobile number>&basket_id=<basket_id>&order_date=<transaction date>&txndesc=<description>&txnamt=<total amount>&otp=<OTP>",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
HTTP Request
POST /transaction/tokenized
HTTP Header
Authorization: Bearer <access token>
The above command returns following JSON structure:
{
"status_code": "",
"status_msg": "",
"rdv_message_key": "",
"basket_id": "",
"transaction_id": "<transaction id>",
"code": ""
}
Parameter | Required | Description |
---|---|---|
instrument_token | Yes | Instrument token |
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
basket_id | Yes | Merchant's Basket ID/Order ID/Cart ID/Reference ID |
txnamt | Yes | Transaction total amount |
order_date | Yes | Merchant's order date (format: YYYY-MM-DD HH:mm:ss) |
txndesc | Yes | Transaction description |
otp | Conditional | Not required when issuer managed OTP |
transaction_id | Yes | Received from get transaction token API |
eci | Yes | Received from customer validation response |
customer_ip | Yes | IP address of the end user | merCatCode | Yes | Merchant category code |
subMerId | No | Sub merchant id (for Acquirer) |
subMerName | No | Sub merchant name (for Acquirer) |
subMerAbbr | No | Sub merchant abbreviation (for Acquirer) |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
data_3ds_secureid | 3DS | required-3DS Only |
data_3ds_pares | 3DS | required-3DS Only |
secured_hash | Conditional | Secured hash |
Add Permanent Payment Instrument
This API will allow merchants to add permanent payment instrument on PayFast. A token value will be returned to initiate the transaction for this instrument. (Currently this API is not available due to some bank/scheme level constrains).
curl --location --request POST '<BASE_URL>/user/instruments' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'merchant_user_id=<merchant's user id>' \
--data-urlencode 'user_mobile_number=<user mobile number>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'txnamt=<total amount>' \
--data-urlencode 'account_type=4' \
--data-urlencode 'bank_code=<bank code>' \
--data-urlencode 'cnic_number=<cnic_number>' \
--data-urlencode 'account_number=<account_number>' \
--data-urlencode 'account_title=<account title>'
var client = new RestClient("<BASE_URL>/user/instruments");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("merchant_user_id", "<merchant's user id>");
request.AddParameter("user_mobile_number", "<user mobile number>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("account_type", "4");
request.AddParameter("bank_code", "<bank code>");
request.AddParameter("cnic_number", "<cnic_number>");
request.AddParameter("account_number", "<account_number>");
request.AddParameter("account_title", "<account title>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/user/instruments',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'merchant_user_id': '<merchant's user id>',
'user_mobile_number': '<user mobile number>',
'basket_id': '<basket_id>',
'txnamt': '<total amount>',
'account_type': '4',
'bank_code': '<bank code>',
'cnic_number': '<cnic_number>',
'account_number': '<account_number>',
'account_title': '<account title>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/user/instruments",
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 => "merchant_user_id=<merchant's user id>&user_mobile_number=<user mobile number>&basket_id=<basket_id>&txnamt=<total amount>&account_type=4&bank_code=<bank code>&cnic_number=<cnic_number>&account_number=<account_number>&account_title=<account_title>",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
HTTP Request
POST /user/instruments
HTTP Header
Authorization: Bearer <access token>
The above command returns following JSON structure:
{
"status_code": "*****",
"status_msg": "*******",
"instrument_alias": "**********",
"instrument_token": "********"
}
Parameter | Required | Description |
---|---|---|
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
instrument_alias | No | Instrument alias |
account_type | Yes | Account type id/Payment type id |
transaction_id | Yes | Last successfull transaction id |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
merCatCode | Yes | Merchant category code |
subMerId | No | Sub merchant id (for Acquirer) |
subMerName | No | Sub merchant name (for Acquirer) |
subMerAbbr | No | Sub merchant abbreviation (for Acquirer) |
data_3ds_secureid | 3DS | required-3DS Only |
secured_hash | Conditional | Secured hash value |
Card Payment Parameters: (UPI,Master,VISA and Paypak Cards)
Parameter | Required | Description |
---|---|---|
card_number | Yes | Card Number (without spaces/hyphens) |
expiry_month | Yes | Card Expiry Month (e.g. 09 for September) |
expiry_year | Yes | Card Expiry Year (e.g. 2021 ) |
cvv | Yes | CVV Value |
Bank Account Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
cnic_number | Yes | Customer's CNIC number registered with Bank |
account_title | No | Account's title |
Wallet Payment Parameters
Parameter | Required | Description |
---|---|---|
bank_code | Yes | Bank code |
account_number | Yes | Bank account number |
cnic_number | Yes | Customer's CNIC number registered with Bank |
account_title | No | Account's title |
OTP for Recurring Transaction
This API will generate an OTP and send to customer, which could be used for sending recurring transaction. OTP will be sent by the bank to customer's mobile number registered with the bank account.
curl --location --request POST '<BASE_URL>/transaction/recurring/otp' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'instrument_token=<instrument token>' \
--data-urlencode 'merchant_user_id=<merchant's user id>' \
--data-urlencode 'user_mobile_number=<mobile>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'txnamt=<Total amount>' \
--data-urlencode 'order_date=<transaction date>'
var client = new RestClient("<BASE_URL>/transaction/recurring/otp");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("instrument_token", "<instrument token>");
request.AddParameter("merchant_user_id", "<merchant's user id>");
request.AddParameter("user_mobile_number", "<mobile>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("txnamt", "<Total amount>");
request.AddParameter("order_date", "<Transaction date>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/transaction/recurring/otp',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer a68adea0cc508db888625bd9a4b9d850521219df68cbf33926c4bbff8c50c00f'
},
form: {
'instrument_token': '<instrument token>',
'merchant_user_id': '<merchant's user id>',
'user_mobile_number': '<mobile>',
'basket_id': '<basket_id>',
'txnamt': '<Total amount>',
'order_date': '<Transaction date>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/transaction/recurring/otp",
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 => "instrument_token=<instrument token>&merchant_user_id=<merchant's user id>&user_mobile_number=<mobile>&basket_id=<basket_id>&txnamt=<Total amount>&order_date=<Transaction date>",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
{
"status_code": "",
"status_msg": "",
"rdv_message_key": "",
"basket_id": "",
"transaction_id": "<transaction id>",
"code": "",
“eci”: true/false,
"data_3ds_acsurl": <3DSVerificationURL>,
"data_3ds_pareq": <3DSRequestValue>,
"data_3ds_html": <3DSRedirectionHTMLPage>,
"data_3ds_secureid": <3DSecureID>,
"data_3ds_gatewayrecommendation": <3DSRecommendation>
}
HTTP Request
POST /transaction/recurring/otp
HTTP Header
Authorization: Bearer <access token>
Parameter | Required | Description |
---|---|---|
instrument_token | Yes | Instrument token |
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
basket_id | Yes | Merchant's Basket ID/Order ID/Cart ID/Reference ID |
customer_ip | Yes | IP address of the end user |
cvv | Yes | CVV (for “visa/master card” based transaction) |
txnamt | Yes | Transaction total amount |
order_date | Yes | Merchant's order date (format: YYYY-MM-DD HH:mm:ss) |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
secured_hash | Conditional | Secured hash |
Initiate Recurring Transaction
Initiate payment transaction based on permanent token. This API will serve recurring payment requests. (Currently this API is not available due to some bank/scheme level constrains).
curl --location --request POST '<BASE_URL>/transaction/recurring' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'instrument_token=<instrument token>' \
--data-urlencode 'transaction_id=<transaction_id>' \
--data-urlencode 'merchant_user_id=<merchant's user id>' \
--data-urlencode 'user_mobile_number=<user mobile number>' \
--data-urlencode 'basket_id=<basket_id>' \
--data-urlencode 'order_date=<transaction date>' \
--data-urlencode 'txndesc=<description>' \
--data-urlencode 'txnamt=<total amount>' \
--data-urlencode 'otp=<OTP>'
var client = new RestClient("<BASE_URL>/transaction/recurring");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("instrument_token", "<instrument token>");
request.AddParameter("transaction_id", "<transaction_id>");
request.AddParameter("merchant_user_id", "<merchant's user id>");
request.AddParameter("user_mobile_number", "<user mobile number>");
request.AddParameter("basket_id", "<basket_id>");
request.AddParameter("order_date", "<transaction date>");
request.AddParameter("txndesc", "<description>");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("otp", "<OTP>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/transaction/recurring',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'instrument_token': '<instrument token>',
'transaction_id': '<transaction_id>',
'merchant_user_id': '<merchant's user id>',
'user_mobile_number': '<user mobile number>',
'basket_id': '<basket_id>',
'order_date': '<transaction date>',
'txndesc': '<description>',
'txnamt': '<total amount>',
'otp': '<OTP>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/transaction/recurring",
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 => "instrument_token=<instrument token>&transaction_id=<transaction date>&merchant_user_id=<merchant's user id>&user_mobile_number=<user mobile number>&basket_id=<basket_id>&order_date=<transaction date>&txndesc=<description>&txnamt=<total amount>&otp=<OTP>",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
HTTP Request
POST /transaction/recurring
HTTP Header
Authorization: Bearer <access token>
The above command returns following JSON structure:
{
"status_code": "",
"status_msg": "",
"rdv_message_key": "",
"basket_id": "",
"transaction_id": "<transaction id>",
"code": ""
}
Parameter | Required | Description |
---|---|---|
instrument_token | Yes | Instrument token |
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
basket_id | Yes | Merchant's Basket ID/Order ID/Cart ID/Reference ID |
cvv | Yes | cvv (for “visa/master card” based transaction) (string) |
txnamt | Yes | Transaction total amount |
order_date | Yes | Merchant's order date (format: YYYY-MM-DD HH:mm:ss) |
txndesc | Yes | Transaction description |
otp | Conditional | Not required when issuer managed OTP |
transaction_id | Yes | Received from get transaction token API |
eci | Yes | Received from customer validation response |
customer_ip | Yes | IP address of the end user |
merCatCode | Yes | Merchant category code |
subMerId | No | Sub merchant id (for Acquirer) |
subMerName | No | Sub merchant name (for Acquirer) |
subMerAbbr | No | Sub merchant abbreviation (for Acquirer) |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
data_3ds_secureid | 3DS | required-3DS Only |
data_3ds_pares | 3DS | required-3DS Only |
secured_hash | Conditional | Secured hash |
Fetch Permanent Instrument Token
This API will fetch a list of stored permanent instrument tokens against provided merchant's users information. (Currently this API is not available due to some bank/scheme level constrains).
var client = new RestClient("<BASE_URL>/user/instruments?merchant_user_id=<merchant's user id>
&user_mobile_number=<user mobile number>");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var client = new RestClient("<BASE_URL>/user/instruments?merchant_user_id=<merchant's user id>&
user_mobile_number=<user mobile number>");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'GET',
'url': '<BASE_URL>/user/instruments?merchant_user_id=<merchant's user id>
&user_mobile_number=<user mobile number>',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/user/instruments?merchant_user_id=<merchant's user id>&user_mobile_number=<user mobile number>",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
HTTP Request
GET /user/instruments
HTTP Header
Authorization: Bearer <access token>
[
{
"instrument_token": "**********",
"account_type": "*",
"description": "***",
"instrument_alias": "**********"
}
]
Parameter | Required | Description |
---|---|---|
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
secured_hash | Conditional | Secured hash |
Delete Instrument
This API will allow merchants to delete stored permanent instrument tokens.
curl --location --request DELETE '<BASE_URL>/user/instruments' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>' \
--data-urlencode 'merchant_user_id=<merchant user id>' \
--data-urlencode 'user_mobile_number=<user mobile number>' \
--data-urlencode 'instrument_alias=<instrument alias>' \
--data-urlencode 'instrument_token=<instrument_token>'
var client = new RestClient("<BASE_URL>/user/instruments");
client.Timeout = -1;
var request = new RestRequest(Method.DELETE);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
request.AddParameter("merchant_user_id", "<merchant user id>");
request.AddParameter("user_mobile_number", "<user mobile number>");
request.AddParameter("instrument_alias", "<instrument alias>");
request.AddParameter("instrument_token", "<instrument_token>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'DELETE',
'url': '<BASE_URL>/user/instruments',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer <access token>'
},
form: {
'merchant_user_id': '<merchant user id>',
'user_mobile_number': '<user mobile number>',
'instrument_alias': '<instrument alias>',
'instrument_token': '<instrument_token>'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/user/instruments",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_POSTFIELDS => "merchant_user_id=<merchant user id>&user_mobile_number=<user mobile number>&instrument_alias=<instrument alias>&instrument_token=<instrument_token>",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
The above command returns following JSON structure:
{
"code": Error/SuccessCode,
"message": ResponseMessage,
}
HTTP Request
DELETE /user/instruments
HTTP Header
Authorization: Bearer <access token>
Parameter | Required | Description |
---|---|---|
merchant_user_id | Yes | Merchant's customer/user id |
user_mobile_number | Yes | Merchant's customer/user id |
instrument_token | Yes | Instrument token |
instrument_alias | No | Instrument alias |
customer_ip | Yes | IP address of the end user |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
secured_hash | Conditional | Secured hash |
Refund Transaction Request
This API will allow merchant to initiate the request for transaction refund in case of any dispute in the transaction.
curl --location --request POST '<BASE_URL>/transaction/refund/<transaction_id>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer a68adea0cc508db888625bd9a4b9d850521219df68cbf33926c4bbff8c50c00f' \
--data-urlencode 'txnamt=<total amount>' \
--data-urlencode 'refund_reason=Refund'
var client = new RestClient("<BASE_URL>/transaction/refund/<transaction_id>");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer a68adea0cc508db888625bd9a4b9d850521219df68cbf33926c4bbff8c50c00f");
request.AddParameter("txnamt", "<total amount>");
request.AddParameter("refund_reason", "Refund");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
var request = require('request');
var options = {
'method': 'POST',
'url': '<BASE_URL>/transaction/refund/<transaction_id>',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer a68adea0cc508db888625bd9a4b9d850521219df68cbf33926c4bbff8c50c00f'
},
form: {
'txnamt': '<total amount>',
'refund_reason': 'Refund'
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/transaction/refund/<transaction_id>",
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 => "&txnamt=<total amount>&refund_reason=Refund",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer a68adea0cc508db888625bd9a4b9d850521219df68cbf33926c4bbff8c50c00f"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
HTTP Request
POST /transaction/refund/<transaction_id>
HTTP Header
Authorization: Bearer <access token>
The above command returns following JSON structure:
{
"code": Error/SuccessCode,
"message": ResponseMessage,
}
Parameter | Required | Description |
---|---|---|
transaction_id | Yes | Successfull transaction id to be refunded |
txnamt | Yes | Original transaction amount |
customer_ip | Yes | IP address of the end user |
refund_reason | Yes | Reason of refund |
reserved_1 | Conditional | Reserved Field 1 |
reserved_2 | Conditional | Reserved Field 2 |
reserved_3 | Conditional | Reserved Field 3 |
api_version | No | API Version |
Get Transaction Status
This API will provide transaction status with respect to the transaction id or the merchant's provided basket id/order id.
// Example code for getting transaction status
// using transaction id
curl --location --request GET '<BASE_URL>/transaction/<transaction_id>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Bearer <access token>'
// Example code for getting transaction status
// using transaction id
var client = new RestClient("<BASE_URL>/transaction/<transaction_id>");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Bearer <access token>");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
// Example code for getting transaction status
// using merchant's provided basket id
var request = require('request');
var options = {
'method': 'GET',
'url': '<BASE_URL>/transaction/basket_id/<basket id>?order_date=<order/transaction date>',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
formData: {
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
<?php
// Example code for getting transaction status
// using transaction id
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "<BASE_URL>/transaction/<transaction_id>",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/x-www-form-urlencoded",
"Authorization: Bearer <access token>"
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
The above command returns following JSON structure:
{
"status_code": "",
"status_msg": "",
"rdv_message_key": "",
"basket_id": "",
"transaction_id": "<transaction id>",
"code": ""
}
HTTP Request
Transaction status by transaction id
GET /transaction/<transaction_id>
HTTP Header
Authorization: Bearer <access token>
Parameter | Required | Description |
---|---|---|
api_version | No | API Version |
Transaction status by basket id/order id (last)
GET /transaction/basket_id/<basket_id>
HTTP Header
Authorization: Bearer <access token>
Parameter | Required | Description |
---|---|---|
order_date | Yes | Transaction/Order Date |
customer_ip | Yes | IP address of the end user |
api_version | No | API Version |
HTTP Header
Authorization: Bearer <access token>
Error Codes
CODES | DESCRIPTION |
---|---|
00 | Processed OK |
002 | Time Out |
001 | Pending |
97 | Dear Customer, you have an insufficient Balance to proceed |
106 | Dear Customer, Your transaction Limit has been exceeded please contact your bank |
3 | You have entered an Inactive Account |
14 | Entered details are Incorrect |
55 | You have entered an Invalid OTP/PIN |
54 | Card Expired |
13 | You have entered an Invalid Amount |
126 | Dear Customer your provided Account details are Invalid |
75 | Maximum PIN Retries has been Exceeded |
14 | Dear Customer, You have entered an In-Active Card number |
15 | Dear Customer, You have entered an In-Active Card number |
42 | Dear Customer, You have entered an Invalid CNIC |
423 | Dear Customer, We are unable to process your request at the moment please try again later |
41 | Dear Customer, entered details are Mismatched |
801 | {0} is your PayFast OTP (One Time Password). Please do not share with anyone. |
802 | OTP could not be sent. Please try again later. |
803 | OTP has been sent to your email address. |
804 | OTP has been sent to your mobile number. |
805 | OTP Verified |
806 | OTP could not be verified. |
807 | Too many attempts. Please try again later in few minutes. |
808 | Passwords do not match |
809 | Invalid Password |
810 | Password could not be changed |
811 | Password changed successfully |
812 | Request could not be validated. Please try again. |
813 | Email address already registered |
850 | OTP not required because issuer manages OTP itself. |
851 | OTP required for permanent token. |
79 | Alternate Success response |
9000 | Rejected by FRMS |
Hashed Parameters
API Reference | Parameters to be Hashed | Data |
---|---|---|
Temp. Token For Transaction | merchant_user_id | For Card :- merchant_user_id+ user_mobile_number+card_number+ expiry_month+expiry_year+cvv |
user_mobile_number | For Account :- merchant_user_id+ user_mobile_number+account_number+ cnic_number | |
Card | card_number | |
expiry_month | For Wallet: - merchant_user_id+ user_mobile_number+account_number+ cnic_number | |
expiry_year | ||
cvv | ||
Account | account_number | |
cnic_number | ||
Wallet | account_number | |
cnic_number | ||
Temp. Token Transaction | instrument_token | instrument_token + merchant_user_id + user_mobile_number + txnamt + otp |
merchant_user_id | ||
user_mobile_number | ||
txnamt | ||
otp | ||
OTP for Recurring Transaction | instrument_token | instrument_token + merchant_user_id + user_mobile_number |
merchant_user_id | ||
user_mobile_number | ||
Initiate Recurring Transaction | instrument_token | instrument_token + merchant_user_id + user_mobile_number + txnamt + basket_id |
merchant_user_id | [+ otp] | |
user_mobile_number | ||
txnamt | ||
basket_id | ||
otp (if applicable) | ||
Customer Account Validation | ||
Common | basket_id | |
txnamt | ||
Card | card_number | basket_id + txnamt + card_number+ expiry_month+expiry_year+cvv |
expiry_month | ||
expiry_year | basket_id + txnamt + account_number + cnic_number | |
cvv | ||
Account | account_number | basket_id + txnamt + account_number + cnic_number |
cnic_number | ||
Wallet | account_number | |
cnic_number | ||
Inititate Transaction without Token | ||
Common | basket_id | |
txnamt | ||
otp | ||
Card | card_number | basket_id + txnamt + card_number+ expiry_month+expiry_year+cvv+otp |
expiry_month | ||
expiry_year | basket_id + txnamt + account_number + cnic_number+otp | |
cvv | ||
Account | account_number | basket_id + txnamt + account_number + cnic_number+otp |
cnic_number | ||
Wallet | account_number | |
cnic_number | ||
txnamt | ||
otp | ||
Add Permanent Instrument | ||
merchant_user_id | merchant_user_id+ user_mobile_number+card_number+ expiry_month+expiry_year+cvv | |
user_mobile_number | merchant_user_id+ user_mobile_number+account_number+ cnic_number | |
Card | card_number | |
expiry_month | merchant_user_id+ user_mobile_number+account_number+ cnic_number | |
expiry_year | ||
cvv | ||
Account | account_number | |
cnic_number | ||
Wallet | account_number | |
cnic_number | ||
Fetch Permanent Instruments | ||
merchant_user_id | merchant_user_id+ user_mobile_number | |
user_mobile_number | ||
Delete Stored Instrument | ||
merchant_user_id | merchant_user_id + user_mobile_number + instrument_token | |
user_mobile_number | ||
instrument_token |
Note:
“+” symbol denotes simple string concatenation.
Hashed data will be received in “secured_hash” parameter in designated APIs
A key will be provided separately for the hash calculation.
- Hash Method: HMAC (Keyed Hash)
- Hash Algorithm: sha256
- Hash Key: ASCII encoded string |
3D Secure Transaction
In case of Visa/Master card transaction, 3DS verification will be performed.
A. APIs Customer Account Validation, Get Temp. Transaction Token, OTP for Recurring Transaction, will accept an additional parameter data_3ds_pagemode
, it has 1 value: SIMPLE
.
i. In SIMPLE
case, data_3ds_html
, will contain a pre-formatted html page which can be used directly to redirect customer to verify OTP. You are not required to modify this value in any case. Any modification in this valaue may lead to unexpected results.
B. APIs Initiate Transaction without Token, Temp. Token Transaction, Initiate Recurring Transaction, will accept 2 more additional parameters for 3DS verification:
i. data_3ds_secureid
: This will be returned in response of APIs Customer Account Validation, Get Temp. Transaction Token, OTP for Recurring Transaction (Customer Validation).
ii. data_3ds_pares
: This value will be returned in call back URL which is called after 3DS verification, the parameter is returned paRes
.