Payment Response

Payment Response

Once the payment is complete the user is redirected to the return_url configured by you. Following is the typical destination where the user is taken to:

HTTP GET https://merchant.shop.com/paymentresponse/handler?order_id=order_id_007&status=CHARGED&status_id=21&signature=euKzwwiUztPPg3MCEYpgKZfcyTr1uQq1hzKkhP8G1vQ%253D&signature_algorithm=HMAC-SHA256

Please note that the parameters are sent using HTTP GET.

Transaction Status codes and their meaning

Status ID Meaning
NEW 10 Newly created order
PENDING_VBV 23 Authentication is in progress
CHARGED 21 Successful transaction
AUTHENTICATION_FAILED 26 User did not complete authentication
AUTHORIZATION_FAILED 27 User completed authentication, but bank refused the transaction
JUSPAY_DECLINED 22 User input is not accepted by the underlying PG
AUTHORIZING 28 Transaction status is pending from bank

Transaction is successful only if you receive CHARGED as the value in status. For all other cases, you must assume that the payment has failed.

Status Verification

After the redirect, the authenticity should be verified using the signature in the response. The signature parameter in the return_url gives the HMAC signature computed using the algorithm specified by the signature_algorithm parameter. The HMAC is calculated using the following algorithm:

  • Get all the parameters (key=value pairs) from the return_url.
  • It is assumed that the parameters in the return_url are converted into key/value pairs.
  • All parameters except signature and signature_algorithm is used in the following steps.
  • Percentage encode each key and value pairs.
  • Sort the list of parameters alphabetically (ASCII based sort) by encoded key.
  • For each key/value pair:
    • Append the encoded key to the output string.
    • Append the '=' character to the output string.
    • Append the encoded value to the output string.
    • If there are more than one key/value pairs, append a '&' character to the output string.
  • Percentage encode the generated string.
  • The HMAC of the string can be calulated using the secret key configured in merchant settings.
  • Percentage encode the generated hash, validate against the signature in response (the signature should percentage decoded once before comparing with the generated hash).

To enable the signature generation at JusPay end for the payment response, you must first create a response key here: https://merchant.juspay.in/settings/api-keys. Once you have created a key successfully, navigate to General settings section and select "Yes" for the option "Use signed response".

Once you have completed the above two steps, all the redirection to your website from JusPay will have signature and the algorithm.

Signature algorithm used by JusPay is HMAC-SHA256. The algorithm is explicitly passed as an argument so that verification is accurate. Newer or more secure algorithms might be introduced in future.

It is also possible to check the status using the /order/status API. Based on the response object, a success confirmation page or failure message can be shown to the customer. Since this is an authenticated call, done from the server side, signature verification is not required.

Python example for HMAC signature verfication:

import urllib
import hmac
import hashlib
import base64

key = 'your_secret_key'
# params := key/value dictionary except `signature`
#           and `signature_algorithm`
# signature := "5ctBJ0vURSTS9awUhbTBXCpUeDEJG8X%252B6c%253D"
# signature_algorithm := "HMAC-SHA256"

encoded_sorted = []
for i in sorted(params.keys()):
    encoded_sorted.append(urllib.quote_plus(i) + '=' + \
      urllib.quote_plus(params.get(i)))

encoded_string = urllib.quote_plus('&'.join(encoded_sorted))
dig = hmac.new(key, \
              msg=encoded_string, \
              digestmod=hashlib.sha256).digest()

assert urllib.quote_plus(base64.b64encode(dig).decode()) == \
       signature

Ruby example for HMAC signature verfication:

require 'uri'
require 'cgi'
require 'openssl'
require 'Base64'

key = "your_secret_key"
# params := key/value hash except `signature`
#           and `signature_algorithm`
# signature := "5ctBJ0vURSTS9awUhbTBXCpUeDEJG8X%252B6c%253D"
# signature_algorithm := "HMAC-SHA256"

encoded_sorted = []
params.keys.sort.each { |k| encoded_list << URI.encode(k) + \
                        "=" + URI.encode(params[k]) }

