Skip to main content

Creating an Enrollment using Intent/QR

UPI Autopay works by establishing an authorization, achieved through an enrollment process, between a merchant and a customer, and referencing it in every recurring payment.

By following this integration guide, you will understand how you can create enrollments and accept UPI Autopay recurring payments in your checkout, by using EBANX Direct API. To complete a payment with UPI Autopay, you will need to create an enrollment for your customer, and then recurring payments can be raised on the same enrollment going forward.

Requirements

  • API credentials - Ensure you have your EBANX integration key. If not, complete the Merchant Signup Form.
  • Familiarity with EBANX Direct - This setup follows the same general structure as other payment methods, with a few unique parameters. See EBANX Direct for more info.

Instructions

To complete a UPI Autopay enrollment using Intent or QR Code, please follow the steps below.

  1. Select your environment

    Select the appropriate environment for your integration. Use the sandbox environment for testing, or the production environment for live transactions. Use the URL for your HTTP requests based on your selection.

    https://sandbox.ebanx.com/ws/direct
  2. Create Enrollment and First Charge

    To start the recurring payment process, use the /ws/direct endpoint to create the mandate and process the first charge. This step involves collecting essential customer details, first charge payment details, and subscription parameters to establish the recurring billing agreement.

    Users will be required to complete a 2FA in order to accept this enrollment on their app. Once the process is complete, the customer will be enrolled for the recurring payment cycle.

    Note

    This is a single API request which includes mandate creation as well as first charge. Once the user authenticates the request through the app link or by scanning the QR code, mandate creation and first charge shall be processed automatically at EBANX's end.

    To trigger this process, call the endpoint /ws/direct with the following parameters:


    Basic parameters

    ParameterRequirementDescription
    integration_keyRequiredYour integration key
    payment.payment_type_codeRequiredCan be either upi-intent-autopay or upi-qrcode-autopay
    operationRequiredMust be request

    Enrollment data

    ParameterRequirementDescription
    payment.enrollment.merchant_enrollment_codeRequiredUnique identifier associated with the enrollment.
    payment.enrollment.back_urls.successRequiredCallback URL for a successful response.
    payment.enrollment.back_urls.failureRequiredCallback URL for a failure response.
    payment.enrollment.subscription.subscription_nameRequiredA descriptor of the service being provided, which will be displayed in the customer's app. No special characters allowed. Maximum characters allowed - 50. (Currently, only Gpay displays this information)
    payment.enrollment.subscription.expiration_dateRequiredDefines when the enrollment is no longer valid, and no further payments will be charged.
    payment.enrollment.subscription.frequencyRequiredThe billing cycle of the enrollment. Available frequencies are: weekly, monthly, yearly, and ondemand.
    payment.enrollment.subscription.recurrence_valueOptional (only required if frequency is set to weekly, monthly, or yearly)If weekly, 1 to 7. If monthly or yearly, 1 to 31. Note: If recurrence value is set as "5" for frequency "monthly", then the recurring charge has to be initiated on the 5th of every month.
    payment.enrollment.subscription.recurrence_ruleOptional (only required if frequency is set to weekly, monthly, or yearly)Currently only supports on.
    payment.enrollment.subscription.min_amountRequiredMinimum amount (per payment) during the validity of the subscription plan (in INR currency).
    payment.enrollment.subscription.max_amountRequiredMaximum amount (per payment) during the validity of the subscription plan (in INR currency).

    Payment data

    ParameterRequirementDescription
    payment.nameRequiredCustomer's full name. Minimum 5 characters, alphabets only.
    payment.emailRequiredCustomer's email.
    payment.phone_numberRequiredCustomer's phone. Minimum 8 digits, maximum 10 digits, numbers only.
    payment.countryRequiredSet to in for India.
    payment.merchant_payment_codeRequiredUnique code for the payment.
    payment.currency_codeRequiredSet to INR.
    payment.amount_totalRequiredPayment amount.
    payment.addressRequiredCustomer's address. Minimum 3 characters.
    payment.street_numberOptionalCustomer's street number.
    payment.cityRequiredCustomer's city. Minimum 3 characters, alphabets only.
    payment.stateRequiredCustomer's state. Either use state code or state name. Refer to the state list for reference.
    payment.zipcodeRequiredCustomer's zipcode or pincode. Must be 6 digits, numbers only.
    Note
    • When setting the max and min amounts, any charge made outside the set value will be declined and shall require a new enrollment set-up with new values in the fields min_amount and max_amount.
    • The following parameters will be displayed in the user's UPI app with the subscription authentication request: expiration_date, frequency, min_amount, max_amount.
    • The predefined values for frequency set the rules for payment execution, but they don't automate the required actions.
      • Pre-debit notifications and payment requests must be managed manually.
      • Payments outside these rules will be declined.
      • Avoid using the last day of the frequency period as the recurrence value.
      • If the time window is missed, the subscription status remains unchanged, and payments can proceed in the next window. Merchants can send a one-time request charge to cover such cases.
      • For more flexibility, consider using "ondemand" as frequency.
  3. QR Code Flow

    In the upi-qrcode-autopay flow, users scan a QR code, which redirects them to their UPI app to complete the transaction. Upon redirection, the UPI app loads the pre-filled payment details and prompts the user to enter their UPI PIN for authentication, finalizing the transaction.

    Request

    Use the following example to initiate a request.

    curl -X POST \
    --location 'https://sandbox.ebanx.com/ws/direct' \
    --header 'Content-Type: application/json' \
    --data '{
    "integration_key": "{<integration_key>}",
    "operation": "request",
    "payment": {
    "name": "John Doe",
    "email": "john.doe@example.com",
    "address": "AV MIRACATU",
    "street_number": "2993",
    "city": "Bengaluru",
    "state": "Karnataka",
    "zipcode": "560087",
    "country": "in",
    "phone_number": "9999999999",
    "payment_type_code": "upi-qrcode-autopay",
    "amount_total": 200,
    "currency_code": "INR",
    "merchant_payment_code": "{<unique_payment_code>}",
    "enrollment": {
    "merchant_enrollment_code": "{<unique_enrollment_code>}",
    "back_urls": {
    "success": "{<merchant_success_url_here>}",
    "failure": "{<merchant_failure_url_here>}"
    },
    "subscription": {
    "subscription_name": "{<subscription_name>}",
    "expiration_date": "2035-12-31",
    "min_amount": "1",
    "max_amount": "500",
    "frequency": "ondemand"
    }
    }
    }
    }'

    Response

    A successful request returns a response like the example below.

    {
    "status": "SUCCESS",
    "payment": {
    "hash": "{<hash_here>}",
    "country": "in",
    "merchant_payment_code": "{<unique_payment_code>}",
    "order_number": null,
    "status": "PE",
    "status_date": null,
    "open_date": "2026-03-22 15:14:39",
    "confirm_date": null,
    "transfer_date": null,
    "amount_br": "200.00",
    "amount_ext": "200.00",
    "amount_iof": "0.00",
    "currency_rate": "1.0000",
    "currency_ext": "INR",
    "due_date": "2026-03-22 15:19:39",
    "instalments": "1",
    "payment_type_code": "upi-qrcode-autopay",
    "pre_approved": false,
    "capture_available": null,
    "customer": {
    "document": "",
    "email": "john.doe@example.com",
    "name": "John Doe",
    "birth_date": null
    },
    "single_transaction": {
    "amount_local": "0.00",
    "amount_crossborder": "200.00"
    },
    "upi": {
    "expiration_date": "2026-03-22 15:24:39",
    "qr_code_value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEAAQMAAABmvDolAAAA..."
    },
    "currency_ext_base": "INR"
    }
    }

    The qr_code_value field contains a base64-encoded PNG image (data:image/png;base64,...). Render this value directly in an <img> tag on your checkout page for the customer to scan.

  4. Intent (App) Flow

    In the upi-intent-autopay flow, mobile users select their preferred UPI app or choose the "Other UPI app" option at checkout before proceeding with payment. Upon clicking to pay, they are redirected to their chosen UPI app. The app then loads the pre-filled payment details and prompts the user to enter their UPI PIN for authentication, completing the transaction.

    Request

    Use the following example to initiate a request.

    curl -X POST \
    --location 'https://sandbox.ebanx.com/ws/direct' \
    --header 'Content-Type: application/json' \
    --data '{
    "integration_key": "{<integration_key>}",
    "operation": "request",
    "payment": {
    "name": "John Doe",
    "email": "john.doe@example.com",
    "address": "AV MIRACATU",
    "street_number": "2993",
    "city": "Bengaluru",
    "state": "Karnataka",
    "zipcode": "753009",
    "country": "in",
    "phone_number": "9999999999",
    "payment_type_code": "upi-intent-autopay",
    "amount_total": 200,
    "currency_code": "INR",
    "merchant_payment_code": "{<unique_payment_code>}",
    "enrollment": {
    "merchant_enrollment_code": "{<unique_enrollment_code>}",
    "back_urls": {
    "success": "{<merchant_success_url_here>}",
    "failure": "{<merchant_failure_url_here>}"
    },
    "subscription": {
    "subscription_name": "{<subscription_name>}",
    "expiration_date": "2035-12-31",
    "min_amount": "1",
    "max_amount": "500",
    "frequency": "ondemand"
    }
    }
    }
    }'

    Response

    A successful request returns a response like the example below.

    {
    "status": "SUCCESS",
    "payment": {
    "hash": "{<hash_here>}",
    "country": "in",
    "merchant_payment_code": "{<unique_payment_code>}",
    "order_number": null,
    "status": "PE",
    "status_date": null,
    "open_date": "2026-03-22 15:14:39",
    "confirm_date": null,
    "transfer_date": null,
    "amount_br": "200.00",
    "amount_ext": "200.00",
    "amount_iof": "0.00",
    "currency_rate": "1.0000",
    "currency_ext": "INR",
    "due_date": "2026-03-22 15:19:39",
    "instalments": "1",
    "payment_type_code": "upi-intent-autopay",
    "pre_approved": false,
    "capture_available": null,
    "customer": {
    "document": "",
    "email": "john.doe@example.com",
    "name": "John Doe",
    "birth_date": null
    },
    "single_transaction": {
    "amount_local": "0.00",
    "amount_crossborder": "200.00"
    },
    "upi": {
    "expiration_date": "2026-03-22 20:49:39",
    "app_links": [
    "gpay://upi/mandate?pa=pay.merch0000000@bankltd&pn=Merchant&mn=Create+Mandate&validitystart=22032026&validityend=31122035&am=1.00&am=200.00&amrule=MAX&recur=ASPRESENTED&tr=000000000000&cu=INR&mc=5817&mc=0000&mode=00&purpose=00&txnType=CREATE&rev=Y&block=N",
    "phonepe://mandate?pa=pay.merch0000000@bankltd&pn=Merchant&mn=Create+Mandate&validitystart=22032026&validityend=31122035&am=1.00&am=200.00&amrule=MAX&recur=ASPRESENTED&tr=000000000000&cu=INR&mc=5817&mc=0000&mode=00&purpose=00&txnType=CREATE&rev=Y&block=N",
    "paytmmp://mandate?pa=pay.merch0000000@bankltd&pn=Merchant&mn=Create+Mandate&validitystart=22032026&validityend=31122035&am=1.00&am=200.00&amrule=MAX&recur=ASPRESENTED&tr=000000000000&cu=INR&mc=5817&mc=0000&mode=00&purpose=00&txnType=CREATE&rev=Y&block=N",
    "upi://mandate?pa=pay.merch0000000@bankltd&pn=Merchant&mn=Create+Mandate&validitystart=22032026&validityend=31122035&am=1.00&am=200.00&amrule=MAX&recur=ASPRESENTED&tr=000000000000&cu=INR&mc=5817&mc=0000&mode=00&purpose=00&txnType=CREATE&rev=Y&block=N"
    ]
    },
    "currency_ext_base": "INR"
    }
    }

    Deep links are URLs that direct users to a specific app or page within an app, enabling seamless navigation directly to the desired content. The deep link details for launching specific UPI apps are provided within the app_links object.

    • Google Pay App Link - Starts with gpay://upi/mandate?..
    • PhonePe App Link - Starts with phonepe://mandate?..
    • Paytm App Link - Starts with paytmmp://mandate?..
    • Generic UPI App Link - Starts with upi://mandate?...
    Note

    The generic app link (upi://mandate?...) can only be used on Android. iOS does not support generic UPI links correctly.

  5. Confirming the Enrollment

    As soon as the enrollment is confirmed by the customer in their banking app, the enrollment status is modified from pending to accepted, and a Status Update Notification is sent to the URL defined in your merchant configuration. Check the notification example below:

    operation=enrollment_status_change&notification_type=update&merchant_enrollment_code=99911110104

    To ensure efficient and compliant interactions, EBANX allows merchants to confirm a user's enrollment status before sending multiple notifications or processing transactions.

    So, before requesting any payments, using the ID provided in merchant_enrollment_code, call the /ws/userenrollments/query endpoint to get the latest status of the enrollment.

    Check the example:

    curl -X POST \
    --location 'https://sandbox.ebanx.com/ws/userenrollments/query' \
    --header 'Content-Type: application/json' \
    --data '{
    "integration_key": "{<integration_key>}",
    "payment_type_code": "{<payment_type_code>}",
    "enrollment": {
    "country": "in",
    "merchant_enrollment_code": "{<unique_enrollment_code>}"
    }
    }'

    A successful request will return a JSON response like the one below, with a status of accepted for the enrollment approved by the customer. Other possible enrollment statuses include not accepted, paused, pending, expired, not_found, and revoked, depending on the actions taken by the merchant or customer.

    {
    "status": "SUCCESS",
    "payment_type": "{<payment_type_code>}",
    "enrollment": {
    "status": "accepted"
    }
    }

    If your enrollment has the status accepted, you can start requesting the recurring payments following the instructions on the Recurring Payment Request page.

  6. Monitor payment for status changes

    Notifications

    Status

  7. Congratulations!

    You have successfully integrated UPI Autopay Enrollment using Intent/QR.

    For more information, refer to the
    Direct API reference guidechevron_right

