NAV Navbar
PHP JSON HTML

Web Integration

Getting Started

How it Works

All that is required for a once-off payment, or to setup a recurring payment (subscription or ad hoc), is an html form with the necessary variables (described in the checkout page) sent to PayFast. PayFast will then process the transaction, update the merchants account, and send a payment confirmation (ITN) to the notify URL. The return variables of the payment confirmation can then be used to update your system accordingly.

getting_started

There are two methods available for integrating with PayFast, ITN, which is our preferred integration method and PDT, a method that we are deprecating, and will no longer support after 2017-12-31. The main difference, besides better security in ITN, is that with ITN our server contacts your website and notifies you of the payment, whereas with PDT you are required to contact and confirm with us.

The following is a list of pages that are generally needed on your website or application:

NAME DESCRIPTION
Checkout page Buyer clicks a button to confirm their order and is redirected to PayFast for payment
Success page Page on your site which the buyer sees after successful payment
Cancelled page Page on your site which the buyer sees after payment is cancelled on PayFast
Notify page Callback page which does all the ‘heavy lifting’ with regards to updating your database with payment information etc

Checkout Page

This page will have an HTML form, usually hidden, with a number of fields containing all the necessary information needed for PayFast to process the payment. Most shopping cart systems will have the buyer click on a ‘Confirm Order’ or ‘Pay Now’ button to submit the form and be redirected to the PayFast Payment page.

Success Page ‘return_url’

This page on your site is where the buyer is redirected to, from PayFast, after a successful payment. A plain HTML page thanking the buyer for their purchase (and maybe mentioning the delivery procedure) is usually the norm. The page is specified by the return_url variable in the HTML form on the Checkout Page. If you are using the PDT method to update your custom integration this page would handle any required functionality.

Cancelled Page ‘cancel_url’

This page (on your site) is where the buyer is redirected from PayFast if they cancel their payment. Good practice is to set this to a page which will allow the buyer to try and purchase again. Our recommendation is that you return the buyer to the Checkout Page. This page is specified by the cancel_url variable as defined in the HTML form on the Checkout Page.

Notify Page ‘notify_url’

This page would do all the ‘work’ which is required (e.g. updating the order in your database), when using our ITN method. This page is ‘called’ by our server directly after a successful payment and before the user is redirected to the Success Page. If there are any communication problems, or errors, our server will try again (up to eight more times).

Possible Sequence of events

Below is a sequence of events for a successful and unsuccessful (cancelled) payment on PayFast assuming the use of the above integration process and using the ITN method.

Successful Payment

  1. Variables POSTed to PayFast from merchant website.
  2. Payment collected from customer through payment engine, and the ITN is posted to the notify_url
  3. ITN process completes
  4. Customer displayed success screen on PayFast
  5. Customer redirected to return_url on merchant website
  6. If first ITN was unsuccessful (eg. due to merchant server outage), ITN is attempted again after 5 minutes, up to 4 consecutive times

Cancelled Payment

  1. Variables POSTed to PayFast from merchant
  2. Buyer cancels payment on PayFast during any step
  3. Customer displayed unsuccessful screen on PayFast
  4. Customer redirected to cancel_url on merchant’s site

Variable format

The below table describes the formats of the variables used when integrating with PayFast.

Format Description
alphanumeric A-Z, a-z, 0-9
alphanumericextended alphanumeric and special characters _-/
char maximum number of characters
decimal numeric and optional decimal point .
email valid email address
numeric numeric digits, 0-9
url/alphanumericspecial alphanumeric and special characters _-/:&?#=+
MD5 hash 32 character hexadecimal number.

Checkout Page

The checkout or confirm page is usually the last step before the buyer will enter their payment details, allowing the buyer to review their order before paying for it.

From the checkout page, all the necessary fields (variables) that PayFast requires to process a payment will be ‘POSTed’ to PayFast. These fields are explained in the tables below.

There are 4 required variables for all types of integrations, with further variables required for recurring payments. The other variables are either highly recommended, or optional.

Take note of the variables that only allow specific characters and those that have a restricted character length, as well as the order that the variables are submitted in.

Variables to be submitted

Merchant Details

<form action="https://sandbox.payfast.co.za/eng/process" method="POST">

<input type="hidden" name="merchant_id" value="10000100">
<input type="hidden" name="merchant_key" value="46f0cd694581a">
<input type="hidden" name="return_url" value="https://www.yoursite.com/return">
<input type="hidden" name="cancel_url" value="https://www.yoursite.com/cancel">
<input type="hidden" name="notify_url" value="https://www.yoursite.com/notify">
NAME DESCRIPTION REQUIRED FORMAT
merchant_id The Merchant ID as given by the PayFast system. Used to uniquely identify the receiving account.
This can be found on the merchant’s settings page.
Yes numeric
merchant_key The Merchant Key as given by the PayFast system. Used to uniquely identify the receiving account. This provides an extra level of certainty concerning the correct account as both the ID and the Key must be correct in order for the transaction to proceed.
This can be found on the merchant’s settings page.
Yes alphanumeric
return_url The URL where the user is returned to after payment has been successfully taken. Optional url
cancel_url The URL where the user should be redirected should they choose to cancel their payment while on the PayFast system. Optional url
notify_url The URL which is used by PayFast to post the Instant Transaction Notifications (ITNs) for this transaction. Optional url

Buyer Details

While these fields are optional, it is highly recommended to provide this information (if available) as it is used to pre-populate any forms the user needs to fill in to complete payment. It decreases the time taken to complete the transaction and improves the rate of successful payment completion.

<input type="hidden" name="name_first" value="John">
<input type="hidden" name="name_last" value="Doe">
<input type="hidden" name="email_address" value="john@doe.com">
<input type="hidden" name="cell_number" value="0123456789">
NAME DESCRIPTION REQUIRED FORMAT
name_first The buyer’s first name. Optional alphanumeric, 100 char
name_last The buyer’s last name. Optional alphanumeric, 100 char
email_address The buyer’s email address Optional alphanumeric, 100 char
cell_number The buyer’s cell number. If the email_address field is empty, and cell_number provided, the system will use the cell_number as the username and autologin the user, if they do not have a registered account Optional numeric

Transaction Details

<input type="hidden" name="m_payment_id" value="01AB">
<input type="hidden" name="amount" value="100.00">
<input type="hidden" name="item_name" value="Test Item">
<input type="hidden" name="item_description" value="A test product">
<input type="hidden" name="custom_int1" value="2">
<input type="hidden" name="custom_str1" value="Extra order information">
NAME DESCRIPTION REQUIRED FORMAT
m_payment_id Unique payment ID on the merchant’s system. Optional alphanumeric, 100 char
amount The amount which the payer must pay in ZAR. Yes decimal
item_name The name of the item being charged for. Yes alphanumeric, 100 char
item_description The description of the item being charged for. Optional alphanumeric, 255 char
custom_int1..5 A series of 5 custom integer variables (custom_int1, custom_int2…) which can be used by the merchant as pass-through variables. They will be posted back to the merchant at the completion of the transaction. Optional numeric, 255 char
custom_str1..5 A series of 5 custom string variables (custom_str1, custom_str2…) which can be used by the merchant as pass-through variables. They will be posted back to the merchant at the completion of the transaction. Optional alphanumeric, 255 char

Transaction Options

<input type="hidden" name="email_confirmation" value="1">
<input type="hidden" name="confirmation_address" value="john@doe.com">
NAME DESCRIPTION REQUIRED FORMAT
1email_confirmation Whether to send email confirmation to the merchant of the transaction. Email confirmation is automatically sent to the payer. Optional 1 or 0
2confirmation_address The address to send the confirmation email to. Optional alphanumeric, 100 char

