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 |
{
"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"
}
{
"request": "eyAgCiAgICJtZXJjaGFudElkIjoiTUVSQ0hBTlRVQVQiLAogICAidHJhbnNhY3Rpb25JZCI6IlRYMTIzNDU2Nzg5IiwKICAgIm1lcmNoYW50T3JkZXJJZCI6Ik0xMjM0NTY3ODkiLAogICAiYW1vdW50IjoxMDAsCiAgICJpbnN0cnVtZW50VHlwZSI6Ik1PQklMRSIsCiAgICJpbnN0cnVtZW50UmVmZXJlbmNlIjoiOTk5OTk5OTk5OSIsCiAgICJtZXNzYWdlIjoiY29sbGVjdCBmb3IgWFhYIG9yZGVyIiwKICAgImVtYWlsIjoiYW1pdHh4eDc1QGdtYWlsLmNvbSIsCiAgICJleHBpcmVzSW4iOjE4MCwKICAgInNob3J0TmFtZSI6IkRlbW9DdXN0b21lciIsCiAgICJzdG9yZUlkIjoic3RvcmUxIiwKICAgInRlcm1pbmFsSWQiOiJ0ZXJtaW5hbDEiCn0="
}
<html-block html=”
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 |
{
"success": true,
"code": "SUCCESS",
"message": "Your request has been successfully completed.",
"data": {
"transactionId": "55fe801b-1092-461a-8480-c80d9781498a",
"amount": 300,
"merchantId": "MERCHANTUAT"
}
}
{
"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": {}
}
<html-block html=”
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 |
<html-block html=”
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
<html-block html=”
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.
using 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;
}
}
import 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();
}
}
from 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