Step by Step guide for prepaid payment flow

Step1: Fill the forms as given below so that the integration team can assist you better with the integration

a.) Switch Integration Prerequisites

📘

We don't support any e-commerce website platforms like Shopify, Magento, Opencart websites with direct prepaid integration.

Step 2: Getting ready

  • Collect the following details from PhonePe's team:
    • Merchant ID
    • Salts
    • AppuniqueId
    • PhonePe app's APK & IPA files can be found here.

Step 3: Test the flow inside the PhonePe Application

How to test the flow inside PhonePe app can be found here

a.) Download the Apk and enter the static URL
b.) Enter the domains.
Request you to whitelist all the domains .
c.) Enter appunique ID (Shared by PhonePe team on the email and will be unique for all the merchants.)

📘

Note: The payment flow will work only inside the PhonePe application. A merchant needs to test the flow inside PhonePe application.

Step 4: Go through the API Documentation and Expectations

Step 5: Integrate with the SSO flow

The details of the Single Sign-On can be found here.

Step 6: Integrate with transaction initiate API

The API needs to be called from the backend server of the merchant. The API contracts can be found here.

a.) Download from sample code from the link as :

URL: https://phon.pe/qn8z49r9
Password: buEomDIbPC

b.) Integrate with payment initiate API

How to do the same in Postman can be found below :

a.) URL : https://apps-uat.phonepe.com/v3/transaction/sdk-less/initiate

b.) transactionContext is base64encoded cart details which will be unique for each merchant. 

Example in above the cart details is shopping : 

Base64encoded of the below cart details : 

{
    "orderContext": {
        "trackingInfo": {
            "type": "HTTPS",
            "url": "https://google.com"
        }
    },
    "fareDetails": {
        "totalAmount": 3900,
        "payableAmount": 3900
    },
    "cartDetails": {
        "cartItems": [{
            "category": "SHOPPING",
            "itemId": "1234567890",
            "price": 3900,
            "itemName": "TEST",
            "quantity": 1
        }]
    }
}

The base 64 encoded value will be : 
ewoJIm9yZGVyQ29udGV4dCI6IHsKCQkidHJhY2tpbmdJbmZvIjogewoJCQkidHlwZSI6ICJIVFRQUyIsCgkJCSJ1cmwiOiAiaHR0cHM6Ly9nb29nbGUuY29tIgoJCX0KCX0sCgkiZmFyZURldGFpbHMiOiB7CgkJInRvdGFsQW1vdW50IjogMzkwMCwKCQkicGF5YWJsZUFtb3VudCI6IDM5MDAKCX0sCgkiY2FydERldGFpbHMiOiB7CgkJImNhcnRJdGVtcyI6IFt7CgkJCSJjYXRlZ29yeSI6ICJTSE9QUElORyIsCgkJCSJpdGVtSWQiOiAiMTIzNDU2Nzg5MCIsCgkJCSJwcmljZSI6IDM5MDAsCgkJCSJpdGVtTmFtZSI6ICJURVNUIiwKCQkJInF1YW50aXR5IjogMQoJCX1dCgl9Cn0=

c.) Base64 encode request body. The body contains the parameters as given below : 

{
"merchantId":"PREPAIDTEST", // Shared by the PhonePe team on email. 
"amount":10000000, // In paise
"validFor":900000, // The payment page will close after this time.
"subMerchantId":"SUBMERCHANTTEST",// only for aggregators//
"transactionId":"TEST123454GHTYFTGU",//unique for each transaction
"merchantOrderId":"TEST123454GHTYFTGU",
"redirectUrl":"https://test-merchant.com/order/42314233232",//on which a user is redirected after payment is completed.
 "transactionContext": "ewoJIm9yZGVyQ29udGV4dCI6IHsKCQkidHJhY2tpbmdJbmZvIjogewoJCQkidHlwZSI6ICJIVFRQUyIsCgkJCSJ1cmwiOiAiaHR0cHM6Ly9nb29nbGUuY29tIgoJCX0KCX0sCgkiZmFyZURldGFpbHMiOiB7CgkJInRvdGFsQW1vdW50IjogMzkwMCwKCQkicGF5YWJsZUFtb3VudCI6IDM5MDAKCX0sCgkiY2FydERldGFpbHMiOiB7CgkJImNhcnRJdGVtcyI6IFt7CgkJCSJjYXRlZ29yeSI6ICJTSE9QUElORyIsCgkJCSJpdGVtSWQiOiAiMTIzNDU2Nzg5MCIsCgkJCSJwcmljZSI6IDM5MDAsCgkJCSJpdGVtTmFtZSI6ICJURVNUIiwKCQkJInF1YW50aXR5IjogMQoJCX1dCgl9Cn0=" // transaction context will be different for each merchant. This cart details is of shopping. 
}