encoded_string = CGI.escape(encoded_sorted.join("&"))

hash_string = CGI.escape(Base64.encode64(OpenSSL::HMAC. \
                        digest(OpenSSL::Digest.new('sha256'), \
                        key, data)).strip())
hash_string == URI.decode(return_url). \
                  split("signature=")[1].split("&")[0]

You can also read the status from the server using /order/status API explained here. Status along with many other data will be returned as part of the /order/status API. This is an alternative to the GET params in return_url.

Failing to do status verification will result in hackers gaming your system. So, please ensure that status verification is in place before you go LIVE with us.

Example request

curl -u api_key: \
  https://api.juspay.in/order/status?order_id=wv_test_ord_110011&merchant_id=skyview

HTTP Response

{
  "merchant_id": "wv_test",
  "order_id": "wv_test_ord_110011",
  "customer_id": "wv_test_user@gmail.com",
  "product_id": "",
  "status": "CHARGED",
  "status_id": 21,
  "amount": 400,
  "currency": "INR",
  "refunded": false,
  "amount_refunded": 0,
  "return_url": "http://skyview./order/cc-confirm",
  ....
}

The above response is truncated for brevity. However, as you can see above, the status was received as CHARGED. This indicates that the payment was successful and so, you can proceed with the fulfillment of the order.

Status Conflicts

In a typical payment using ExpressCheckout, the control goes from your Checkout Page to Juspay's servers,then to Payment Gateway(PG) or Aggregator and then to the Bank pages for the second factor authentication. You will then be redirected to the PG page after the payment is authenticated and authorized, and then back to your inventory confirmation page. In all the above cases there can be timeouts due to bad network or bank/PG downtime. This leads to temporary status conflict between Juspay and/or the PG/bank, as we missed the updated response after the payment.

These conflicts are reconciled periodically, when we get the updated status from the PG. The updated status for an order will be notified to the merchant via emails or webhooks. You can also poll the current status of the order using /order/status API to check for an update. This can also be triggered individually for each order, from the order details page in the merchant dashboard.

To enable email alerts, please contact support@juspay.in

The notification will be sent when the status changes from PENDING_VBV/AUTHORIZATION_FAILED to CHARGED.

Webhooks

After the completion of every payment/refund call, Juspay will provide a direct notification to your server regarding the event. These are called Webhooks. You must configure a valid HTTP endpoint that is reachable from our servers to consume these notifications. Our servers will push data using HTTP POST call to your endpoint.

The following events will trigger a webhook call from our end to your server:

  • Successful payment
  • Successful refund
  • Payment failure
  • Refund failure

Why webhooks?

Payment redirection using customers' browsers are not reliable all the time. There would be instances where customers' devices would be on low quality connections and thereby the final redirection might not succeed. In such cases, a webhook call can help you complete the order for the customer.

But care must be taken while consuming the webhook data. Since you might receive both webhook and customer redirection around the same time, you should not process the order twice. This is true for most cases.

In very rare scenarios, our webhook call pertaining to an order might hit your server more than once. This can happen due to network fluctuations. So, care must be taken to ensure that such scenarios are handled too.

Events

Event Name Description
ORDER_SUCCEEDED Generated when payment is successful for an order
ORDER_REFUNDED Generated when a refund is successful
ORDER_FAILED Generated when an order payment fails
ORDER_REFUND_FAILED Generated when an order refund fails
TXN_CREATED Generated when payment is initiated for an order
REFUND_MANUAL_REVIEW_NEEDED Generated when the refund status is ambigious and the refund has to be manually reconciled by the merchant with the payment processor.

Response structure for Webhook

{
  "id": "evt_gsu1c0r7umcfrxeb",
  "date_created": "2015-06-03T10:42:25Z",
  "event_name": "ORDER_SUCCEEDED",
  "content": {
    "order": {
        /* Complete order data as obtained from /order/status API */
    }
}

Handling Failures

If your server is not reachable when we are attempting webhook notification, then we would reattempt to deliver it for another 2 times. The interval between each invocation is 5 minutes. So, extended downtime of your servers will result in lost notifications.