UPI Intent UX Flow

This demo illustrates the end-to-end payment experience with UPI Intent (or UPI App) flow. The journey begins on the merchant's checkout page, where the customer selects the UPI App. After submitting the request, the generic intent link (only applicable for Android devices) is invoked on merchant checkout, which opens the Android tray of UPI Apps. The user clicks on the desired UPI app, which redirects them to the application. The user reviews and approves the mandate directly within the app, and once confirmed, both the customer and the merchant receive immediate mandate confirmation.

Guidelines
  • This method only works on mobile flows (app or mobile-web). Intent flow does not work on laptop, tablet, or desktop web flows.
  • The generic intent link only works on Android. For iOS, this functionality doesn't exist due to OS limitations. This option should not be shown on iOS.
  • Use a reverse timer to highlight the end of the session to the user (industry-wide norm is 5 minutes). The user is expected to complete authentication during this time.

UPI QR Code UX Flow

This demo illustrates the end-to-end payment experience with the UPI QR code flow. The journey begins on the merchant's checkout page, where the customer selects the UPI QR code. After submitting the request, the QR code is shown on the checkout page for the user to scan. The user selects their desired UPI app and scans the QR code shown. The user reviews and approves the mandate directly within the app, and once confirmed, both the customer and the merchant receive immediate mandate confirmation.

Guidelines
  • This method is most preferred on desktop flows, but can still work on mobile flows through a "Download QR" option.
  • There should be a "Download QR" option if the method is being shown on mobile flows.
  • Using a reverse timer (industry-wide norm is 5 minutes) to highlight the end of the session to the user is a good practice. The user is expected to complete the authentication during this time.
  • It is recommended to add step-wise user guidance on the checkout page along with the reverse timer for better user experience, such as:
    • Step 1: Open your UPI app
    • Step 2: Scan the QR code shown above
    • Step 3: Authorise the mandate with UPI PIN
    • Step 4: Do not refresh this page and wait for the final status

Still need help?

Help Image

We hope this article was helpful. If you still have questions, you can explore the following options: