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.
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 2018-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
- Variables POSTed to PayFast from merchant website.
- Payment collected from customer through payment engine, and the ITN is posted to the
notify_url
- ITN process completes
- Customer displayed success screen on PayFast
- Customer redirected to
return_url
on merchant website - 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
- Variables POSTed to PayFast from merchant
- Buyer cancels payment on PayFast during any step
- Customer displayed unsuccessful screen on PayFast
- 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 . |
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="0823456789">
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 valid 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, 10 char |
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 |
- 1This is a Boolean variable whose value must be 1 (on) or 0 (off).
- 2A variable can be specified globally on your account or overridden on a per transaction basis. The value provided during a transaction overrides the global setting.
Set Payment Method
<input type="hidden" name="payment_method" value="cc">
NAME | DESCRIPTION | REQUIRED | FORMAT |
---|---|---|---|
payment_method | When this field is set, only the payment method specified can be used when the buyer reaches PayFast. If this field is blank, or not included, then all available payment methods will be shown. The values are as follows:
|
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:
|
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:
|
Yes (For Ad Hoc only) | 2 |
Split Payment Details
Checkout page variable
For a split payment, we make us of the hidden variable called setup. Note that this will not be included in the signature. The value for setup needs to contain the JSON encoded payload split_payment as per the table below.
JSON variables
Split Payments
<input type="hidden" name="setup" value='{ "split_payment" : {
"merchant_id":10000105,
"percentage":10,
"min":100,
"max":100000}}' >
NAME | DESCRIPTION | REQUIRED | FORMAT |
---|---|---|---|
merchant_id | The receiving merchant | Yes | numeric, 8 char |
amount | The amount in cents (ZAR), that will go to the receiving merchant | Yes* (unless only percentage is used) | numeric |
percentage | The percentage allocated to the receiving merchant | Yes* (unless only amount is used) | numeric, 2 char |
min | The minimum amount that will be split, in cents (ZAR) | Optional | numeric |
max | The maximum amount that will be split, in cents (ZAR) | Optional | numeric |
* At least one of these needs to be sent to us. It is not mandatory to send both, but if you do, PayFast will calculate the split amount using both the percentage and the amount variables submitted to us.
Rules for split payments
- You will need to contact PayFast to enable this on your account.
- Only one receiving merchant can be allocated a split payment, per transaction.
- All amounts used for the split must be in cents.
- Using this direct request method for splitting a payment will take precedence over any previously submitted split data sent or set up by the PayFast support team in the database.
- If both percentage and amount are specified, then the percentage will be deducted first, and then the amount will be deducted from the rest.
- If the split amount is smaller than the min, then the min will be used instead of the split amount.
- If the split amount is bigger than the max, then the max will be used instead of the split amount.
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. This hash will be regenerated by the PayFast engine and the values compared to ensure the integrity of the data transfer. |
Yes | MD5 hash, characters must be in lower case |
<?php
// Construct variables
$cartTotal = xxxx;// This amount needs to be sourced from your application
$data = array(
// Merchant details
'merchant_id' => '10000100',
'merchant_key' => '46f0cd694581a',
'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 parameter string
$pfOutput = '';
foreach( $data as $key => $val )
{
if(!empty($val))
{
$pfOutput .= $key .'='. urlencode( trim( $val ) ) .'&';
}
}
// Remove last ampersand
$getString = substr( $pfOutput, 0, -1 );
//Uncomment the next line and add a passphrase if there is one set on the account
//$passPhrase = '';
if( isset( $passPhrase ) )
{
$getString .= '&passphrase='. urlencode( trim( $passPhrase ) );
}
$data['signature'] = md5( $getString );
This array can then also be used in generating the form output.
<?php
// 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
Common causes of a failed integration / signature mismatch
The following will cause a signature mismatch or a payment to fail:
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.
A required field is missing
A field is greater than the allowable character length
Any of the fields containing non-allowable characters
The Parameter string has been URLencoded incorrectly. The resultant URLencoding has to be show upper case, for example,
http%3A%2F%2
and not lower case likehttp%3a%2f%2f
.The Parameter 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.
Success page example (Return 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
Notify Page (ITN)
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:
- Receive the data posted by PayFast
- Notify PayFast that the information has been received
- 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
- Verify that the order hasn’t been processed already
- 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 url encoded 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, characters must be in lower case |
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
<?php
header( 'HTTP/1.0 200 OK' );
flush();
Store the posted data in:
<?php
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
<?php
// $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
<?php
// 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:
- www.payfast.co.za
- w1w.payfast.co.za
- w2w.payfast.co.za
- sandbox.payfast.co.za
Security step three
<?php
$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
<?php
// 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, 1 );
// 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 | This option determines whether curl verifies the authenticity of the peer’s certificate. The default value is 1 . |
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:
|
Step three
<?php
$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
<?php
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:
<?php
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)
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:
- HTTP GET is used retrieve a resource.
- HTTP PUT is used where an action is required on a resource.
- HTTP POST is used where a resource needs to be created.
- HTTP PATCH is used to update all / subset of a resource.
Minimum Requirements
At a minimum, the following must be provided to gain access to the API ecosystem:
- A valid and an API enabled PayFast merchant account
- A passphrase as set on the merchant account settings page
- PayFast merchant ID
- The version of the API you want to interact with
- A valid merchant signature
- 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:
application/x-www-form-urlencoded Essentially one big query string where all name / value pairs are separated by the ‘&’ symbol, with an equal (=) symbol between name and value. This is similar to submitting the traditional HTML FORM via POST (eg. frequency=3&cycles=12…).
application/json Fields should be passed in as a single-level JSON representation. Example to the right in the Json tab.
<?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 ) .'&';
}
}
// Remove the last '&' 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 Signature | API Signature | |
---|---|---|
Merchant ID variable name | merchant_id | merchant-id |
Order of the string variables (before hashing) | The variables need to be ordered correctly, as per the checkout page documentation | The data is ksorted, in other words, the variable are ordered alphabetically |
Amount | The 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:
- Login to PayFast using their merchant credentials.
- Clicking on ‘Settings’, and then ‘Edit’ under the ‘Security Pass Phrase’ section.
- 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 |
valid email address | |
numeric | numeric digits, 0-9 |
url/alphanumericspecial | alphanumeric and special characters _-/:&?#=+ |
MD5 hash (characters must be in lower case) | 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.
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:
- Gravity Forms
- WP Invoice
- Paid Membership Pro
- WHMCS (Uses Ad Hoc)
- WooCommerce Subscriptions (Uses Ad Hoc, managed by WooThemes)
- Shopify
- OpenCart
- Drupal Commerce
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
- Cancel
Any recurring billing type may be cancelled from the PayFast merchant account. The buyer will be notified via email of this action.
- 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
"API V1"
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/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, characters must be in lower case |
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, characters must be in lower case |
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, characters must be in lower case |
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, characters must be in lower case |
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, characters must be in lower case |
cycles | Body, the number of cycles for the subscription. | Optional | numeric |
frequency | Body, the frequency for the subscription | Optional | numeric |
run_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, characters must be in lower case |
CURL Examples
The examples below demonstrate cURL calls containing the following:
- HTTP Method: PUT
- URL: https://api.payfast.co.za/
- Endpoint: subscriptions/[Token]/[Action]
The calls are made to v1 (version 1) of the API. The merchant-id, version, timestamp and signature are all included as request headers.
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, 1 );
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:
- code: The HTTP status code for the result
- status: A more verbose description of the result
- data: Will contain a response of either true or false for the action and may also contain one or more description(s) for the reason of the result
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
"API V1"
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/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, characters must be in lower case |
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, characters must be in lower case |
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, characters must be in lower case |
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, characters must be in lower case |
CURL Examples
The examples below demonstrate cURL calls containing the following:
- HTTP Method: POST
- URL: https://api.payfast.co.za/
- Endpoint: subscriptions/[Token]/[Action] The calls are made to v1 (version 1) of the API. The merchant-id, version, timestamp and signature are all included as request headers. The amount, item_name and item_description are included in the request body.
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, 1 );
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:
- code: The HTTP status code for the result
- status: A more verbose description of the result
- data: Will contain a response of either true or false for the action and may also contain one or more description(s) for the reason of the result
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, characters must be in lower case |
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, characters must be in lower case |
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, characters must be in lower case |
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
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, characters must be in lower case |
date | Body, date of the time period. Defaults to current month | Optional | YYYY-MM-DD |
Credit Card 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 credit card 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, characters must be in lower case |
API Validation
CURL Examples
The example below demonstrates a cURL call containing the following:
- HTTP Method: GET
- URL: https://api.payfast.co.za/transactions/history
- Endpoint: /daily. The call is made to v1 (version 1) of the API. The merchant-id, version, timestamp and signature are all included as request headers. The date and format are included in the request body.
<?php
// URL for curl_init
$url = "https://api.payfast.co.za/transactions/history/daily?date=2017-01-01";
// Set up cURL
$ch = curl_init( $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_HEADER, false );
curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, 1 );
curl_setopt( $ch, CURLOPT_TIMEOUT, 60 );
curl_setopt( $ch, CURLOPT_CUSTOMREQUEST, "GET" );
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. |
Split payments
Engines available for splitting
PayFast has two systems facilitating split payments; the payment engine, where the buyer initiates the transaction, and the recurring engine, where recurring subscriptions and ad hoc payments are handled automatically.
The rules governing these two systems’ split payments are basically the same. However, while there are similarities in the implementation methods of these two systems, there are slight differences. In general, where functionality overlaps, the rules and implementation methods are as similar as possible.
Basics rules of split payment
- You will need to contact PayFast to enable this on your account.
- Only one receiving merchant can be allocated a split payment, per split transaction. Therefore the merchant ID of this receiving merchant is mandatory.
- All amounts used for the split must be in cents.
- The method used will be implemented by PayFast according to precedence.
- If both percentage and amount are specified, then the percentage will be deducted first, and then the amount will be deducted from the rest.
- If the split amount is smaller than the min, then the min will be used instead of the split amount.
- If the split amount is bigger than the max, then the max will be used instead of the split amount.
Methods of facilitating a split
1. Direct request method
When the split data is embedded in the call to us, this will take precedence over the other methods.
2. Original transaction method
When the split data was sent to us via the direct method, this data will be extracted and used, upon a subsequent transaction.
3. Database method
When the split data has been set up in the database by contacting PayFast support, then we will use this data for all the merchant’s transactions, if neither of the preceding methods are being utilised.
Engine type and method support
Each engine supports the various methods of facilitating a split as follows.
The payment engine supports
All once off transactions as follows:
- Direct request method
- Database method
The recurring engine supports
Subscription based payments as follows:
- Direct Request method
- Original transaction method
- Database method
Ad hoc agreements as follows:
- Direct Request method
- Original transaction method
- Database method
Direct request method
For a request based split, a json encoded payload is sent to PayFast with the other transaction variables, in a variable called ‘setup’.
Variables to be submitted
The following variables are used for a split payment via the direct request method.
Split payment variable in the checkout form
<input type="hidden" name="setup" value='{ "split_payment" : {
"merchant_id":10000105,
"percentage":10,
"min":100,
"max":100000}}' >
NAME | DESCRIPTION | REQUIRED | FORMAT |
---|---|---|---|
merchant_id | The receiving merchant | Yes | numeric, 8 char |
amount | The amount in cents (ZAR), that will go to the receiving merchant | Yes* (unless only percentage is used) | numeric |
percentage | The percentage allocated to the receiving merchant | Yes* (unless only amount is used) | numeric, 2 char |
min | The minimum amount that will be split, in cents (ZAR) | Optional | numeric |
max | The maximum amount that will be split, in cents (ZAR) | Optional | numeric |
* Note that amount and percentage are used to calculate the total split amount that the receiving merchant will get. At least one of these needs to be sent to us. It is not mandatory to send both, but if you do, you will need to keep in mind that we will calculate the split amount using both the percentage and the amount variables submitted to us.
Example calculations
The following examples show an HTML based implementation. For each of them, we always show the receiving merchant id since it is mandatory for a successful split. We also assume an original transaction amount of ZAR 400 is used, and we convert that amount to cents for the split calculation (40,000 cents).
Example 1 - All variables have been sent
<input type="hidden" name="setup" value='{ "split_payment" : {
"merchant_id":10000105,
"percentage":10,
"amount":500,
"min":100,
"max":100000}}' >
Example 1 - All variables have been sent
{ "split_payment" : {
"merchant_id":10000105,
"percentage":10,
"amount":500,
"min":100,
"max":100000 } }
In this example, all the possible split data variables have been provided, specifically percentage (10%), amount (500 cents), min (100 cents) and max
(100,000 cents).
For the calculation, the percentage amount will be 4,000 cents (10% of 40,000 cents).
Split amount will then be calculated as:
(transaction amount – percentage amount) – split data amount)
(40,000 – 4,000) – 500)
= 35,500 cents
While min and max amounts are optional, they have been sent in this example so we compare them with the split amount.
The split amount is not smaller than the min, so the min will not be used.
The split amount is not bigger than the max, so the max will not be used.
The split amount, therefore, stays as calculated at 35,500 cents (ZAR 355).
Example 2 - Percentage, min and max have been sent
<input type="hidden" name="setup" value='{ "split_payment" : {
"merchant_id":10000105,
"percentage":10,
"min":100,
"max":20000}}' >
Example 2 – Percentage, min and max have been sent
{ "split_payment" : {
"merchant_id":10000105,
"percentage":10,
"min":100,
"max":20000 } }
In this example, the percentage is provided, but not the amount.
Split amount will then be calculated as:
(transaction amount – percentage amount)
(40,000 – 4,000)
= 36,000 cents
The split amount is not smaller than the min, so the min will not be used.
The split amount is bigger than the max, so the max will be used instead of the calculated amount.
The split amount, therefore, comes to 20,000 cents (ZAR 200).
Example 3 - Amount has been sent
<input type="hidden" name="setup" value='{ "split_payment" : {
"merchant_id":10000105,
"amount":500 }}' >
Example 3 – Amount has been sent
{ "split_payment" : {
"merchant_id":10000105,
"amount":500 } }
In this example, only the amount is provided.
Split amount will then be calculated as:
(transaction amount – split data amount)
(40,000 – 500)
= 39,500 cents
The split amount, therefore, comes to 39,500 cents (ZAR 395), as no min or max has been provided.
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.158) |
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
The sandbox
The PayFast sandbox is an exact code duplicate of the production site, available for running test transactions with.
Any transactions made or actions performed on this system, are isolated from the main production environment, while providing a realistic experience of your integration with PayFast, before going live.
Sandbox url:
Using our sandbox, you will be able to test your integration, once off payments and recurring payments, as well as receive ITNs, without any money changing hands.
It makes use of a single payment method – a wallet with a substantially large dummy balance. While it is not possible to utilise the other payment methods in sandbox, this will not affect your integration.
The sandbox provides you with tools to check your POST variables, your parameter string generated and your security signature generated.
Sandbox Limitations
- The sandbox ITN will only be sent once.
- The sandbox does not make any connections to external systems (allowing all payments to be successful).
- Buyer registration has been disabled in the sandbox. Please use the generic buyer details, provided here in these instructions, for testing.
Tools to test your integration
Getting started with sandbox
We recommend that you take a tour of the sandbox so you can familiarize yourself with it.
The tour provides you with a step by step guide on how to use the sandbox tools.
To find this, you will first need to gain access to your unique sandbox account at https://sandbox.payfast.co.za.
Simply insert your email address and proceed, to enter the sandbox.
Then click on ‘The Tour’ button at the top left.
The Post Check Tools
Check your POST variables by clicking on ‘Open Tools’ at the top right of your sandbox dashboard.
The ‘Signature Generator’ tool allows you to determine the signature that should be generated. Simply insert your parameter string and then click ‘Generate Signature’.
The ‘Post Check Form’ tool allows you to check the variables that will be posted to PayFast:
- Check the order
- Check the length of the values
- Check if there are any missing fields
- Check the signature generated
Simply insert the values into the relevant fields and then click ‘Post To Sandbox’.
The ITN Tool
By clicking ‘View All’ you will be able to see all the ITNs sent to your server, and the response that we received from your server.
Setting a Passphrase
Under ‘Settings’, you can set a passphrase. This is required for all subscription and ad hoc payments. It is the salt added to your parameter string before generating the signature.
Recurring Billing Tools
Subscriptions and ad hoc payments completed in sandbox can be viewed on your sandbox account. Just like on the PayFast merchant account, you will be able to cancel, charge, pause and edit subscriptions. For ad hoc payments, you will be able to charge and cancel them.
When editing a subscription you can change the amount, the number of cycles (payments), the next payment date and the frequency.
Run a test transaction
- You will need to use sandbox credentials, obtained from your own sandbox account, or you can use the default credentials below:
NAME | DESCRIPTION |
---|---|
Merchant ID | 10000100 |
Merchant Key | 46f0cd694581a |
2. Set your integration to sandbox/test mode by changing the redirect URL to https://sandbox.payfast.co.za/eng/process.
3. When making use of the ITN, change the validate URL, in your notify URL script, to https://sandbox.payfast.co.za/eng/query/validate.
4. When conducting a test transaction on your site, you will be redirected to the PayFast sandbox. You may need to enter buyer credentials, as follows:
NAME | DESCRIPTION |
---|---|
Username | sbtu01@payfast.co.za |
Password | clientpass |
5. You will then see that you are in the sandbox test environment.
For a once off payment, you will see the amount given for the transaction, and a PayFast wallet (which is reset to R99,999,999.99 every night). Complete the test transaction by clicking on ‘Pay Now Using Your Wallet’.
For a recurring payment, you will see a message about the recurring payment, as well as 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’.
6. The ITN will then be sent to the notify URL and you will be redirected to the return URL.
7. View the ITNs from your sandbox dashboard by clicking ‘View All’ in the ITN section of your sandbox dashboard.
Live “test” transactions (fulfilled)
The only real way to know 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.
The live payment engine URL is:
If you wish to test this functionality, keep in mind that any money transferred by testing this way will appear in your PayFast wallet. It can then simply be paid out, once you are finished with the testing.
Please note that any “test” transactions processed this way will be subject to the agreed transaction fees which can unfortunately not be refunded.
Test Kit
The test kit is a tool designed for you to become familiar with the PayFast integration and test the interaction between your site and PayFast.
Key differences between the test kit and an actual integration
For a live integration, the checkout page needs to include the required fields for the checkout page and then submit this to PayFast. Here in the test kit, the submit code is located in signature.php page where we are showing the parameter string and signature. This flow is for test purposes only.
For a live integration, the passphrase needs to be set in the admin configuration, and referenced as a variable when needed. It is not part of the checkout page form, or hard-coded in the notify page, as we do here.
For a live integration, the following will be hidden, either set in configuration or hard-coded in your integration:
- The Merchant ID and Merchant Key
- The URLs (Return, Cancel and Notify)
- The Email confirmation fields
4. The Merchant Payment ID will be generated by the merchant’s site.
Sample code
The following code resources have been kindly contributed by fellow developers for your convenience:
DOWNLOAD | CONTRIBUTER |
---|---|
PHP ITN | PayFast |
JSP ITN | John Eatwell |
VB.Net | Jose Heitor |
C#.Net | Thabo Letsoalo |
C#.Net, (View demo) | Louis Lewis |
Ruby on rails | Pawel Janiak |
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.
You will need to ensure that the MD5 hash characters are in lower case.
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.
How to get your plugin listed on our shopping carts page
If you have developed a PayFast plugin and would like it listed on our shopping carts page, please visit this link and fill out the required information.