Set Payment Method

<input type="hidden" name="payment_method" value="cc">
NAME DESCRIPTION REQUIRED FORMAT
payment_method Setting the payment method allows for only the desired payment method to be in focus when the buyer lands on the payment page. The values are as follows:
  • ‘eft’ – sets eft payment method
  • ‘cc’ – sets credit card payment method
  • ‘dc’ – sets debit card payment method
  • ‘bc’ – sets bitcoin payment method
  • ‘mp’ – sets masterpass payment method
  • ‘mc’ – sets mobicred payment method
  • ‘cd’ – sets cash deposit payment method
Optional alphanumeric, 3 char

Recurring Billing Details

Subscription

Subscription

<input type="hidden" name="subscription_type" value="1">
<input type="hidden" name="billing_date" value="2017-01-01">
<input type="hidden" name="recurring_amount" value="123.45">
<input type="hidden" name="frequency" value="3">
<input type="hidden" name="cycles" value="12">

Ad Hoc

<input type="hidden" name="subscription_type" value="2">
NAME DESCRIPTION REQUIRED FORMAT
subscription_type The subscription type sets the recurring billing type to a subscription. Value is as follows:
  • 1 – sets type to a subscription
Yes (For subscription only) 1
billing_date The date from which future subscription payments will be made. Eg. 2016-01-01. Defaults to current date if not set. Optional Date format: YYYY-MM-DD
recurring_amount Future recurring amount for the subscription. Defaults to the ‘amount’ value if not set. A minimum amount of R5.00 should be used as the recurring_amount. Optional decimal
frequency The cycle period. Yes (For subscription only) numeric:
3- Monthly
4- Quarterly
5- Biannual
6- Annual
cycles The number of payments/cycles that will occur for this subscription. Set to 0 for infinity. Yes (For subscription only) numeric, 0 for indefinite subscription

Ad Hoc

NAME DESCRIPTION REQUIRED FORMAT
subscription_type The subscription type sets the recurring billing type to an ad hoc payment. Value is as follows:
  • 2 – sets type to an ad hoc payment
Yes (For Ad Hoc only) 2

Security Features

The Signature

<input type="hidden" name="signature" value="f103e22c0418655fb03991538c51bfd5">

</form>
NAME DESCRIPTION REQUIRED FORMAT
signature

A security signature of the transmitted data taking the form of an MD5 hash of the submitted variables.

The string from which the hash is created, is the concatenation of the name value pairs of all the non-blank variables with ‘&’ used as a separator eg. name_first=John&name_last=Doe&email_address=… where pairs are listed in the order in which they appear on this page.

This hash will be regenerated by the PayFast engine and the values compared to ensure the integrity of the data transfer.

Yes MD5 hash
<?
// Construct variables 
$data = array(
    // Merchant details
    'merchant_id' => '',
    'merchant_key' => '',
    'return_url' => 'http://www.yourdomain.co.za/thank-you.html',
    'cancel_url' => 'http://www.yourdomain.co.za/cancelled-transction.html',
    'notify_url' => 'http://www.yourdomain.co.za/itn.php',
    // Buyer details
    'name_first' => 'First Name',
    'name_last'  => 'Last Name',
    'email_address'=> 'valid@email_address.com',
    // Transaction details
    'm_payment_id' => '8542', //Unique payment ID to pass through to notify_url
    // Amount needs to be in ZAR
    // If multicurrency system its conversion has to be done before building this array
    'amount' => number_format( sprintf( "%.2f", $cartTotal ), 2, '.', '' ),
    'item_name' => 'Item Name',
    'item_description' => 'Item Description',
    'custom_int1' => '9586', //custom integer to be passed through           
    'custom_str1' => 'custom string is passed along with transaction to notify_url page'
);        

// Create GET string
foreach( $data as $key => $val )
{
    if(!empty($val))
     {
        $pfOutput .= $key .'='. urlencode( trim( $val ) ) .'&';
     }
}
// Remove last ampersand
$getString = substr( $pfOutput, 0, -1 );
if( isset( $passPhrase ) )
{
    $getString .= '&passphrase='. urlencode( trim( $passPhrase ) );
}   
$data['signature'] = md5( $getString );

This array can then also be used in generating the form output.

<?
// If in testing mode make use of either sandbox.payfast.co.za or www.payfast.co.za
$testingMode = true;
$pfHost = $testingMode ? 'sandbox.payfast.co.za' : 'www.payfast.co.za';
$htmlForm = '<form action="https://'.$pfHost.'/eng/process" method="post">'; 
foreach($data as $name=> $value)
{ 
    $htmlForm .= '<input name="'.$name.'" type="hidden" value="'.$value.'" />'; 
} 
$htmlForm .= '<input type="submit" value="Pay Now" /></form>'; 
echo $htmlForm;

The order of the checkout variables

The order in which the checkout page variables and urlencoded values are submitted is vitally important, and allows PayFast to ensure the integrity of the data transfer by way of the signature. It is a set order, the same as they appear in the tables above.

When the data transmitted from the checkout page is received by PayFast, the MD5 hash will be regenerated by PayFast from the supplied data, in the set order, and the resulting hash will be compared with the signature received. If the hash created, from the checkout variables supplied, does not match the signature, then the payment will fail. The string from which the hash is created, is the concatenation of the name value pairs of all the non-blank variables with ‘&’ used as a separator eg:

name_first=John&name_last=Doe&email_address=john.doe@example.com..

Passphrase

The passphrase is an optional/ extra security feature, made up of a maximum of 32 characters, which is set by the Merchant in the Settings section of their PayFast Dashboard. The identical passphrase must be used on the merchant’s site.

The passphrase is used to ‘salt’ the parameter string before it is MD5 hashed to generate the signature.

This further aids in ensuring the integrity of the data that is being passed through when payment is made.

Example Checkout Page

confirm page

Common causes of a failed integration / signature mismatch

The following will cause a signature mismatch or a payment to fail:

  1. The order of the variables in parameter string (to create the signature/MD5 hash) does not mirror the order as presented above. This is the most likely cause of a signature mismatch! It is critical that the variables are concatenated in the order as they appear in the tables above.

  2. A required field is missing

  3. A field is greater than the allowable character length

  4. Any of the fields containing non-allowable characters

  5. The GET string has been URLencoded incorrectly. The resultant URLencoding has to be show upper case, for example, http%3A%2F%2 and not lower case like http%3a%2f%2f.

  6. The GET string has not been trimmed of white spaces on the ends. Please make use of PHP’s trim() function to avoid this.

Success Page

The success page, or return page, is used to show the buyer that the payment has been successfully received and provides any necessary details about the order.

This page is determined by the value set on the return_url field of the form submitted from the checkout page. It is possible to add a cart id, or order id, onto the return_url which the merchant’s system can then use to access the necessary information from the database to be displayed to the user on the success page.

Return page example

success page

Cancel Page

This page is where buyers are redirected to if they cancel the payment transaction at any stage. It is defined by the cancel_url field that is set on the shopping cart or client checkout page prior to being redirected to the PayFast payment engine.

If you are saving the user’s purchase information prior to being redirected, it is common practice to present that information to the buyer on this page to encourage them to complete the transaction or continue shopping. Many eCommerce solutions set the cancel_url field to the same page as the shopping cart page to get the buyer to retry (or reconsider) paying.

