In this article you will be going to know:


What is the Instant Payment Notification (IPN)?


Instant Payment Notification (IPN) is the payment status notification to the configured URL and it is a pure server-to-server connection (i.e: It is not a browser-based request).

As soon as a transaction is created or altered, IPN will instantly send a notification to the merchant’s specified IPN Listener URL, which can have any code that will assist in updating ERP or dependent systems. Alternatively, you may wish to save this information in your local database.


How to configure a new IPN?

  • Include a callback URL in the transaction request, and that will be used as an IPN URL for that transaction and/or: 


  • Add manual IPN configs in the dashboard, and those will also run for each transaction, for all transaction events. You can do that simply by navigating to your merchant Dashboard > Developers > Payment Notification > Configuration.
    You can control what notification type to receive from Paytabs. Paytabs server will post data to the IPN listener whenever the selected event occurs on your account (based on the IPN configuration).


The IPN URL must be HTTPS otherwise the IPN body will be empty, for security reasons.




How does the IPN service work?


The IPN will be triggered as soon as the transaction is completed and expects to get a ‘200 OK’ response from their site. If it does not, it goes into a queue to try again. It will be retried up to 5 times, with an increased delay between each attempt. Until it either gets a 200 OK response or the retry count is exceeded. 


If the IPN does not get the ‘200 OK’ response in all of its attempts, an entry will be added to the transaction notes showing this, so we have a record that it was attempted and failed to get the correct response.


IPN vs Callback:


Callback: is a one-time IPN service, and the callback URL is passed with each payment API request in case of wanting to use the service via Callbacks.


IPN: is called whenever an event happens on Paytabs’ server and the IPN URL is configured in the merchant dashboard.


Enable Callback‘: callback is invoked AND IPN is invoked.
Disable Callback‘: callback is invoked if passed with parameters and IPN is ignored.



Below are different scenarios of IPN/Callback possible configurations and the expected behavior:


Callback
IPN
Response/Expected Behavior
NullNullNo Response
URL 1Null
(with_callback = true or false)
Respond to URL 1
NullURL 2
(with_callback = true or false)
Respond to URL 2
URL 1URL 2
(with_callback = false)
Respond to URL 1
URL 1URL 2
(with_callback = true)
Respond to URL 1 & URL 2



How to Configure UserAgent Sent in IPN Request Headers?


The User-Agent header is an HTTP header intended to identify the user agent responsible for making a given HTTP request which in this case PayTabs servers, below you can find the steps needed to edit the UserAgent value sent with any IPN request:

1- From the Payment Notification view nvaigate to IPN UserAgnt section then click on Edit:


2- You will be redirected to IPN UserAgent Header page, from there you will be able to choose on of the available uaser agents and then click on Update to save the updated value as shown below:




3- Finally, once you update the UserAgent, you will be able to view it from the payment notification page and it will be sent within each IPN request as shown below:


Sample IPNs Response Payload:

Default Web JSON Option

{
    "tran_ref": "TST2100600035019",
    "cart_id": "cart_11111",
    "cart_description": "Description of the items/services",
    "cart_currency": "AED",
    "cart_amount": "12.3",
    "tran_currency": "AED",
    "tran_total": "12.30",
    "customer_details": {
        "name": "fff sss",
        "email": "[email protected]",
        "phone": "0522222222",
        "street1": "address street",
        "city": "dubai",
        "state": "DU",
        "country": "AE",
        "ip": "92.98.175.176"
    },
    "shipping_details": {
        "name": "wajih last1",
        "email": "[email protected]",
        "phone": "971555555555",
        "street1": "street2",
        "city": "dubai",
        "state": "DU",
        "country": "AE",
        "ip": "92.98.175.176"
    },
    "payment_result": {
        "response_status": "A",
        "response_code": "G27743",
        "response_message": "Authorised",
        "cvv_result": " ",
        "avs_result": " ",
        "transaction_time": "2021-01-06T10:09:03Z"
    },
    "payment_info": {
        "card_type": "Credit",
        "card_scheme": "Visa",
        "payment_description": "4111 11## #### 1111",
        "expiryMonth": 11,
        "expiryYear": 2022
    }
}

Basic Web JSON Option

{
  "tran_ref": "TST2100600035019",
  "merchant_id": 1842,
  "profile_id": 47170,
  "cart_id": "cart_11111",
  "cart_description": "Description of the items/services",
  "cart_currency": "AED",
  "cart_total": "12.3",
  "tran_currency": "AED",
  "tran_total": "12.30",
  "tran_type": "Sale",
  "tran_class": "ECom",
  "customer_name": "fff sss",
  "customer_email": "[email protected]",
  "customer_country": "AE",
  "customer_ip": "92.98.175.176",
  "response_status": "A",
  "response_code": "G27743",
  "response_message": "Authorised",
  "acquirer_message": "",
  "acquirer_rrn": "",
  "card_type": "Credit",
  "payment_description": "4111 11## #### 1111",
  "expiry_month": 11,
  "expiry_year": 2022
}

IPN Security:


To Keep your IPN URL secure and to ensure that the request is genuine, we are sending a custom header Signature including HMAC signature of the entire request body hashed by Profile ServerKey


How to validate calculate the Signature locally:

  1. Calculate the Hash (sha256 algorithm) of the whole payload received.
  2. Compare the calculated in the step 1 with the signature payload received. 


Sample PHP Code

function is_genuine($payload, $requestSignature, $serverKey)
    {
        $signature = hash_hmac('sha256', $payload, $serverKey);

        if (hash_equals($signature, $requestSignature) === TRUE) {
            // VALID Redirect
            return true;
        } else {
            // INVALID Redirect
            return false;
        }
    }