PROD
Base Url: https://mercury-t2.phonepe.com
Collect Call Endpoint: https://mercury-t2.phonepe.com/v3/charge
Header Name | Header Value |
---|---|
Content-Type | application/json |
X-VERIFY | SHA256(base64 encoded payload + “/v3/charge” + salt key) + ### + salt index |
X-PROVIDER-ID | Used for the cases where the merchants are getting onboarded via their Providers |
X-CALLBACK-URL | Merchants need to pass their Callback URL to receive automated callbacks/ webhooks from Phonepe post performing transactions |
Sample Payload for Base64{ "merchantId":"MERCHANTUAT", "transactionId":"TX123456789", "merchantOrderId":"M123456789", "amount":100, "instrumentType":"MOBILE", "instrumentReference":"9999999999", "message":"collect for XXX order", "email":"amitxxx75@gmail.com", "expiresIn":180, "shortName":"DemoCustomer", "storeId":"store1", "terminalId":"terminal1" }
Sample Request{ "request": "eyAgCiAgICJtZXJjaGFudElkIjoiTUVSQ0hBTlRVQVQiLAogICAidHJhbnNhY3Rpb25JZCI6IlRYMTIzNDU2Nzg5IiwKICAgIm1lcmNoYW50T3JkZXJJZCI6Ik0xMjM0NTY3ODkiLAogICAiYW1vdW50IjoxMDAsCiAgICJpbnN0cnVtZW50VHlwZSI6Ik1PQklMRSIsCiAgICJpbnN0cnVtZW50UmVmZXJlbmNlIjoiOTk5OTk5OTk5OSIsCiAgICJtZXNzYWdlIjoiY29sbGVjdCBmb3IgWFhYIG9yZGVyIiwKICAgImVtYWlsIjoiYW1pdHh4eDc1QGdtYWlsLmNvbSIsCiAgICJleHBpcmVzSW4iOjE4MCwKICAgInNob3J0TmFtZSI6IkRlbW9DdXN0b21lciIsCiAgICJzdG9yZUlkIjoic3RvcmUxIiwKICAgInRlcm1pbmFsSWQiOiJ0ZXJtaW5hbDEiCn0=" }
Request Parameters
Parameter Name | Type | Description | Mandatory |
---|---|---|---|
merchantId | String | Unique Merchant ID assigned to the merchant by PhonePe | Yes |
transactionId | String | Unique Transaction ID generated by the merchant to track this request to PhonePe transactionId length Should be unique for each collect request.should be less than 35 characters. – No Special characters allowed except underscore “_” and hyphen “-“ | Yes |
merchantOrderId | String | Unique Order ID generated by the merchant merchantOrderId length should be less than 48 characters. | Yes |
amount | Long | Amount in Paisa | Yes |
instrumentType | ENUM | Has the value MOBILE | Yes |
instrumentReference | String | Mobile number of the user | Yes |
expiresIn | Long | expire time of payment completion.Payment should be completed with in this time else will be markedfailed . (default 30 days) | Yes |
message | String | Recommended to pass transaction id, order id and invoice number . | No |
email | String | Email Id of User | No |
shortName | String | Customer Name | No |
subMerchant | String | Sub-category of the merchant | No |
storeId | String | Store Id of store. Should be unique across. Special characters like ” “, “,”, “@” etc. are not allowed. Length should be lesser than 38 characters | Yes |
terminalId | String | Terminal Id of store. Should be unique for a store. Special characters like ” “, “,”, “@” etc. are not allowed. Length should be lesser than 38 characters | No |
Sample Success Response{ "success": true, "code": "SUCCESS", "message": "Your request has been successfully completed.", "data": { "transactionId": "55fe801b-1092-461a-8480-c80d9781498a", "amount": 300, "merchantId": "MERCHANTUAT" } }
Sample Failed Response{ "success": false, "code": "INTERNAL_SERVER_ERROR", "message": "There is an error trying to process your transaction at the moment. Please try again in a while.", "data": {} }
Response Parameters
Parameter Name | Type | Description |
---|---|---|
success | BOOLEAN | Success status of the request |
code | ENUM | See below section for list of codes |
message | STRING | Short message about status of request |
transactionId | STRING | Unique Transaction ID generated by the merchant to track this request to PhonePe |
merchantId | STRING | Unique Merchant ID assigned to the merchant by PhonePe |
amount | LONG | Transaction amount in paise |
mobileNumber | STRING | Mobile Number |
Response Codes
The code in the above API response could be:
SUCCESS
: Collect was successfully sent to VPAINTERNAL_SERVER_ERROR
: Something went wrong. Need to validate through check transaction status API first to know the payment status.INVALID_TRANSACTION_ID
: TransactionId in request was duplicateBAD_REQUEST
: Some mandatory parameter was missingAUTHORIZATION_FAILED
: Checksum sent in header was not valid
Charge Callback
When the user responds to the collect request sent by the merchant, a request is sent to either the URL provided in X-CALLBACK-URL or the merchant’s registered callback URL. By default, this is a POST request.
Note:
- The callback would be sent only for success/Failed scenarios. For pending cases, there won’t be any callback. For such transactions payment status should be checked with below API.
- If payment is in pending state, Merchant should display a message “Payment is in progress, please wait for sometime.”
- The payment will always be closed within the expiry time passed in the collect request.
C# SampleCodeusing System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Net; using System.Text; using System.Security.Cryptography; using Newtonsoft.Json; namespace Rextester { public class Program { private const string PHONEPE_STAGE_BASE_URL = "https://mercury-uat.phonepe.com/enterprise-sandbox"; private string merchantKey = "8289e078-be0b-484d-ae60-052f117f8deb"; private const string merchantId = "M2306160483220675579140"; private string transactionId = "mer_order_8"; private int amount = 100; private string instrumentType = "MOBILE"; private string instrumentReference = "9XXXXXXXXX"; private string storeId = "store1"; private string terminalId = "terminal1"; private int expiresIn = 180; public bool SendPaymentRequest(){ PhonePeCollectRequest phonePeCollectRequest = new PhonePeCollectRequest(); phonePeCollectRequest.merchantId = merchantId; phonePeCollectRequest.transactionId = transactionId; phonePeCollectRequest.merchantOrderId = transactionId; phonePeCollectRequest.amount = amount; phonePeCollectRequest.expiresIn = expiresIn; phonePeCollectRequest.instrumentType = instrumentType; phonePeCollectRequest.instrumentReference = instrumentReference; phonePeCollectRequest.storeId = storeId; phonePeCollectRequest.terminalId = terminalId; //convert string to json String jsonStr = JsonConvert.SerializeObject(phonePeCollectRequest); Console.WriteLine(jsonStr); string base64Json = ConvertStringToBase64(jsonStr); Console.WriteLine(base64Json); string jsonSuffixString = "/v3/charge" + merchantKey; string checksum = GenerateSha256ChecksumFromBase64Json(base64Json, jsonSuffixString); checksum = checksum + "###1"; Console.WriteLine(checksum); string txnURL = PHONEPE_STAGE_BASE_URL + "/v3/charge"; Console.WriteLine("txnURL : " + txnURL); try { HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(txnURL); webRequest.Method = "POST"; webRequest.ContentType = "application/json"; webRequest.Headers.Add("x-verify", checksum); PhonePeCollectApiRequestBody phonePeCollectApiRequestBody = new PhonePeCollectApiRequestBody(); phonePeCollectApiRequestBody.request = base64Json; String jsonBody = JsonConvert.SerializeObject(phonePeCollectApiRequestBody); using (StreamWriter requestWriter = new StreamWriter(webRequest.GetRequestStream())) { requestWriter.Write(jsonBody); } string responseData = string.Empty; using (StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream())) { responseData = responseReader.ReadToEnd(); if (responseData.Length > 0) { //Dictionary<string, string> responseParam = JSONConvert.decode(responseData); PhonePeCollectResponseBody responseBody = JsonConvert.DeserializeObject<PhonePeCollectResponseBody>(responseData); Console.WriteLine(responseData); Console.WriteLine(responseBody.message); } } } catch (Exception e) { Console.WriteLine(e); return false; } return false; } public bool SendCheckPaymentStatusRequest() { string headerString = String.Format("/v3/transaction/{0}/{1}/status{2}", merchantId, transactionId, merchantKey); Console.WriteLine("headerString: " + headerString); string checksum = GenerateSha256ChecksumFromBase64Json("", headerString); checksum = checksum + "###1"; Console.WriteLine(checksum); bool result = CallPhonePeStatusApi(checksum); return result; } private bool CallPhonePeStatusApi(String xVerify) { Console.WriteLine("CallPhonePeStatusApi()"); string txnURL = PHONEPE_STAGE_BASE_URL; String urlSuffix = String.Format("/v3/transaction/{0}/{1}/status", merchantId, transactionId); txnURL = txnURL + urlSuffix; Console.WriteLine("Url: " + txnURL); try { HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(txnURL); webRequest.Method = "GET"; webRequest.Headers.Add("x-verify", xVerify); string responseData = string.Empty; using (StreamReader responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream())) { responseData = responseReader.ReadToEnd(); if (responseData.Length > 0) { PhonePeCollectResponseBody responseBody = JsonConvert.DeserializeObject<PhonePeCollectResponseBody>(responseData); Console.WriteLine(responseData); Console.WriteLine(responseBody.message); } } } catch (Exception e) { Console.WriteLine(e); return false; } return false; } //convert jsonBody to base64 public string ConvertStringToBase64(string inputString) { string base64Json = null; byte[] requestBytes = Encoding.UTF8.GetBytes(inputString); base64Json = Convert.ToBase64String(requestBytes); return base64Json; } // calculate SHA256 private string GenerateSha256ChecksumFromBase64Json(string base64JsonString, string jsonSuffixString) { string checksum = null; SHA256 sha256 = SHA256.Create(); string checksumString = base64JsonString + jsonSuffixString; byte[] checksumBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(checksumString)); //checksum = BitConverter.ToString(checksumBytes).Replace("-", string.Empty); foreach (byte b in checksumBytes) { checksum += $"{b:x2}"; } return checksum; } public static void Main(string[] args){ Program obj = new Program(); bool QRResponse = obj.SendPaymentRequest(); Console.WriteLine(" Success"); bool statusResponse = obj.SendCheckPaymentStatusRequest(); Console.WriteLine("Payment status check"); } } public class PhonePeCollectRequest { public string merchantId; public string transactionId; public string merchantOrderId; public int amount; public int expiresIn; public string instrumentType; public string instrumentReference; public string storeId; public string terminalId; } public class PhonePeCollectApiRequestBody { public string request; } public class PhonePeCollectResponseBody { public bool success; public string code; public string message; public Data data; } public class Data { public string transactionId; public int amount; public string merchantId; public string providerReferenceId; } }
Java SampleCodeimport java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.nio.charset.StandardCharsets; import javax.xml.bind.DatatypeConverter; public class RequestPaymentApi { String apiSaltKey = "salt_key"; static String urlEndpoint = "/v3/charge"; public static String GenerateSha256FromBase64Json(byte[] base64Encoded, String urlEndpoint) { String checksum= null; MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } // compute the hash of the input string byte[] hash = md.digest(urlEndpoint.getBytes()); return checksum; } public static void main(String[] args) throws Exception { String apiUrl = "https://mercury-uat.phonepe.com/enterprise-sandbox/v3/charge"; // Request parameters Map<String, Object> params = new HashMap<String, Object>(); params.put("merchantId", "MERCHANTUAT"); params.put("transactionId", "TX12345678901"); params.put("merchantOrderId", "M123456701"); params.put("amount", (long) 100); //params.put("amount", "100.00"); params.put("instrumentType", "MOBILE"); params.put("instrumentReference", "8296000000"); params.put("message", "This is Collect Call"); params.put("email", "deepak@gmail.com"); params.put("expiresIn", (long) 1800); params.put("shortName", "DemoCustomer"); params.put("storeId", "store1"); params.put("terminalId", "1"); //creating Json payload into EncodedBase64 Gson gson = new Gson(); String json = gson.toJson(params); byte[] base64Encoded = Base64.getEncoder().encode(json.getBytes(StandardCharsets.UTF_8)); //creating X-verify String checksum = GenerateSha256FromBase64Json(base64Encoded,urlEndpoint); checksum = checksum + "###1"; // Construct request body StringBuilder requestBody = new StringBuilder(); for (Entry<String, Object> entry : params.entrySet()) { requestBody.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); } requestBody.setLength(requestBody.length() - 1); // Remove the trailing "&" URL url = new URL(apiUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("X-verify", "checksum"); conn.setDoOutput(true); OutputStream os = conn.getOutputStream(); os.write(requestBody.toString().getBytes()); os.flush(); int responseCode = conn.getResponseCode(); System.out.println("Response Code: " + responseCode); BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); String response; while ((response = br.readLine()) != null) { System.out.println(response); } br.close(); conn.disconnect(); } }
Python SampleCodefrom django.shortcuts import render from django.http import HttpResponse import requests import base64 import hashlib from rest_framework.decorators import api_view import json from django.http import JsonResponse import qrcode import os txnid = "TEST20231004021525T" baseUrl = 'https://mercury-uat.phonepe.com/enterprise-sandbox' MID = 'MERCHANTUAT' saltkey = 'f1fed176-917c-4c1b-b5ae-1e1d39e1f8d5' keyindex = '1' def requestpayment(request): url = baseUrl + '/v3/charge' payload = { "merchantId": MID, "transactionId": txnid, "merchantOrderId": "MO8090133", "amount": 100, "instrumentType": "MOBILE", "instrumentReference": "8296412345", # "message":'Hi, this is Deepak', # "shortName": "sairamit", "storeId": "store1", "terminalId": "terminal1", "expiresIn": 180 } # for base64 encoded payload strjson = json.dumps(payload) encoded_dict = strjson.encode('UTF-8') encodeddata = base64.b64encode(encoded_dict) encodeddata = encodeddata.decode('UTF-8') data = { "request": encodeddata } print(json.dumps(data)) # for Sha256 calculation # api_saltkey = '/v3/charge' + saltkey str_forSha256 = encodeddata + '/v3/charge' + saltkey sha_value = hashlib.sha256(str_forSha256.encode('UTF-8')).hexdigest() x_verify = sha_value + '###' + keyindex print(x_verify); headers = { "Content-Type": "application/json", #"x-provider-id": "UATPROVIDER", # "x-callback-url": "https://3c07d4cctf.execute-api.ap-northeast-1.amazonaws.com/default/myfunc", # "x-call-mode": "POST", # "X-REDIRECT-MODE": "POST", "X-VERIFY": x_verify } print(headers) print(strjson) print(url) print(str_forSha256) print(x_verify) res = requests.post(url=url, data=json.dumps(data), headers=headers) print(res.status_code) print(res) return HttpResponse(res)
{“method”:”post”,”url”:”/v3/charge”,”auth”:”required”,”results”:{“codes”:[{“name”:””,”code”:”{\n \”success\”: true,\n \”code\”: \”SUCCESS\”,\n \”message\”: \”Your request has been successfully completed.\”,\n \”data\”: {\n \”transactionId\”: \”55fe801b-1092-461a-8480-c80d9781498a\”,\n \”amount\”: 300,\n \”merchantId\”: \”MERCHANTUAT\”,\n \”providerReferenceId\”: \”C2111161249027983263789\”\n }\n}”,”language”:”json”,”status”:200},{“name”:””,”code”:”{\n \”success\”: false,\n \”code\”: \”BAD_REQUEST\”,\n \”message\”: \”Invalid mobile number: \”,\n \”data\”: {}\n}”,”language”:”json”,”status”:400}]},”params”:[{“name”:”request”,”type”:”string”,”enumValues”:””,”default”:””,”desc”:”base64 encoded payload”,”required”:true,”in”:”body”,”ref”:””,”_id”:”5f310486f1017f0441fa05ea”},{“name”:”Content-Type”,”type”:”string”,”enumValues”:””,”default”:”application/json”,”desc”:””,”required”:true,”in”:”header”,”ref”:””,”_id”:”5f310486f1017f0441fa05e9″},{“name”:”X-VERIFY”,”type”:”string”,”enumValues”:””,”default”:”2dbfabed915b9b9759bc10a3ce6ecfbeb0c1169d5eada325668fcf31be8d360e###1″,”desc”:”SHA256(base64 encoded payload + \”/v3/charge\” + salt key) + ### + salt index”,”required”:true,”in”:”header”,”ref”:””,”_id”:”5f310486f1017f0441fa05e8″},{“name”:”X-CALLBACK-URL”,”type”:”string”,”enumValues”:””,”default”:””,”desc”:”Callback Url where a request will be made once user responds to collect request.”,”required”:true,”in”:”header”,”ref”:””,”_id”:”5f310486f1017f0441fa05e7″},{“name”:”X-PROVIDER-ID”,”type”:”string”,”enumValues”:””,”default”:””,”desc”:”Used for the cases where the merchant has multiple merchant IDs”,”required”:true,”in”:”header”,”ref”:””,”_id”:”5f310486f1017f0441fa05e6″}],”examples”:{“codes”:[{“code”:”{\n \”request\”: \”eyAgCiAgICJtZXJjaGFudElkIjoiTUVSQ0hBTlRVQVQiLAogICAidHJhbnNhY3Rpb25JZCI6IlRYMTIzNDU2Nzg5IiwKICAgIm1lcmNoYW50T3JkZXJJZCI6Ik0xMjM0NTY3ODkiLAogICAiYW1vdW50IjoxMDAsCiAgICJpbnN0cnVtZW50VHlwZSI6Ik1PQklMRSIsCiAgICJpbnN0cnVtZW50UmVmZXJlbmNlIjoiOTk5OTk5OTk5OSIsCiAgICJtZXNzYWdlIjoiY29sbGVjdCBmb3IgWFhYIG9yZGVyIiwKICAgImVtYWlsIjoiYW1pdHh4eDc1QGdtYWlsLmNvbSIsCiAgICJleHBpcmVzSW4iOjE4MCwKICAgInNob3J0TmFtZSI6IkRlbW9DdXN0b21lciIsCiAgICJzdG9yZUlkIjoic3RvcmUxIiwKICAgInRlcm1pbmFsSWQiOiJ0ZXJtaW5hbDEiCn0=\”\n}”,”language”:”json”}]},”apiSetting”:”64c244096688b200429110a5″}
https://mercury-uat.phonepe.com/enterprise-sandbox