Request Payment API

Request Payment APIs are used when the merchant wants to send a collect payment request to user's PhonePe app against an order.

PROD

Base Url: https://mercury-t2.phonepe.com

Collect Call Endpoint: https://mercury-t2.phonepe.com/v3/charge

Header NameHeader Value
Content-Typeapplication/json
X-VERIFYSHA256(base64 encoded payload +
“/v3/charge” + salt key) + ### + salt index
X-PROVIDER-IDUsed for the cases where the merchant has multiple merchant IDs
X-CALLBACK-URLCallback Url where a request will be made once user responds
to collect request.
Click here to see about this request.
{  
   "merchantId":"MERCHANTUAT",
   "transactionId":"TX123456789",
   "merchantOrderId":"M123456789",
   "amount":100,
   "instrumentType":"MOBILE",
   "instrumentReference":"9999999999",
   "message":"collect for XXX order",
   "email":"[email protected]",
   "expiresIn":180,
   "shortName":"DemoCustomer",
   "storeId":"store1",
   "terminalId":"terminal1"
}
{
  "request": "eyAgCiAgICJtZXJjaGFudElkIjoiTUVSQ0hBTlRVQVQiLAogICAidHJhbnNhY3Rpb25JZCI6IlRYMTIzNDU2Nzg5IiwKICAgIm1lcmNoYW50T3JkZXJJZCI6Ik0xMjM0NTY3ODkiLAogICAiYW1vdW50IjoxMDAsCiAgICJpbnN0cnVtZW50VHlwZSI6Ik1PQklMRSIsCiAgICJpbnN0cnVtZW50UmVmZXJlbmNlIjoiOTk5OTk5OTk5OSIsCiAgICJtZXNzYWdlIjoiY29sbGVjdCBmb3IgWFhYIG9yZGVyIiwKICAgImVtYWlsIjoiYW1pdHh4eDc1QGdtYWlsLmNvbSIsCiAgICJleHBpcmVzSW4iOjE4MCwKICAgInNob3J0TmFtZSI6IkRlbW9DdXN0b21lciIsCiAgICJzdG9yZUlkIjoic3RvcmUxIiwKICAgInRlcm1pbmFsSWQiOiJ0ZXJtaW5hbDEiCn0="
}

<html-block html=”

Request Parameters

“>

Parameter NameTypeDescriptionMandatory
merchantIdStringUnique Merchant ID assigned to the merchant by PhonePeYes
transactionIdStringUnique 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 38 characters.
Yes
merchantOrderIdStringUnique Order ID generated by the merchant
merchantOrderId length should be less than 48 characters.
Yes
amountLongAmount in PaisaYes
instrumentTypeENUMHas the value MOBILEYes
instrumentReferenceStringMobile number of the userYes
expiresInLongexpire time of payment completion.Payment should be completed with in this time else will be markedfailed. (default 30 days)Yes
messageStringRecommended to pass transaction id, order id and invoice number.No
emailStringEmail Id of UserNo
shortNameStringCustomer NameNo
subMerchantStringSub-category of the merchantNo
storeIdStringStore Id of store. Should be unique across. Special characters like ” “, “,”, “@” etc. are not allowed. Length should be lesser than 38 charactersYes
terminalIdStringTerminal Id of store. Should be unique for a store. Special characters like ” “, “,”, “@” etc. are not allowed. Length should be lesser than 38 charactersNo
{
    "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 NameTypeDescription
successBOOLEANSuccess status of the request
codeENUMSee below section for list of codes
messageSTRINGShort message about status of request
transactionIdSTRINGUnique Transaction ID generated by the merchant to track this request to PhonePe
merchantIdSTRINGUnique Merchant ID assigned to the merchant by PhonePe
amountLONGTransaction amount in paise
mobileNumberSTRINGMobile Number

<html-block html=”

Response Codes

“>

The code in the above API response could be:

  • SUCCESS : Collect was successfully sent to VPA
  • INTERNAL_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 duplicate
  • BAD_REQUEST : Some mandatory parameter was missing
  • AUTHORIZATION_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", "[email protected]");
        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