The request body will be : 

{ "request": "ewoJIm1lcmNoYW50SWQiOiAiUFJFUEFJRFRFU1QiLAoJImFtb3VudCI6IDEwMDAwMDAwLAoJInZhbGlkRm9yIjogOTAwMDAwLAoJInRyYW5zYWN0aW9uSWQiOiAiVEVTVDEyMzQ1NEdIVFlGVEdVIiwKCSJtZXJjaGFudE9yZGVySWQiOiAiVEVTVDEyMzQ1NEdIVFlGVEdVIiwKCSJyZWRpcmVjdFVybCI6ICJodHRwczovL3Rlc3QtbWVyY2hhbnQuY29tL29yZGVyLzQyMzE0MjMzMjMyIiwKCSJ0cmFuc2FjdGlvbkNvbnRleHQiOiAiZXdvSkltOXlaR1Z5UTI5dWRHVjRkQ0k2SUhzS0NRa2lkSEpoWTJ0cGJtZEpibVp2SWpvZ2V3b0pDUWtpZEhsd1pTSTZJQ0pJVkZSUVV5SXNDZ2tKQ1NKMWNtd2lPaUFpYUhSMGNITTZMeTluYjI5bmJHVXVZMjl0SWdvSkNYMEtDWDBzQ2draVptRnlaVVJsZEdGcGJITWlPaUI3Q2drSkluUnZkR0ZzUVcxdmRXNTBJam9nTXprd01Dd0tDUWtpY0dGNVlXSnNaVUZ0YjNWdWRDSTZJRE01TURBS0NYMHNDZ2tpWTJGeWRFUmxkR0ZwYkhNaU9pQjdDZ2tKSW1OaGNuUkpkR1Z0Y3lJNklGdDdDZ2tKQ1NKallYUmxaMjl5ZVNJNklDSlRTRTlRVUVsT1J5SXNDZ2tKQ1NKcGRHVnRTV1FpT2lBaU1USXpORFUyTnpnNU1DSXNDZ2tKQ1NKd2NtbGpaU0k2SURNNU1EQXNDZ2tKQ1NKcGRHVnRUbUZ0WlNJNklDSlVSVk5VSWl3S0NRa0pJbkYxWVc1MGFYUjVJam9nTVFvSkNYMWRDZ2w5Q24wPSIKfQ==" } 



d.) Calculate X-Verify 

SHA256(base64 encoded payload + "/v3/transaction/sdk-less/initiate" + salt key) + '###' + salt index

You can calculate manually using https://passwordsgenerator.net/sha256-hash-generator/

SHA256(ewoJIm1lcmNoYW50SWQiOiAiUFJFUEFJRFRFU1QiLAoJImFtb3VudCI6IDEwMDAwMDAwLAoJInZhbGlkRm9yIjogOTAwMDAwLAoJInRyYW5zYWN0aW9uSWQiOiAiVEVTVDEyMzQ1NEdIVFlGVEdVIiwKCSJtZXJjaGFudE9yZGVySWQiOiAiVEVTVDEyMzQ1NEdIVFlGVEdVIiwKCSJyZWRpcmVjdFVybCI6ICJodHRwczovL3Rlc3QtbWVyY2hhbnQuY29tL29yZGVyLzQyMzE0MjMzMjMyIiwKCSJ0cmFuc2FjdGlvbkNvbnRleHQiOiAiZXdvSkltOXlaR1Z5UTI5dWRHVjRkQ0k2SUhzS0NRa2lkSEpoWTJ0cGJtZEpibVp2SWpvZ2V3b0pDUWtpZEhsd1pTSTZJQ0pJVkZSUVV5SXNDZ2tKQ1NKMWNtd2lPaUFpYUhSMGNITTZMeTluYjI5bmJHVXVZMjl0SWdvSkNYMEtDWDBzQ2draVptRnlaVVJsZEdGcGJITWlPaUI3Q2drSkluUnZkR0ZzUVcxdmRXNTBJam9nTXprd01Dd0tDUWtpY0dGNVlXSnNaVUZ0YjNWdWRDSTZJRE01TURBS0NYMHNDZ2tpWTJGeWRFUmxkR0ZwYkhNaU9pQjdDZ2tKSW1OaGNuUkpkR1Z0Y3lJNklGdDdDZ2tKQ1NKallYUmxaMjl5ZVNJNklDSlRTRTlRVUVsT1J5SXNDZ2tKQ1NKcGRHVnRTV1FpT2lBaU1USXpORFUyTnpnNU1DSXNDZ2tKQ1NKd2NtbGpaU0k2SURNNU1EQXNDZ2tKQ1NKcGRHVnRUbUZ0WlNJNklDSlVSVk5VSWl3S0NRa0pJbkYxWVc1MGFYUjVJam9nTVFvSkNYMWRDZ2w5Q24wPSIKfQ==/v3/transaction/sdk-less/initiate938b6b39-48dd-421b-b051-4617cf703377)