Cancel Page Example

cancel page

Notify Page (ITN)

itn_page

The payment notification (Instant Transaction Notification – ITN) communicates with the notify_url, which is a  field set on the  form sent from the checkout page, allowing for the exchange of data between the two web servers after a successful transaction. The notify_url should process the following:

  1. Receive the data posted by PayFast
  2. Notify PayFast that the information has been received
  3. Perform security checks
    • Verify the security signature is valid
    • Verify the source IP address belongs to PayFast
    • Verify the payment amount matches your order amount
    • Verify the data received is valid
  4. Verify that the order hasn’t been processed already
  5. Process the order
    • Update the status to paid
    • Email the buyer confirming payment

Return Variables

Detailed below are the possible variables returned to the receiver as part of an ITN from PayFast.

Transaction details

NAME DESCRIPTION INCLUDE FORMAT
m_payment_id Unique payment ID on the merchant’s system. Optional alphanumeric, 100 char
pf_payment_id Unique transaction ID on PayFast. Required numeric
payment_status The status of the payment. Required alphanumeric
item_name The name of the item being charged for. Required alphanumeric, 100 char
item_description The description of the item being charged for. Optional alphanumeric, 255 char
amount_gross The total amount which the payer paid. Required decimal
amount_fee The total in fees which was deducated from the amount. Required decimal
amount_net The net amount credited to the receiver’s account. Required decimal
custom_str1..5 The series of 5 custom string variables (custom_str1, custom_str2…) originally passed by the receiver during the payment request. Optional alphanumeric, 255 char
custom_int1..5 The series of 5 custom integer variables (custom_int1, custom_int2…) originally passed by the receiver during the payment request. Optional numeric

Buyer details

NAME DESCRIPTION INCLUDE FORMAT
name_first The buyer’s first name. Optional alphanumeric, 100 char
name_last The buyer’s last name. Optional alphanumeric, 100 char
email_address The buyer’s email address Optional alphanumeric, 100 char

Merchant details

NAME DESCRIPTION INCLUDE FORMAT
merchant_id The Merchant ID as given by the PayFast system. Used to uniquely identify the receiver’s account. Required numeric

Recurring billing details

NAME DESCRIPTION INCLUDE FORMAT
token Unique ID on PayFast that represents the subscription Required alphanumeric, 36 char
NAME DESCRIPTION INCLUDE FORMAT
payment_status After a successful payment the status sent will be COMPLETE. When a subscription is cancelled the status will be CANCELLED. Required COMPLETE or CANCELLED

Security information

NAME DESCRIPTION INCLUDE FORMAT
signature A security signature of the transmitted data taking the form of an MD5 hash of the submitted variables. The string from which the hash is created, is the concatenation of the name value pairs of all the non-blank variables with ‘&’ used as a separator eg. “name_first=John&name_last=Doe&email_address=…” where pairs are listed in the order in which they appear on this page. This hash will be regenerated by the PayFast engine and the values compared to ensure the integrity of the data transfer. Optional MD5 hash

If the ITN callback method has been used, part of the security checking stage is confirming the received data’s signature (see security check one).

If you have a passphrase set on your account “Settings” page, it will need to be added to the string used to generate the signature. The passphrase is never published or given out. It serves as an extra security measure to ensure that all information is accurate and has not been tampered with.

Step one

<?
header( 'HTTP/1.0 200 OK' );
flush();

Store the posted data in:

<?
define( 'SANDBOX_MODE', true );
$pfHost = SANDBOX_MODE ? 'sandbox.payfast.co.za' : 'www.payfast.co.za';
// Posted variables from ITN
$pfData = $_POST;

// Strip any slashes in data
foreach( $pfData as $key => $val )
{
    $pfData[$key] = stripslashes( $val );
}

Receive the payment information from PayFast and then tell PayFast that this page is reachable by triggering a header 200, the payment engine will make a few attempts, one immediately and then one after 10 minutes again, then exponentially at longer intervals, until it receives an OK 200 from your web server. Once the ITN receives the OK 200 there will be no further comminication with the ITN.

Step two

Conduct four security checks to ensure that the data you are receiving is correct, from the correct source and hasn’t been altered; you should not continue the process if a test fails!

Security check one

<?
// $pfData includes of ALL fields posted through from PayFast, plus the empty strings
$pfData = $_POST;

// Construct variables 
foreach( $pfData as $key => $val )
{
    if( $key != 'signature' )
    {
        $pfParamString .= $key .'='. urlencode( $val ) .'&';
    }
}

// Remove the last '&' from the parameter string
$pfParamString = substr( $pfParamString, 0, -1 );
$pfTempParamString = $pfParamString;
// Passphrase stored in website database
$passPhrase = '';

if( !empty( $passPhrase ) )
{
    $pfTempParamString .= '&passphrase='.urlencode( $passPhrase );
}
$signature = md5( $pfTempParamString );

if($signature!=$pfData['signature'])
{
    die('Invalid Signature');
}

Verify the security signature in the data array; this is done in a similar way that the signature that you generated for stage one of the user payment flow. It is to ensure that there hasn’t been any middle man attacks and changing of values within the received data. The string that gets created needs to include all fields posted from PayFast.

Security step two

<?
// Variable initialization
$validHosts = array(
    'www.payfast.co.za',
    'sandbox.payfast.co.za',
    'w1w.payfast.co.za',
    'w2w.payfast.co.za',
);

$validIps = array();

foreach( $validHosts as $pfHostname )
{
    $ips = gethostbynamel( $pfHostname );
    if( $ips !== false )
    {
        $validIps = array_merge( $validIps, $ips );
    }
}

// Remove duplicates
$validIps = array_unique( $validIps );

if( !in_array( $_SERVER['REMOTE_ADDR'], $validIps ) )
{
    die('Source IP not Valid');
}

With this test you will be checking to ensure that your application is communicating with a valid PayFast payment engine.

The following is a list of valid domains:

Security step three

<?
$cartTotal = xxxx; // This amount needs to be sourced from your application
if( abs( floatval( $cartTotal ) - floatval( $pfData['amount_gross'] ) ) > 0.01 )
{
    die('Amounts Mismatch');
}

Check payment data against the merchant’s order. This can be determined by comparing the amount processed for payment and the amount of the cart in you application and seeing if they match.

Security step four

<?
// Variable initialization
$url = 'https://'. $pfHost .'/eng/query/validate';

// Create default cURL object
$ch = curl_init();

// Set cURL options - Use curl_setopt for greater PHP compatibility
// Base settings
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, false );      
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, 2 );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );

// Standard settings
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_POST, true );
curl_setopt( $ch, CURLOPT_POSTFIELDS, $pfParamString );

// Execute CURL
$response = curl_exec( $ch );
curl_close( $ch );

$lines = explode( "\r\n", $response );
$verifyResult = trim( $lines[0] );

if( strcasecmp( $verifyResult, 'VALID' ) != 0 )
{
    die('Data not valid');
}

Using cURL, validate the data that you have received from PayFast by contacting our server and confirming the order details.

Live validation URL:

Sandbox validation URL:

The following table contains a detailed description of each of the cURL options used in the code snippet to the right.

