How to correctly structure a request for PhonePe Auto-Debit API (/v3/recurring/debit/init)?

I am integrating PhonePe’s Auto-Debit API (/v3/recurring/debit/init) but keep receiving the following error response:

{ 
  "status": "error", 
  "message": "Please check the inputs you have provided. [message = Incorrect Request.]" 
}

Payload Request is:

{
  "merchantId": "MID12345",
  "merchantUserId": "U123456789",
  "subscriptionId": "OMS2006110139450123456789",
  "transactionId": "TX1234567890",
  "autoDebit": true,
  "amount": 39900
}

X-VERIFY, payload format correct or wrong?
I have followed the documentation and ensured the request format is correct, but I still get this error. I need clarification on whether my request payload is missing any required fields or if the X-VERIFY signature is incorrect.

How should I structure the request properly to avoid this error? Any guidance would be appreciated.

  • Ensured transactionId is unique for every request.
  • Verified amount is in paisa format (e.g., ₹399.00 = 39900).
  • Tested in Postman using hardcoded values.
  • Checked subscriptionId format to ensure correctness.
  • Generated X-VERIFY hash according to PhonePe’s documentation.
  • Logged request payload to confirm correct structure.

Expected Outcome: I expected a successful API response with transaction details.

Here is the minimal reproducible example for my issue:

$apiKey = 'your_salt_key';
$baseUrl = '``https://mercury-t2.phonepe.com``';
$subscriptionId = 'SUB123456';
$transactionId = 'TX' . strtoupper(bin2hex(random_bytes(8))); // Generate unique transaction ID
$amount = 10000; // Amount in paise (₹100)
$callurl = "https://yourdomain.com/api/phonepe/callback"

// Request payload
$authPayload_1 = [
  'merchantId' => 'your_merchant_id',
  'merchantUserId' => 'your_merchant_id',
  'subscriptionId' => $subscriptionId,  
  'transactionId' => $transactionId,
  'autoDebit' => true,
  'amount' => $amount,
];
$base64Payload = base64_encode(json_encode($authPayload_1));
$payloadHash_1 = $base64Payload . '/v3/recurring/debit/init' . $apiKey;
$checksum_a = hash('sha256', $payloadHash_1);
$xVerifyy = $checksum_a . '###' . 'your_salt_index';

$curl = curl_init();
curl_setopt_array($curl, [
  CURLOPT_URL => $baseUrl . '/v3/recurring/debit/init',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_POSTFIELDS => json_encode(['request' => $base64Payload]),
  CURLOPT_HTTPHEADER => [
    'Content-Type: application/json',
    'X-VERIFY: ' . $xVerifyy,
    'X-CALLBACK-URL: '.$callurl

  ],
]);

$response = curl_exec($curl);
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);

$responseData = json_decode($response, true);
var_dump($responseData);```