X-Verify : 61D71FB6214D27AEE1626D828F2F4DDEE430E8F20B04AADEAE84864E670BC8D7###1

e.) Headers will be : 

X-Verify : 61D71FB6214D27AEE1626D828F2F4DDEE430E8F20B04AADEAE84864E670BC8D7###1
X-CLIENT-ID : PREPAIDTEST
Content-Type : application/json
CALLBACK-URL : //the details can be found here : https://developer.phonepe.com/v4/reference#s2s-call-back-1

Sample Curl Request

Request : 

curl -X POST \
  https://apps-uat.phonepe.com/v3/transaction/sdk-less/initiate \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -H 'postman-token: 4513c1d4-50e9-6450-9306-9e5d945047a5' \
  -H 'x-client-id: PREPAIDTEST' \
  -H 'x-verify: 61D71FB6214D27AEE1626D828F2F4DDEE430E8F20B04AADEAE84864E670BC8D7###1' \
  -d '{ "request": "ewoJIm1lcmNoYW50SWQiOiAiUFJFUEFJRFRFU1QiLAoJImFtb3VudCI6IDEwMDAwMDAwLAoJInZhbGlkRm9yIjogOTAwMDAwLAoJInRyYW5zYWN0aW9uSWQiOiAiVEVTVDEyMzQ1NEdIVFlGVEdVIiwKCSJtZXJjaGFudE9yZGVySWQiOiAiVEVTVDEyMzQ1NEdIVFlGVEdVIiwKCSJyZWRpcmVjdFVybCI6ICJodHRwczovL3Rlc3QtbWVyY2hhbnQuY29tL29yZGVyLzQyMzE0MjMzMjMyIiwKCSJ0cmFuc2FjdGlvbkNvbnRleHQiOiAiZXdvSkltOXlaR1Z5UTI5dWRHVjRkQ0k2SUhzS0NRa2lkSEpoWTJ0cGJtZEpibVp2SWpvZ2V3b0pDUWtpZEhsd1pTSTZJQ0pJVkZSUVV5SXNDZ2tKQ1NKMWNtd2lPaUFpYUhSMGNITTZMeTluYjI5bmJHVXVZMjl0SWdvSkNYMEtDWDBzQ2draVptRnlaVVJsZEdGcGJITWlPaUI3Q2drSkluUnZkR0ZzUVcxdmRXNTBJam9nTXprd01Dd0tDUWtpY0dGNVlXSnNaVUZ0YjNWdWRDSTZJRE01TURBS0NYMHNDZ2tpWTJGeWRFUmxkR0ZwYkhNaU9pQjdDZ2tKSW1OaGNuUkpkR1Z0Y3lJNklGdDdDZ2tKQ1NKallYUmxaMjl5ZVNJNklDSlRTRTlRVUVsT1J5SXNDZ2tKQ1NKcGRHVnRTV1FpT2lBaU1USXpORFUyTnpnNU1DSXNDZ2tKQ1NKd2NtbGpaU0k2SURNNU1EQXNDZ2tKQ1NKcGRHVnRUbUZ0WlNJNklDSlVSVk5VSWl3S0NRa0pJbkYxWVc1MGFYUjVJam9nTVFvSkNYMWRDZ2w5Q24wPSIKfQ==" } '
  
Response : 

{
    "success": true,
    "code": "SUCCESS",
    "data": {
        "redirectUrl": "phonepe://checkoutResolve?reservationId=R2007131719303119074010&redirectUrl=https://test-merchant.com/order/42314233232"
    }
}