OPTION DESCRIPTION
CURLOPT_RETURNTRANSFER Set to TRUE to return the transfer as a string of the return value of curl_exec() instead of outputting it out directly.
CURLOPT_HEADER Set to False to exclude the header in the output.
CURLOPT_SSL_VERIFYHOST Set to 2 to check the existence of a common name in the SSL peer certificate, and to also verify that it matches the hostname provided.
CURLOPT_SSL_VERIFYPEER Set to FALSE to stop cURL from verifying the merchant site’s certificate.
CURLOPT_URL Set to the PayFast query validation URL, eg. https://www.payfast.co.za/eng/query/validate. This can also be set when initializing a session with curl_init().
CURLOPT_POST Set to TRUE to do a regular HTTP POST. This POST is the normal application/x-www-form-urlencoded kind, most commonly used by HTML forms.
CURLOPT_POSTFIELDS The full data to post via HTTP to PayFast. This parameter is passed as a urlencoded string, such as:

m_payment_id=01&pf_payment_id=01234..

Step three

<?
$pfPaymentId = $pfData['pf_payment_id'];

Query your database and compare the pf_payment_id in order to verify that the order hasn’t already been processed on your system.

Step four

<?
 if( $pfData ['payment_status'] == 'COMPLETE' )
 {
    // If complete, update your application
 }
 else
 {
    // If unknown status, do nothing (which is the safest course of action)
 }

For Recurring billing only:

<?
switch( $pfData['payment_status'] )
{
    case 'COMPLETE':
    // If complete, update your application
       break;
    case 'CANCEL':
    // If cancel, then cancel subscription
       break;
    default:
    // If unknown status, do nothing (which is the safest course of action)
       break;
}

Once you have completed these tests and the data received is valid, check the payment status and handle appropriately.

PDT (deprecated)

PDT

API Integration

Getting Started

PayFast is in the process of rolling out a fully-fledged RESTful API. The first endpoints available will be for the management of subscriptions, with further functionality being released in the near future.

How it Works

All API communications with PayFast take the form of standard HTTP requests. These requests are made against a set of endpoints, depending on the action required. Variables may be sent via both the headers and body of each request as specified. The minimum set of variables required to connect to PayFast’s API services are detailed below.

API services follow RESTful principles, and thus rely on HTTP verbs to describe the action being requested:

Minimum Requirements

At a minimum, the following must be provided to gain access to the API ecosystem:

  1. A valid and an API enabled PayFast merchant account
  2. A passphrase as set on the merchant account settings page
  3. PayFast merchant ID
  4. The version of the API you want to interact with
  5. A valid merchant signature
  6. A timestamp included in the request

Input Formats and Content Types

{
    "frequency" : 3,
    "cycles" : 12
}

Sending data to the API may be done in one of two ways:

<?php

// $pfData will contain all of the values to be sent to the API,
// As well as in both the headers and the body.
$pfData = $fieldsToTransmit;

// Construct variables 
foreach( $pfData as $key => $val ) {
    $data[$key] = stripslashes( $val );
}

if( isset( $passPhrase ) ) {
    $pfData['passphrase'] = $passPhrase;
}

// Sort the array by key, alphabetically
ksort($pfData);

// Normalise the array into a parameter string
foreach( $pfData as $key => $val ) {
    if( $key != 'signature' ) {
        $pfParamString .= $key .'='. urlencode( $val ) .'&amp;';
    }
}

// Remove the last '&amp;' from the parameter string
$pfParamString = substr( $pfParamString, 0, -1 );
$signature = md5( $pfParamString );

API Signature Generation

The security signature of the transmitted data takes the form of an MD5 hash of the alphabetised submitted variables, header and body variables, as well as the passphrase. The string from which the hash is created is the concatenation of the name value pairs of all the non-blank variables with ‘&’ used as a separator. Each value should also be urlencoded (eg. “merchant-id=10000100&passphrase=passphrase&..&version=v1”).

The generated MD5 signature must be passed in the header of the request and this hash will be regenerated by the API and compared to ensure the integrity of the data transfer.

Difference between Checkout Page Signature generation and API Signature Generation

Checkout Page SignatureAPI Signature
Merchant ID variable namemerchant_idmerchant-id
Order of the string variables (before hashing)The variables need to be ordered correctly, as per the checkout page documentationThe data is ksorted, in other words, the variable are ordered alphabetically
AmountThe amount which the buyer must pay, in RANDS (ZAR)The amount which the buyer must pay, in CENTS (ZAR)

Merchant Passphrase

The signature described previously utilises a passphrase that is chosen by the merchant and is linked to their account. Every request sent by the merchant will have a signature that is salted with their passphrase. The passphrase is considered a secret between the merchant and PayFast and should never be sent or given out.

The merchant may set their own passphrase by:

  1. Login to PayFast using their merchant credentials.
  2. Clicking on ‘Settings’, and then ‘Edit’ under the ‘Security Pass Phrase’ section.
  3. Inputting the desired passphrase, and clicking ‘Update’

Request Timestamp

Each request to the API must contain an ISO-8601 formatted timestamp. This field must be present in each request body along with the signature. Failure to include this field will result in an error. The timestamp field must be formatted according to ISO-8601 standards, and be in the following format:

YYYY-MM-DDTHH:MM[(+-)HH:MM] (e.g. 2016-04-01T12:00:01+02:00)

The time zone offset group ((+-)HH:MM) is optional. If not included, the default will be assumed to be GMT +2.

IP Whitelisting

Each request to the API may be controlled by an IP address whitelist. If set, the IP address of the server completing the API call must be in the given list, else the action will not be processed. The whitelist can be set on the merchant’s settings page and is an optional security setting.

Variable format

The below table describes the formats of the variables used when integrating with PayFast.

Format Description
alphanumeric A-Z, a-z, 0-9
alphanumericextended alphanumeric and special characters _-/
char maximum number of characters
decimal numeric and optional decimal point .
email valid email address
numeric numeric digits, 0-9
url/alphanumericspecial alphanumeric and special characters _-/:&?#=+
MD5 hash 32 character hexadecimal number.

Recurring Billing

Introduction

The recurring service will allow for merchants to create two methods of recurring payments, one method being a traditional subscription model of a recurring charge on a given date, the other a one-click ad hoc model where the future dates and amounts of payments may be unknown.

How it Works

In order to setup a subscription or ad hoc payment you will first need to follow the Web Integration documentation and include the necessary payment parameters for subscriptions or ad hoc payments. Once setup, the buyer will not have to be redirected to PayFast again in order to make payment, and you will be able to perform the below mentioned actions via the API making use of the token sent to your notify URL as part of the ITN. For a subscription, PayFast will charge the credit card according to the data sent in the payment request, for ad hoc payments PayFast will only charge the buyers card when instructed to do so via the API.

PayFast Recurring Billing

Subscriptions

The buyer who chooses to enter into a subscription with a merchant will, after checkout, be redirected to PayFast where only the credit card payment option will be available. After a successful first payment there is no need for the buyer to make any further manual payments for the subscription. The recurring amount will be deducted from their credit card in accordance with the frequency, billing date and number of payments (cycles) given. Each successful payment will create an ITN to the merchant and they will be able to manage the subscription via an API or from their PayFast account.

Ad Hoc Payments

A buyer who agrees to enter into an ad hoc payment with a merchant will, after checkout, be redirected to PayFast where only the credit card payment option will be available. After a successful first payment there is no need for the buyer to make any further manual payments. For any future payments the merchant will only need to send a token value to the API to have the associated credit card of the buyer charged. On each successful payment, an ITN will be sent to the merchant and they will be able to manage the subscription via the API or from their PayFast account.

R0.00 Initial Transaction

