Skip to main content

Parameters

The POST request to the return URL includes the following parameters:
ParameterTypeDescription
cf_subReferenceIdLongUnique numeric ID generated when the subscription was created.
cf_subscriptionIdStringID of the subscription.
cf_authAmountFloatThe amount charged to authorise the subscription.
cf_referenceIdLongThe reference ID or transaction ID of authorisation in PG.
cf_statusStringStatus of the subscription. In the returnUrl, the response should be ACTIVE or BANK_APPROVAL_PENDING if the authorisation was successful, or INITIALIZED if the authorisation failed.
cf_messageStringA brief note about the payment.
signatureStringThe hash of all parameters in the request generated using Secret Key.
cf_umrnStringThe unique identifier associated with a mandate. Applicable if the payment mode is eMandate.
cf_checkoutStatusStringThe subscription checkout status. The status can be SUCCESS, FAILED, SUCCESS_DEBIT_PENDING, or SUCCESS_TOKENIZATION_PENDING.
cf_modeStringThe checkout payment mode. Modes: NPCI_SBC, SBC_UPI, SBC_CREDIT_CARD, SBC_DEBIT_CARD.
cf_subscriptionPaymentIdStringThe subscription payment ID.
cf_umnStringThe unique identifier associated with a mandate. Applicable if the payment mode is UPI.

Sample Payload

Once the authorisation is complete, Cashfree will send a POST request to your return_url with the following payload:
{
  "cf_subReferenceId": 1234567,
  "cf_subscriptionId": "sub_test_123",
  "cf_authAmount": 1.00,
  "cf_referenceId": 987654321,
  "cf_status": "ACTIVE",
  "cf_message": "Subscription authorised successfully",
  "signature": "calculated_signature_here",
  "cf_umrn": "UMRN1234567890",
  "cf_checkoutStatus": "SUCCESS",
  "cf_mode": "SBC_UPI",
  "cf_subscriptionPaymentId": "pay_test_123",
  "cf_umn": "UMN1234567890"
}

Sample Code

Below are examples of how to receive and process the redirection payload in your backend.
const express = require('express');
const app = express();

// Middleware to parse POST bodies
app.use(express.urlencoded({ extended: true }));

app.post('/return-url', (req, res) => {
  const payload = req.body;
  
  console.log('Received Redirection Payload:', payload);

  const status = payload.cf_status;
  if (status === 'ACTIVE' || status === 'BANK_APPROVAL_PENDING') {
    // Handle success
    res.send('Subscription Authorised Successfully');
  } else {
    // Handle failure
    res.send('Authorization Failed');
  }
});
from flask import Flask, request

app = Flask(__name__)

@app.route('/return-url', methods=['POST'])
def return_url():
    # Capture the POST payload
    payload = request.form.to_dict()
    
    print("Received Redirection Payload:", payload)
    
    status = payload.get('cf_status')
    if status in ['ACTIVE', 'BANK_APPROVAL_PENDING']:
        return "Subscription Authorised Successfully", 200
    else:
        return "Authorisation Failed", 400
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
public class SubscriptionController {

    @PostMapping("/return-url")
    public String handleRedirection(HttpServletRequest request) {
        // Collect parameters from the POST request
        Map<String, String[]> parameterMap = request.getParameterMap();
        
        String status = request.getParameter("cf_status");
        
        if ("ACTIVE".equals(status) || "BANK_APPROVAL_PENDING".equals(status)) {
            return "Subscription Authorised Successfully";
        } else {
            return "Authorisation Failed";
        }
    }
}
package main

import (
	"fmt"
	"net/http"
)

func returnURLHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	// Parse the POST form
	r.ParseForm()
	
	status := r.FormValue("cf_status")
	fmt.Printf("Subscription Status: %s\n", status)

	if status == "ACTIVE" || status == "BANK_APPROVAL_PENDING" {
		fmt.Fprint(w, "Subscription Authorised Successfully")
	} else {
		fmt.Fprint(w, "Authorisation Failed")
	}
}

func main() {
	http.HandleFunc("/return-url", returnURLHandler)
	http.ListenAndServe(":8080", nil)
}
<?php
// Receive the POST data from Cashfree redirection
$payload = $_POST;

$status = $payload['cf_status'] ?? '';

if ($status === 'ACTIVE' || $status === 'BANK_APPROVAL_PENDING') {
    echo "Subscription Authorised Successfully";
} else {
    echo "Authorisation Failed";
}
?>
Return URL
  • After the customer completes the checkout on the OTP page, they are redirected to your return_url. This redirection is link-based. For example, if you provide a return_url in the format https://b8af79f41056.eu.ngrok.io?order_id={order_id}, the customer is redirected to https://b8af79f41056.eu.ngrok.io?order_id=order_271vfuhh1o4h6bQIigqyOx74YiJ1T.
  • In production, cf_status and cf_message may not be included in the return_url response, even though they are present in the sandbox.
    The return_url is intended only to redirect customers back to your site after payment. It should not be used to retrieve complete subscription details.
For accurate and complete data, use webhooks.
  • Configure your webhook URL in the Cashfree Dashboard.
  • Enable the relevant events, such as SUBSCRIPTION_AUTH_STATUS and SUBSCRIPTION_PAYMENT_SUCCESS.
Always validate the subscription status through webhook notifications for production-grade reliability.