Step 7: Open Phonepe payments page

On client side open the "redirectUrl" using the below code

<body onload="window.location.href = '{{$data['request']['redirectUrl']}}'">
  
  As soon as user completes the payment he will be redirected to the **redirectUrl** which was given by the merchant in the initiate API. In above example the URL is : 
  
  "redirectUrl":"https://test-merchant.com/order/42314233232"

📘

Note

PhonePe does not share the status of the transaction at the client-side. As soon as the user completes the payment, he will be redirected to the merchant's URL. A merchant needs to fetch the status of the transaction from the backend API.

Step 8: Check the status of the transaction

A merchant needs to check the status of the transaction by integrating with :

a.) Check status API

x-verify will be calculated as : SHA256("/v3/transaction/PREPAIDTEST/TX000007085/status" + saltKey) + "###" + saltIndex

SHA256(/v3/transaction/PREPAIDTEST/TX000007085/status938b6b39-48dd-421b-b051-4617cf703377) == A582EF66D7757E665751E34CF44D7294A8101B7BADAD3E6E8B352D12967434A3

curl -X GET \
  https://apps-uat.phonepe.com/v3/transaction/PREPAIDTEST/TX000007085/status \
  -H 'cache-control: no-cache' \
  -H 'x-client-id: PREPAIDTEST' \
  -H 'x-verify: A582EF66D7757E665751E34CF44D7294A8101B7BADAD3E6E8B352D12967434A3###1'

b.) Webhook/Callback

A merchant needs to create a POST request API which can accept the details as mentioned below.

a.) It should be publically available and should be on port 443.
b.) A merchant should validate x-verify to know that the response is being sent by the PhonePe server only.

curl -X POST \
  https://api.merchant.com/response/phonepe \
  -H 'content-type: application/json' \
  -H 'x-verify: 2abaa82a4810c57dcd6aa52680dd772173b1e40770afe028131f31ddbe5487a8###1' \
  -d '{
"response":"ewoJInN1Y2Nlc3MiOiB0cnVlLAoJImNvZGUiOiAiUEFZTUVOVF9TVUNDRVNTIiwKCSJkYXRhIjogewoJCSJ0cmFuc2FjdGlvbklkIjogImY2MjI0MjBmLTJmNTgtNGYyZS04MzJmIiwKCQkibWVyY2hhbnRJZCI6ICJNSURURVNUIiwKCQkiYW1vdW50IjogMTAwMCwKCQkicHJvdmlkZXJSZWZlcmVuY2VJZCI6ICJQMTkxMjE4MTIxMDM1NzQyMTc1Njc1NSIsCgkJInBheW1lbnRTdGF0ZSI6ICJDT01QTEVURUQiLAoJCSJwYXlSZXNwb25zZUNvZGUiOiAiU1VDQ0VTUyIKCX0KfQ=="
}'

📘

Note

a.) A merchant can rely on the webhook/ PhonePe call back to fetch the transaction status.
If the webhook response is received in a few milliseconds, a merchant can show a success/failure page to the user. Else a merchant needs to poll the check status API. Integrating with check status API is mandatory.
b.) As soon as a user is redirected to the merchant page after payment is completed, a merchant should poll the status of the transaction using get status API.
c.) The polling needs to be done till validFor(time sent in the initiate API) + 5 minutes to fetch the status of the transaction.

Step 9: Integrate with refund APIs

There can be a couple of cases in which refunds might need to be triggered by the merchant:

  • User cancels the order
  • Merchant times out when waiting for the payment from PhonePe (using Check Transaction Status) and the payment comes after the merchant times out. The merchant should trigger a refund for the transaction.

Step 10: Identification of the source of traffic as PhonePe

As few merchants have to hide other payment options and other payment banners for the PhonePe Switch users, they should know that the user is opening the website inside the PhonePe application.

📘

Note

There should be no options shown to the user, as soon as he clicks on Pay, automatically PhonePe Payments page should open.

This can be done in 2 ways:

  1. Use a separate URL for your store in the PhonePe Apps Platform.
  2. Identify user agent as ‘PhonePe’ sent in PhonePe webview.

Step 11: Share the test cases to PhonePe Integration team

Refer to the section here. Merchant testing team needs to share the commented test cases to the PhonePe integration team on email for PreProd signoff.

Step 12: Provide PhonePe's team with the Switch pre-production URL/React Native Bundle

PhonePe's team would test the Switch and give the signoff on integration.