It is possible to setup a subscription or ad hoc payment with an initial amount of R0.00. This would be used with subscriptions if the first cycle/period is free (the recurring_amount value would need to be a minimum of R5.00), or, in the case of ad hoc payments it is used to setup the buyers account on the merchants site, allowing for future payments. If the initial amount is R0.00 the buyer will be redirected to PayFast, where they will input their credit card details and go through 3D Secure, but no money will be deducted.

Integration Options

Pay Now Button

One of the easiest ways to create a subscription is to use a Pay Now button. The button code can be generated from your PayFast dashboard. Simply fill in the necessary fields (ensuring the subscription fields are populated), click ‘generate’ and copy the code to your website.

Payment Request

Should a merchant require a buyer to start a subscription without the buyer going onto a website they can make use of the Request Payment feature on their PayFast dashboard. The merchant will need to fill in the required fields, then PayFast will send an email on behalf of the merchant with a button to start the subscription. Once the initial payment is made the subscription will be active.

E-commerce and Platform Plugins

Subscriptions will be supported by a number of PayFast supported plugins which may be downloaded from our shopping carts page. Currently the following plugins support subscriptions:

Due to some integration requirements, ad hoc payments may not be available via some of our plugins.

Custom Integration

To accommodate recurring billing for the widest possible merchant base, the traditional custom integration has been extended to allow for the additional subscription fields. Future versions of the API will implement a more RESTful approach with additional security options. Please follow the developer documentation in order to build a custom integration, taking note of the subscription fields on the checkout page, and the return variables.

A passphrase is compulsory for all subscriptions which is set on the merchant’s PayFast settings page. Generation of the signature sent to PayFast follows the current documentation. The order of the additional subscription fields is important and can be seen in the table on the checkout page.

Recurring Maintenance

Buyer Perspective

A buyer is able to login to their PayFast account and view or cancel any of their recurring billings. When cancelled by the buyer, the merchant will be notified via email, and/or an ITN will be sent to the notify_url with the payment_status of CANCELLED. The buyer will be able to change the credit card, including card verification and 3D secure, linked to the subscription or ad hoc payment. Should a buyer not have a PayFast account, they will be able to register at any point to manage their subscriptions.

Expired Cards

A buyer will be notified via email a month in advance about registered cards which will expire and are linked to an active subscription/agreement. Instructions will be provided in the notification email to help them link a new card to their subscription, so that they do not experience any break in payments or service. A buyer will be permitted to register for subscriptions even if the card is due to expire before the end of the subscription term.

Merchant Perspective

The following actions may be accomplished via the PayFast dashboard, as well as the API

  1. Cancel

    Any recurring billing type may be cancelled from the PayFast merchant account. The buyer will be notified via email of this action.

  2. Pause

    Should a subscription be paused the remaining payments (cycles) will remain untouched. The end date of the subscription moves on by the number of paused frequency period(s). Effectively the buyer gains a payment gap and the number of payments will still be the same as originally requested. A free month(s) could be provided by pausing (pause) a subscription and reducing the number of cycles by making an update to the subscription.

    Only the merchant has the functionality to pause or unpause a subscription.

Failed Payments

Subscriber Out of Funds

PayFast will try a number of times to reprocess a payment where the buyer does not have funds on their credit card. On failure, the buyer will be notified, allowing some time for the problem to be resolved. On a complete failure (after X amount of times), the subscription will be ‘locked’ and will need some action from the merchant to reactivate on the PayFast account or via the API pause endpoint.

ad hoc payments Out of Funds

When receiving the API call to charge an agreement’s credit card via token, PayFast will attempt to charge the card immediately and the failed response will be returned returned.

System Issues

PayFast will resolve any system issue that may cause payment failure. Subscription payments will resume once all systems have been restored.

Subscription Payments API Endpoints

URL Composition

The API exposes the following endpoints which will allow Merchants the ability to interact with subscriptions on their accounts.

URLs to interact with take the following form:

[endpoint]This should be set to “subscriptions”
[token]The 36 character alphanumeric string returned to your notify URL via the ITN callback which uniquely identifies a subscription
[action]This will be the verb describing the intended action to take.
?testing=true Include this text should you wish to make use of the PayFast sandbox for testing purposes.

Actions Available via the API

If using a FORM to post data to any endpoint, all FORMs must submit via normal POST forms and have a hidden value called ‘_method’, set to the appropriate verb.

Recurring Billing Type 1 – Subscription Payments

Successful ping response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful ping response

{
  "code":404,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] ping

Used to check if the API is responding to requests.

https://api.payfast.co.za/subscriptions/ping

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/ping

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

Successful pause response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful pause response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[PUT] pause

Pause a subscription, for a duration indicated by a ‘cycles’ payload variable.

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/pause

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
cycles Body, number of cycles to pause the subscription for. Default is 1 if not given. Optional numeric

Successful unpause response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful unpause response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[PUT] unpause

Unpause a subscription

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/unpause

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

Successful cancel response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful cancel response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[PUT] cancel

This will cancel a subscription entirely.

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/cancel

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

Successful update response

{
  "code":200,
  "status":"success",
  "data":{
    "response":{
      "token":"a3b3ae55-ab8b-b388-df23-4e6882b86ce0",
      "amount":"1628",
      "cycles":"14",
      "cycles_complete":"9",
      "frequency":"3",
      "status":"1",
      "run_date":"2016-07-04"
    }
  }
}

Unsuccessful update response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[PATCH] update

This allows for multiple subscription values to be updated

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/update

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
cycles Body, the number of cycles for the subscription. Optional numeric
frequency Body, the frequency for the subscription Optional numeric
date Body, the next run date for the subscription. Optional YYYY-MM-DD
amount Body, the amount which the buyer must pay, in CENTS (ZAR). Optional numeric

Successful fetch response

{
  "code":200,
  "status":"success",
  "data":{
    "response":{
      "token":"a3b3ae55-ab8b-b388-df23-4e6882b86ce0",
      "amount":"1628",
      "cycles":"14",
      "cycles_complete":"9",
      "frequency":"3",
      "status":"1",
      "run_date":"2016-07-04"
    }
  }
}

Unsuccessful fetch response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] fetch

Returns a JSON object containing the subscription details

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/fetch

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

CURL Examples

The examples below demonstrate cURL calls containing the following:

Pausing a subscription

<?php

$token = 'dc0521d3-55fe-269b-fa00-b647310d760f';
// Set up cURL, add "?testing=true" to the end when testing
$ch = curl_init( "https://api.payfast.co.za/subscriptions/". $token ."/pause" );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch, CURLOPT_TIMEOUT, 60 );
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "PUT" );
// For the body values such as amount, frequency, & date
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $payload ) );
curl_setopt( $ch, CURLOPT_VERBOSE, true );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
    'version: v1',
    'merchant-id: 10000100',
    'signature: 840654b40a8b312e54650e1613696b44',
    'timestamp: 2016-04-01T12:00:01' 
) );

// Execute and close cURL
$data = curl_exec( $ch );
curl_close( $ch );

curl -v -X PUT -H “merchant-id: 10000100” -H “version: v1” -H “timestamp=2016-04-01T12:00:01” -H “signature=840654b40a8b312e54650e1613696b44” https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/pause

An example of the request information sent can be seen below:

>PUT https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/pause HTTP/1.1

>User-Agent: curl/7.37.0

>Host: api.payfast.co.za

>Accept: */*

>merchant-id: 10000100

>version: v1

>timestamp: 2016-04-01T12:00:01

>signature: 840654b40a8b312e54650e1613696b44

>Content-Length: 0

>Content-Type: application/x-www-form-urlencoded

Return Variables

Example of a success response

{
        "code": 200,
        "status": "success",
        "data": {
                "response": true,
                "message": "Success"
        }
}

Example of a failure response

{
        "code": 400,
        "status": "failed",
        "data": {
                "response": false,
                "message": "Failure"
        }
}

All responses from the API follow a standard format. It is a JSON encoded string containing code, status and data elements. The data element may contain more than one message.

Outline of a JSON formatted response:

Errors and Causes

The following errors can be expected during authentication when connecting to PayFast.

CODE ERROR MESSAGE REASON
400

Required variables not present in request

Value for signature is not in the expected format

API version is not valid

Signature not present in headers

The request is missing some or all of the required fields.

Generated when the merchant signature provided is not an MD5 hash, or is malformed.

Issued when the version header refers to a version that does not exist, or is malformed.

The signature has not been provided.

401

Merchant not found

Request origin not recognised

Request origin could not be verified

Merchant authorisation failed

The given merchant ID was not found.

Generated when the request does not contain a REMOTE_ADDR value.

Occurs when the request is made from a location not specified in the whitelist.

The signature is incorrect.

404 Service / endpoint not found The endpoint does not exist or the requesting merchant does not have permission to access.
429 Signature rate limit reached, please try again in a few minutes The rate limit was hit.
500

Application Error

Communication Failure

Application Error.

Networking issue with the API.

Ad Hoc Payments API Endpoints

URL Composition

The API exposes the following endpoints which will allow Merchants the ability to interact with subscriptions on their accounts.

URLs to interact with take the following form:

[endpoint]This should be set to “subscriptions”
[token]The 36 character alphanumeric string returned to your notify URL via the ITN callback which uniquely identifies a subscription
[action]This will be the verb describing the intended action to take.
?testing=true Include this text should you wish to make use of the PayFast sandbox for testing purposes.

Actions Available via the API

If using a FORM to post data to any endpoint, all FORMs must submit via normal POST forms and have a hidden value called ‘_method’, set to the appropriate verb.

Recurring Billing Type 2 – Ad Hoc Payments

Successful ping response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful ping response

{
  "code":404,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] ping

Used to check if the API is responding to requests.

https://api.payfast.co.za/subscriptions/ping

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/ping

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

Successful adhoc response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful adhoc response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[POST] adhoc

Charge an ad hoc subscription based on token.

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/adhoc

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
amount Body, the amount which the buyer must pay, in CENTS (ZAR). Yes numeric
item_name Body, the name of the item being charged for. Yes alphanumeric
item_description Body, the description of the item being charged for. optional alphanumeric
itn Body, specify whether an ITN must be sent for the ad hoc charge (1 by default). optional 0 or 1
m_payment_id Body, unique payment ID on the merchant’s system. optional alphanumeric
cc_cvv Body, the credit card cvv number. optional numeric

Successful fetch response

{
  "code":200,
  "status":"success",
  "data":{
    "response":{
      "token":"a3b3ae55-ab8b-b388-df23-4e6882b86ce0",
      "status":1
    }
  }
}

Unsuccessful adhoc response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] fetch

Returns a JSON object containing the subscription details.

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/fetch

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

Successful cancel response

{
  "code":200,
  "status":"success",
  "data":{
    "response":true
  }
}

Unsuccessful cancel response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[PUT] cancel

This will cancel a subscription entirely.

https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/cancel

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

CURL Examples

The examples below demonstrate cURL calls containing the following:

Charging a Token

<?php
// Array used for CURLOPT_POSTFIELDS
$payload = array(
    'amount' => $amount,
    'item_name' => $itemName,
    'item_description' => $itemDescription //optional
);


$token = 'dc0521d3-55fe-269b-fa00-b647310d760f';
// Set up cURL, add "?testing=true" to the end when testing
$ch = curl_init( "https://api.payfast.co.za/subscriptions/". $token ."/adhoc" );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch, CURLOPT_TIMEOUT, 60 );
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
// For the body values such as amount, item_name, & item_description
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $payload ) );
curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
    'version: v1',
    'merchant-id: 10000100',
    'signature: 840654b40a8b312e54650e1613696b44',
    'timestamp: 2016-04-01T12:00:01' 
) );

// Execute and close cURL
$response = curl_exec( $ch );
curl_close( $ch );

curl -v -X PUT -H “merchant-id: 10000100” -H “version: v1” -H “timestamp=2016-04-01T12:00:01” -H “signature=840654b40a8b312e54650e1613696b44” https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/adhoc

An example of the request information sent can be seen below:

> PUT https://api.payfast.co.za/subscriptions/dc0521d3-55fe-269b-fa00-b647310d760f/adhoc HTTP/1.1

> User-Agent: curl/7.37.0

> Host: api.payfast.co.za

> Accept: */*

> merchant-id: 10000100

> version: v1

> timestamp: 2016-04-01T12:00:01

> signature: 840654b40a8b312e54650e1613696b44

> Content-Length: 0

> Content-Type: application/x-www-form-urlencoded

Return Variables

Example of a success response

{
         "code": 200,
         "status": "success",
         "data": {
                 "response": true,
                 "message": "Success"
         }
 }

Example of a failure response

{
        "code": 400,
        "status": "failed",
        "data": {
                "response": false,
                "message": "Failure"
        }
}

All responses from the API follow a standard format. It is a JSON encoded string containing code, status and data elements. The data element may contain more than one message.

Outline of a JSON formatted response:

Errors and Causes

The following errors can be expected during authentication when connecting to PayFast.

CODE ERROR MESSAGE REASON
400

Required variables not present in request

Value for signature is not in the expected format

API version is not valid

Signature not present in headers

The request is missing some or all of the required fields.

Generated when the merchant signature provided is not an MD5 hash, or is malformed.

Issued when the version header refers to a version that does not exist, or is malformed.

The signature has not been provided.

401

Merchant not found

Request origin not recognised

Request origin could not be verified

Merchant authorisation failed

The given merchant ID was not found.

Generated when the request does not contain a REMOTE_ADDR value.

Occurs when the request is made from a location not specified in the whitelist.

The signature is incorrect.

404 Service / endpoint not found The endpoint does not exist or the requesting merchant does not have permission to access.
429 Signature rate limit reached, please try again in a few minutes The rate limit was hit.
500

Application Error

Communication Failure

Application Error.

Networking issue with the API.

PayFast Account

Available actions for accounts

The actions described below are available via the API in order for merchants to interact with their PayFast account.

Transaction History

The URL to interact with will take the following form:

Unsuccessful history response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] history

Obtain the transaction history for given a period.

https://api.payfast.co.za/transactions/history?from=2017-01-01&to=2017-02-01

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
from Body, start date for the time period. Defaults to current month Optional YYYY-MM-DD
to Body, end date for the time period. Defaults to current date Optional YYYY-MM-DD

Unsuccessful daily response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] daily

Obtain the transaction history for a given daily period.

https://api.payfast.co.za/transactions/history/daily?date=2017-01-01

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
date Body, date of the time period. Defaults to current date Optional YYYY-MM-DD

Unsuccessful weekly response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] weekly

Obtain the transaction history for a given weekly period.

https://api.payfast.co.za/transactions/history/weekly?date=2017-01-01

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
date Body, date of the time period. Defaults to current week Optional YYYY-MM-DD

Unsuccessful monthly response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] monthly

Obtain the transaction history for a given monthly period.

https://api.payfast.co.za/transactions/history/monthly?date=2017-01-01

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
date Body, date of the time period. Defaults to current month Optional YYYY-MM-DD

Transaction Query

The URL to interact with will take the following forms below.

Live Endpoint:

Sandbox Endpoint:

When testing, an optional parameter “testing=true” needs to be appended. This will route transactions to a sandbox environment where no production data is returned.

The Transaction token, or PayFast payment id, needs to be sent to retrieve the transaction details.

Successful query response

{
  "code":200,
  "status":"success",
  "data":{
    "response":{
      "pf_payment_id":"69",
      "m_payment_id":"232345",
      "status":"COMPLETE",
      "amount":"3600",
      "cc_status":"00",
      "cc_message":"Approved or completed successfully (00)"
    },
    "message":"Success"
  }
}

Unsuccessful query response

{
  "code":500,
  "status":"error",
  "data":{
    "response":false
  }
}

[GET] query

Query a transaction.

https://api.payfast.co.za/process/query/01d2e4c7-28c8-3a86-151f-eab5357da649

https://api.payfast.co.za/process/query/69

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash

Transaction Refund

The URL to interact with will take the following forms below.

Live Endpoint:

Sandbox Endpoint:

Successful refund response

{
  "code":200,
  "data":{
    "message":"Success",
    "response":{
      "amount":1000,
      "cc_message":"Transaction was successful (00)",
      "cc_status":"00",
      "m_payment_id":"232345",
      "pf_payment_id":75405,
      "transaction_token":"8f6395b4-07ba-65d9-4445-7c252f6bf11c"
    }
  },
  "status": "success"
}

Unsuccessful refund response

{
  "code":400,
  "data":{
    "message":"Failed",
    "response":"reason why this request failed."
  },
  "status":"failed"
}

[POST] refund

Refund a particular transaction.

https://api.payfast.co.za/process/refund

NAME DESCRIPTION REQUIRED FORMAT
merchant-id Header, the Merchant ID as given by the PayFast system. Yes numeric, 8 char
version Header, the PayFast API version. Yes v1
timestamp Header, the current timestamp. Yes ISO-8601 date and time, YYYY-MM-DDTHH:MM:SS[+HH:MM]
signature Header, MD5 hash of the alphabetised submitted header and body variables, as well as the passphrase. Yes MD5 hash
amount Header, the amount to refund. Yes numeric
pf_payment_id Header, the pf_payment_id of a particular transaction Yes, without transaction_token numeric
transaction_token Header, the token of a particular transaction. Yes, without pf_payment_id alphanumeric
mail_merchant Body, send a notification email to the merchant. Optional 0 or 1
mail_customer Body, send a notification email to the customer Optional 0 or 1

API Validation

CURL Examples

The example below demonstrates a cURL call containing the following:

<?php
// Array used for CURLOPT_POSTFIELDS
$payload = array(
    'date' => '2017-01-01'
);

// Set up cURL
$ch = curl_init( "https://api.payfast.co.za/transactions/history/daily" );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt( $ch, CURLOPT_TIMEOUT, 60 );
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "GET" );
// For the body values such as date, from, to, & format
curl_setopt( $ch, CURLOPT_POSTFIELDS, http_build_query( $payload ) );
curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
curl_setopt( $ch, CURLOPT_HTTPHEADER, array(
    'version: v1',
    'merchant-id: 10000100',
    'signature: 840654b40a8b312e54650e1613696b44',
    'timestamp: 2017-01-01T12:00:00' 
) );

// Execute and close cURL
$response = curl_exec( $ch );
curl_close( $ch );

curl -v -X PUT -H “merchant-id: 10000100” -H “version: v1” -H “timestamp: 2017-01-01T12:00:00” -H “signature: 840654b40a8b312e54650e1613696b44” https://api.payfast.co.za/transactions/history/daily

An example of the request information sent can be seen below:

> GET https://api.payfast.co.za/transactions/history/daily HTTP/1.1

> User-Agent: curl/7.37.0

> Host: api.payfast.co.za

> Accept: */*

> merchant-id: 10000100

> version: v1

> timestamp: 2017-01-01T12:00:00

> signature: 840654b40a8b312e54650e1613696b44

> Content-Length: 0

> Content-Type: application/x-www-form-urlencoded

Errors and Causes

The following errors can be expected during authentication when connecting to PayFast.

CODE ERROR MESSAGE REASON
400

Required variables not present in request

Value for signature is not in the expected format

API version is not valid

Signature not present in headers

The request is missing some or all of the required fields.

Generated when the merchant signature provided is not an MD5 hash, or is malformed.

Issued when the version header refers to a version that does not exist, or is malformed.

The signature has not been provided.

401

Merchant not found

Request origin not recognised

Request origin could not be verified

Merchant authorisation failed

The given merchant ID was not found.

Generated when the request does not contain a REMOTE_ADDR value.

Occurs when the request is made from a location not specified in the whitelist.

The signature is incorrect.

404 Service / endpoint not found The endpoint does not exist or the requesting merchant does not have permission to access.
429 Signature rate limit reached, please try again in a few minutes The rate limit was hit.
500

Application Error

Communication Failure

Application Error.

Networking issue with the API.

System Information

The following information can be used by system administrators if any changes need to be made to your servers when integrating with PayFast.

IP addresses

These are the PayFast server IPs. Our information can come from any of these IPs and we recommend white-listing all of these IPs.

IP ADDRESS
197.97.145.144 / 28 (197.97.145.145 - 197.97.145.222)
41.74.179.192 / 27 (41.74.179.193 – 41.74.179.222)

Ports

When communicating with the notify url via the ITN, PayFast makes use of ports 80, 8080, 8081 and 443 only.

Testing and Tools

Sandbox

The PayFast sandbox testing environment allows you to perform test transactions when integrating with PayFast. The sandbox currently makes use of a single payment method – a PayFast wallet with an infinite fake balance for once off payments, or a test credit card for recurring payments. This will allow you to test your integration with PayFast, including the ITN, without any money changing hands. Although it is not currently possible to experience the other payment methods on PayFast, this will not affect your integration.

Testing with the Sandbox

Sandbox url:

Testing on the PayFast system follows a sandbox strategy, which is to say that there is an exact code duplicate of the production site available in a sandbox. Any transactions made or actions performed on this system are isolated from the main production environment and as such it provides a realistic, but inconsequential environment where merchants can test their system before going live.

How to use the Sandbox

The sandbox provides you with tools to:

A. Check the POST variables, security signature and recurring billing.

B. Test your PayFast integration.

A. Check POST Variables

The sandbox URL is https://sandbox.payfast.co.za, and it allows you to:

  1. Take a tour of the sandbox so you can familiarize yourself with it.
  2. Test the POST variables and determine what the security signature should be.
  3. View the response the ITN received from your server.
  4. Add a passphrase.
  5. View test subscriptions and ad hoc payments.

Sandbox Dashboard

1.The Tour

The tour provides you with a step by step guide on how to use the POST CHECK and ITN tools. The merchant ID and Key provided are those registered to your sandbox account.

2.POST CHECK

The POST CHECK ‘Signature Generator’ tool allows you to determine the signature that should be generated. This is done by inserting the parameter string into the tool and clicking on ‘Generate Signature’.

Signature Generator

The ‘Post Check Form’ tool allows you to test the variables that will be POSTed to PayFast. You can check the ordering, value lengths, if there are any missing fields, as well as the signature generated.

Post check tool

3.ITN

The ITN tool allows you to view the ITNs sent to your server, and the response that we received from your server.

ITN View

4.SETTINGS (Passphrase)

Under settings you can set the passphrase. This would be the ‘password’ that is necessary in order to generate the correct security signature.

Sandbox Settings

5.Recurring Billing

Test subscriptions and ad hoc payments can be viewed as shown, once the test payment is completed. It is possible to cancel and charge both test subscriptions and ad hoc payments (when charging, the ITN is viewed as mentioned above), as well as pause and edit subscriptions. When editing a subscription you can change the amount, number of cycles (payments), next payment date and the frequency.

Edit Subscription

B. Test PayFast Integration

The PayFast sandbox allows you to test your PayFast integration without any money exchanging hands. In order to do this you can set the PayFast module on your site to sandbox/test mode, in the case where a PayFast module is used, otherwise, if developing a custom integration, you can change the redirect URL to the sandbox site (https://sandbox.payfast.co.za/eng/process). In this instance you will also need to change the validate URL, in your notify URL script, to the sandbox site (https://sandbox.payfast.co.za/eng/query/validate). In both cases you will need to use sandbox credentials (which can be obtained from your sandbox account, or from the ‘Testing‘ page.

When conducting a test transaction on your site, you will be redirected to the PayFast sandbox. You may need to enter user credentials, which are as follows:

Username: sbtu01@payfast.co.za

Password: clientpass

Once off Payment

Once you are logged in (either automatically by the system, or after entering the above credentials) to PayFast you will see the below screen, stating that you are in the sandbox/test environment, with the amount given for the transaction, and a PayFast wallet (which is reset to R99,999,999.99 every night). You can complete the test transaction by clicking on ‘Pay Now Using Your Wallet’. The ITN will then be sent to the notify URL before you are redirected to the return URL. You will then be able to view the ITN as mentioned in section A.3 above, if you used your sandbox credentials.

Sandbox Payment Page

Recurring Billing

Once you are redirected to the PayFast sandbox you will see one of the below screen (either for a subscription or ad hoc payment), describing the subscription, as well as providing you with a test credit card and cvv number. In order to make the test payment select the credit card and enter the cvv number provided and click on ‘Pay’. The ITN will then be sent to the notify URL, before you are redirected to the return URL. You will then be able to view the ITN as mentioned in section A.3 above, if you used your sandbox credentials.

Sandbox Recurring Payment Page

Ad Hoc

Sandbox AdHoc Payment Page

Sandbox credentials

Should you not wish to setup a sandbox account, generic sandbox credentials are available with which you can test once off payment integration (to test subscriptions you will need to setup your own sandbox account). These are detailed below:

Merchant account credentials for testing ITN (default):

NAME DESCRIPTION
Username sbtm01@payfast.co.za
Merchant ID 10000100
Merchant Key 46f0cd694581a
PDT Disabled
ITN Use notify_url to test ITN

Sandbox Limitations

The sandbox does not make any connections to external systems and any such functionality which would require it to has been “stubbed” for the sandbox. Most significantly this means that all payments will result in successful transactions.

Buyer registration has been disabled in the sandbox. Please use the generic sandbox credentials detailed above for testing.

Live “Test” Transactions (Fulfilled)

Your integration to the PayFast system can be tested by posting to the sandbox location with the necessary details for your test merchant account. You must then proceed with the payment using the credentials of one of your test user accounts.

Any transactions processed in the sandbox by PayFast:

The live payment engine URL is https://www.payfast.co.za/eng/process

The only real way to “test” whether the full end to end system is working correctly is to actually process some transactions on the live system.

If you have ensured that your inputs to PayFast are correct in test transactions with the sandbox and have ensured that you can handle the appropriate responses, there should be no reason why the live system should perform any differently.

If you wish to test this functionality however, note that any money transferred in testing this way will appear in your wallet and can simply be paid out once you are finished with the testing.

Test Kit

The test kit is a tool designed for you to use in order to become familiar with PayFast integration and test the interaction between your site and PayFast. There are several key differences between the test kit and an actual integration that are highlighted in the readme file, please ensure you read this file before using the test kit.

Download Test Kit

Additional Sample Code

Below are links to additional sample code resources which may aid you with your integration.

PCI Compliance

PayFast is PCI DSS level 1 compliant. PCI DSS stands for Payment Card Industry Data Security Standard and is a PASA (Payment Association of South Africa) regulation in South Africa, this means any company accepting credit card payments on their website needs to comply in some way. Outsourcing your card payments to PayFast means you do not have to be concerned about the laborious process of being PCI compliant, and can rest assured in the knowledge that card information is handled securely.

For more information on PCI compliance you can refer our blog post, or to the PCI security standards best practices. You can, if need be, take the PCI self assessment questionaire.

FAQs

Landing Page Errors

Why do I get a signature mismatch?

This is most likely caused if you generated the MD5 hashed string with the variables in the wrong order, they need to be in the order as they appear in the tables on the checkout page.

Another reason could be that you have not urlencoded the variable values and trimmed all white spaces off the ends using php’s trim() function.

The resultant URL encoding must be in upper case (eg. http%3A%2F%2F), and spaces encoded as ‘+’.

All POSTed values must adhere to the format as specified in the tables on the checkout page, any excess or invalid characters will cause this error.

The passphrase, if used, must be identical on your PayFast account as well as the site, and may consist only of letters, numbers and -_/.

Should you wish to setup recurring billing, then you will need to have a passphrase set and recurring billing enabled on your account in order to prevent the signature mismatch error.

Why is my account “not able to receive payments”?

This could be due to your account not being verified, or the required payment method is not active on your account. It is not possible to pay yourself via PayFast, if you use the email address to which your account is registered to make a payment from your site then you will receive this error. You must also ensure that ad hoc billing or subscriptions are enabled on your account should you wish to setup recurring billing in order to prevent this error.

What causes an invalid URL error?

The PayFast system will pick up on ‘local’ or ‘localhost’ in the return, cancel and notify URLs and throw the invalid URL error. This is because it is not possible to test the ITN locally due to no server to server communication. The site needs to be web accessible in order for the PayFast integration to work as expected.

What causes the error ‘The supplied variables are not according to specification’?

This error is thrown if any of the POSTed values are incorrect, for instance, if the merchant_id or merchant_key is incorrect (possibly due to using a sandbox credentials on the live site), the following error will be thrown ‘The supplied variables are not according to specification: merchant_key: Merchant key is invalid’. The error will highlight which variables are incorrect or missing, you will then need to ensure that the POST form is adjusted accordingly.

ITN Callback errors

I do not receive the ITN callback, why?

The URL specified by the ‘notify_url’ parameter in the POST form may not be reachable. To test this navigate to your notify URL and ensure you receive a 200 response. Also see ‘Sandbox Tools and Testing’ for checking the notify URL response. Any response other than a 200 would need to be corrected. If the ITN receives a 500 response, or no response, you will need to contact your host in order to resolve this.

The other reason the notify URL may be unreachable would be the use of an incorrect port. PayFast makes use of ports 80, 8080, 8081 and 443 only.

What causes the ITN security check errors?

Invalid signature

This would be caused by the incorrect use of the passphrase, or the incorrect order of variables in the string that is MD5 hashed to generate the signature.

Bad access of page

This error is caused either by the notify URL not responding with a 200 OK, or if the valid data security check fails. The valid data security check confirms that the data received by the notify URL matches the data sent by PayFast. You will need to ensure that CURL is enabled on your server and setup to be able to receive external data.

Amount mismatch

This error is due to the amount sent in the ITN not matching the amount stored in your DB for the transaction in question.

Bad source IP address

This error is caused by the ITN not being received from a specified PayFast source. This is often due to the use of a proxy server.