Bug: [FEATURE] add cypress tests for void payment in v2



### Feature Description

This implementation adds comprehensive V2 API testing for payment void/cancel operations across different payment states. The feature introduces a new Cypress test suite that validates three critical scenarios: successfully voiding a payment in the requires_capture state `after manual capture confirmation`, attempting to void a payment in the `requires_payment_method` state, and attempting to void a completed payment in the `succeeded` state.

### Possible Implementation

A new test file `VoidPayments.cy.js` contains three separate test contexts that verify void behavior across payment states using both manual and automatic capture flows.

### Have you spent some time checking if this feature request has been raised before?

- [x] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [x] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

Yes, I am willing to submit a PR!
diff --git a/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js b/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js
index 3f09a83e804..7090f5a1406 100644
--- a/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js
+++ b/cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js
@@ -5,7 +5,7 @@ import { getCustomExchange } from "./_Reusable";
 const successfulNo3DSCardDetails = {
   card_number: "4111111111111111",
   card_exp_month: "08",
-  card_exp_year: "25",
+  card_exp_year: "28",
   card_holder_name: "joseph Doe",
   card_cvc: "999",
 };
@@ -13,7 +13,7 @@ const successfulNo3DSCardDetails = {
 const successfulThreeDSTestCardDetails = {
   card_number: "4111111111111111",
   card_exp_month: "10",
-  card_exp_year: "25",
+  card_exp_year: "28",
   card_holder_name: "morino",
   card_cvc: "999",
 };
@@ -52,6 +52,36 @@ const multiUseMandateData = {
   },
 };
 
+const billingAddress = {
+  address: {
+    line1: "1467",
+    line2: "Harrison Street",
+    line3: "Harrison Street",
+    city: "San Fransico",
+    state: "California",
+    zip: "94122",
+    country: "US",
+    first_name: "joseph",
+    last_name: "Doe",
+  },
+  email: "example@example.com",
+};
+
+const shippingAddress = {
+  address: {
+    line1: "1467",
+    line2: "Harrison Street",
+    line3: "Harrison Street",
+    city: "San Fransico",
+    state: "California",
+    zip: "94122",
+    country: "US",
+    first_name: "joseph",
+    last_name: "Doe",
+  },
+  email: "example@example.com",
+};
+
 export const payment_methods_enabled = [
   {
     payment_method_type: "bank_debit",
@@ -368,19 +398,7 @@ export const connectorDetails = {
             pix: {},
           },
         },
-        billing: {
-          address: {
-            line1: "1467",
-            line2: "Harrison Street",
-            line3: "Harrison Street",
-            city: "San Fransico",
-            state: "California",
-            zip: "94122",
-            country: "BR",
-            first_name: "john",
-            last_name: "doe",
-          },
-        },
+        billing: billingAddress,
         currency: "BRL",
       },
     }),
@@ -409,19 +427,7 @@ export const connectorDetails = {
             },
           },
         },
-        billing: {
-          address: {
-            line1: "1467",
-            line2: "Harrison Street",
-            line3: "Harrison Street",
-            city: "San Fransico",
-            state: "California",
-            zip: "94122",
-            country: "NL",
-            first_name: "john",
-            last_name: "doe",
-          },
-        },
+        billing: billingAddress,
       },
     }),
     Giropay: getCustomExchange({
@@ -439,19 +445,7 @@ export const connectorDetails = {
             },
           },
         },
-        billing: {
-          address: {
-            line1: "1467",
-            line2: "Harrison Street",
-            line3: "Harrison Street",
-            city: "San Fransico",
-            state: "California",
-            zip: "94122",
-            country: "DE",
-            first_name: "john",
-            last_name: "doe",
-          },
-        },
+        billing: billingAddress,
       },
     }),
     Sofort: getCustomExchange({
@@ -466,19 +460,7 @@ export const connectorDetails = {
             },
           },
         },
-        billing: {
-          address: {
-            line1: "1467",
-            line2: "Harrison Street",
-            line3: "Harrison Street",
-            city: "San Fransico",
-            state: "California",
-            zip: "94122",
-            country: "DE",
-            first_name: "john",
-            last_name: "doe",
-          },
-        },
+        billing: billingAddress,
       },
     }),
     Eps: getCustomExchange({
@@ -492,19 +474,7 @@ export const connectorDetails = {
             },
           },
         },
-        billing: {
-          address: {
-            line1: "1467",
-            line2: "Harrison Street",
-            line3: "Harrison Street",
-            city: "San Fransico",
-            state: "California",
-            zip: "94122",
-            country: "AT",
-            first_name: "john",
-            last_name: "doe",
-          },
-        },
+        billing: billingAddress,
       },
     }),
     Przelewy24: getCustomExchange({
@@ -545,26 +515,19 @@ export const connectorDetails = {
             },
           },
         },
-        billing: {
-          address: {
-            line1: "1467",
-            line2: "Harrison Street",
-            line3: "Harrison Street",
-            city: "San Fransico",
-            state: "California",
-            zip: "94122",
-            country: "PL",
-            first_name: "john",
-            last_name: "doe",
-          },
-        },
+        billing: billingAddress,
       },
     }),
   },
   card_pm: {
     PaymentIntent: getCustomExchange({
       Request: {
-        currency: "USD",
+        amount_details: {
+          order_amount: 1001,
+          currency: "USD",
+        },
+        billing: billingAddress,
+        shipping: shippingAddress,
       },
       Response: {
         status: 200,
@@ -573,6 +536,7 @@ export const connectorDetails = {
         },
       },
     }),
+    
     PaymentIntentOffSession: getCustomExchange({
       Request: {
         currency: "USD",
@@ -583,7 +547,7 @@ export const connectorDetails = {
           status: "requires_payment_method",
         },
       },
-    }), 
+    }),
     "3DSManualCapture": getCustomExchange({
       Request: {
         payment_method: "card",
@@ -608,24 +572,36 @@ export const connectorDetails = {
     }),
     No3DSManualCapture: getCustomExchange({
       Request: {
-        payment_method: "card",
         payment_method_data: {
           card: successfulNo3DSCardDetails,
         },
-        currency: "USD",
+        payment_method_type: "card",
+        payment_method_subtype: "credit",
         customer_acceptance: null,
-        setup_future_usage: "on_session",
+      
+      },
+      Response: {
+        status: 200,
+        body: {
+          status: "requires_capture",
+        },
       },
     }),
     No3DSAutoCapture: getCustomExchange({
       Request: {
-        payment_method: "card",
         payment_method_data: {
           card: successfulNo3DSCardDetails,
         },
-        currency: "USD",
+        payment_method_type: "card",
+        payment_method_subtype: "credit",
         customer_acceptance: null,
-        setup_future_usage: "on_session",
+        shipping: shippingAddress,
+      },
+      Response: {
+        status: 200,
+        body: {
+          status: "succeeded",
+        },
       },
     }),
     Capture: getCustomExchange({
@@ -634,7 +610,6 @@ export const connectorDetails = {
         payment_method_data: {
           card: successfulNo3DSCardDetails,
         },
-        currency: "USD",
         customer_acceptance: null,
       },
     }),
@@ -659,8 +634,28 @@ export const connectorDetails = {
           error: {
             type: "invalid_request",
             message:
-              "You cannot cancel this payment because it has status succeeded",
-            code: "IR_16",
+              "This Payment could not be PaymentsCancel because it has a status of requires_payment_method. The expected state is requires_capture, partially_captured_and_capturable, partially_authorized_and_requires_capture",
+            code: "IR_14",
+          },
+        },
+      },
+    }),
+    VoidAfterConfirm: getCustomExchange({
+      Request: {},
+      Response: {
+        status: 200,
+        body: {
+          status: "cancelled",
+        },
+      },
+      ResponseCustom: {
+        status: 400,
+        body: {
+          error: {
+            type: "invalid_request",
+            message:
+              "This Payment could not be PaymentsCancel because it has a status of succeeded. The expected state is requires_capture, partially_captured_and_capturable, partially_authorized_and_requires_capture",
+            code: "IR_14",
           },
         },
       },
@@ -671,7 +666,6 @@ export const connectorDetails = {
         payment_method_data: {
           card: successfulNo3DSCardDetails,
         },
-        currency: "USD",
         customer_acceptance: null,
       },
       ResponseCustom: {
@@ -970,7 +964,7 @@ export const connectorDetails = {
           error: {
             error_type: "invalid_request",
             message: "Json deserialize error: invalid card number length",
-            code: "IR_06"
+            code: "IR_06",
           },
         },
       },
@@ -1077,8 +1071,9 @@ export const connectorDetails = {
         body: {
           error: {
             error_type: "invalid_request",
-            message: "Json deserialize error: unknown variant `United`, expected one of `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTN`, `BWP`, `BYN`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `IRR`, `ISK`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`, `ZWL`",
-            code: "IR_06"
+            message:
+              "Json deserialize error: unknown variant `United`, expected one of `AED`, `AFN`, `ALL`, `AMD`, `ANG`, `AOA`, `ARS`, `AUD`, `AWG`, `AZN`, `BAM`, `BBD`, `BDT`, `BGN`, `BHD`, `BIF`, `BMD`, `BND`, `BOB`, `BRL`, `BSD`, `BTN`, `BWP`, `BYN`, `BZD`, `CAD`, `CDF`, `CHF`, `CLP`, `CNY`, `COP`, `CRC`, `CUP`, `CVE`, `CZK`, `DJF`, `DKK`, `DOP`, `DZD`, `EGP`, `ERN`, `ETB`, `EUR`, `FJD`, `FKP`, `GBP`, `GEL`, `GHS`, `GIP`, `GMD`, `GNF`, `GTQ`, `GYD`, `HKD`, `HNL`, `HRK`, `HTG`, `HUF`, `IDR`, `ILS`, `INR`, `IQD`, `IRR`, `ISK`, `JMD`, `JOD`, `JPY`, `KES`, `KGS`, `KHR`, `KMF`, `KPW`, `KRW`, `KWD`, `KYD`, `KZT`, `LAK`, `LBP`, `LKR`, `LRD`, `LSL`, `LYD`, `MAD`, `MDL`, `MGA`, `MKD`, `MMK`, `MNT`, `MOP`, `MRU`, `MUR`, `MVR`, `MWK`, `MXN`, `MYR`, `MZN`, `NAD`, `NGN`, `NIO`, `NOK`, `NPR`, `NZD`, `OMR`, `PAB`, `PEN`, `PGK`, `PHP`, `PKR`, `PLN`, `PYG`, `QAR`, `RON`, `RSD`, `RUB`, `RWF`, `SAR`, `SBD`, `SCR`, `SDG`, `SEK`, `SGD`, `SHP`, `SLE`, `SLL`, `SOS`, `SRD`, `SSP`, `STN`, `SVC`, `SYP`, `SZL`, `THB`, `TJS`, `TMT`, `TND`, `TOP`, `TRY`, `TTD`, `TWD`, `TZS`, `UAH`, `UGX`, `USD`, `UYU`, `UZS`, `VES`, `VND`, `VUV`, `WST`, `XAF`, `XCD`, `XOF`, `XPF`, `YER`, `ZAR`, `ZMW`, `ZWL`",
+            code: "IR_06",
           },
         },
       },
@@ -1105,8 +1100,9 @@ export const connectorDetails = {
         body: {
           error: {
             error_type: "invalid_request",
-            message: "Json deserialize error: unknown variant `auto`, expected one of `automatic`, `manual`, `manual_multiple`, `scheduled`",
-            code: "IR_06"
+            message:
+              "Json deserialize error: unknown variant `auto`, expected one of `automatic`, `manual`, `manual_multiple`, `scheduled`",
+            code: "IR_06",
           },
         },
       },
@@ -1132,8 +1128,9 @@ export const connectorDetails = {
         body: {
           error: {
             error_type: "invalid_request",
-            message: "Json deserialize error: unknown variant `this_supposed_to_be_a_card`, expected one of `card`, `card_redirect`, `pay_later`, `wallet`, `bank_redirect`, `bank_transfer`, `crypto`, `bank_debit`, `reward`, `real_time_payment`, `upi`, `voucher`, `gift_card`, `open_banking`, `mobile_payment`",
-            code: "IR_06"
+            message:
+              "Json deserialize error: unknown variant `this_supposed_to_be_a_card`, expected one of `card`, `card_redirect`, `pay_later`, `wallet`, `bank_redirect`, `bank_transfer`, `crypto`, `bank_debit`, `reward`, `real_time_payment`, `upi`, `voucher`, `gift_card`, `open_banking`, `mobile_payment`",
+            code: "IR_06",
           },
         },
       },
@@ -1202,7 +1199,8 @@ export const connectorDetails = {
         body: {
           error: {
             type: "invalid_request",
-            message: "A payment token or payment method data or ctp service details is required",
+            message:
+              "A payment token or payment method data or ctp service details is required",
             code: "IR_06",
           },
         },
diff --git a/cypress-tests-v2/cypress/e2e/configs/Payment/Utils.js b/cypress-tests-v2/cypress/e2e/configs/Payment/Utils.js
index 569b557b690..c21a3c6a650 100644
--- a/cypress-tests-v2/cypress/e2e/configs/Payment/Utils.js
+++ b/cypress-tests-v2/cypress/e2e/configs/Payment/Utils.js
@@ -5,7 +5,7 @@ const connectorDetails = {
 };
 
 export default function getConnectorDetails(connectorId) {
-  let x = mergeDetails(connectorId);
+  const x = mergeDetails(connectorId);
   return x;
 }
 
@@ -61,9 +61,9 @@ export const should_continue_further = (res_data) => {
   }
 
   if (
-    res_data.body.error !== undefined ||
-    res_data.body.error_code !== undefined ||
-    res_data.body.error_message !== undefined
+    res_data.Response.body.error !== undefined ||
+    res_data.Response.body.error_code !== undefined ||
+    res_data.Response.body.error_message !== undefined
   ) {
     return false;
   } else {
@@ -89,9 +89,12 @@ export function defaultErrorHandler(response, response_data) {
   if (typeof response.body.error === "object") {
     for (const key in response_data.body.error) {
       // Check if the error message is a Json deserialize error
-      let apiResponseContent = response.body.error[key];
-      let expectedContent = response_data.body.error[key];
-      if (typeof apiResponseContent === "string" && apiResponseContent.includes("Json deserialize error")) {
+      const apiResponseContent = response.body.error[key];
+      const expectedContent = response_data.body.error[key];
+      if (
+        typeof apiResponseContent === "string" &&
+        apiResponseContent.includes("Json deserialize error")
+      ) {
         expect(apiResponseContent).to.include(expectedContent);
       } else {
         expect(apiResponseContent).to.equal(expectedContent);
diff --git a/cypress-tests-v2/cypress/e2e/configs/Payment/_Reusable.js b/cypress-tests-v2/cypress/e2e/configs/Payment/_Reusable.js
index 353d96260b5..d24e96cfdf8 100644
--- a/cypress-tests-v2/cypress/e2e/configs/Payment/_Reusable.js
+++ b/cypress-tests-v2/cypress/e2e/configs/Payment/_Reusable.js
@@ -46,9 +46,7 @@ with `getCustomExchange`, if 501 response is expected, there is no need to pass
 
 // Const to get default PaymentExchange object
 const getDefaultExchange = () => ({
-  Request: {
-    currency: "EUR",
-  },
+  Request: {},
   Response: {
     status: 501,
     body: {
@@ -62,9 +60,7 @@ const getDefaultExchange = () => ({
 });
 
 const getUnsupportedExchange = () => ({
-  Request: {
-    currency: "EUR",
-  },
+  Request: {},
   Response: {
     status: 400,
     body: {
diff --git a/cypress-tests-v2/cypress/e2e/spec/Payment/0001-[No3DS]Payments.cy.js b/cypress-tests-v2/cypress/e2e/spec/Payment/0001-[No3DS]Payments.cy.js
index 21766617c09..06afc506bcb 100644
--- a/cypress-tests-v2/cypress/e2e/spec/Payment/0001-[No3DS]Payments.cy.js
+++ b/cypress-tests-v2/cypress/e2e/spec/Payment/0001-[No3DS]Payments.cy.js
@@ -40,12 +40,11 @@ describe("[Payment] [No 3DS] [Payment Method: Card]", () => {
       let req_data = data["Request"];
       let res_data = data["Response"];
       cy.paymentIntentCreateCall(
+        globalState,
         fixtures.createPaymentBody,
-        req_data,
         res_data,
         "no_three_ds",
-        "automatic",
-        globalState
+        "automatic"
       );
     });
 
@@ -59,7 +58,7 @@ describe("[Payment] [No 3DS] [Payment Method: Card]", () => {
       ];
       let req_data = data["Request"];
       let res_data = data["Response"];
-      cy.paymentIntentConfirmCall(
+      cy.paymentConfirmCall(
         fixtures.confirmBody,
         req_data,
         res_data,
@@ -97,12 +96,11 @@ describe("[Payment] [No 3DS] [Payment Method: Card]", () => {
       let req_data = data["Request"];
       let res_data = data["Response"];
       cy.paymentIntentCreateCall(
+        globalState,
         fixtures.createPaymentBody,
-        req_data,
         res_data,
         "no_three_ds",
-        "automatic",
-        globalState
+        "automatic"
       );
     });
 
@@ -116,7 +114,7 @@ describe("[Payment] [No 3DS] [Payment Method: Card]", () => {
       ];
       let req_data = data["Request"];
       let res_data = data["Response"];
-      cy.paymentIntentConfirmCall(
+      cy.paymentConfirmCall(
         fixtures.confirmBody,
         req_data,
         res_data,
diff --git a/cypress-tests-v2/cypress/e2e/spec/Payment/0003-VoidPayments.cy.js b/cypress-tests-v2/cypress/e2e/spec/Payment/0003-VoidPayments.cy.js
new file mode 100644
index 00000000000..76fb97d9644
--- /dev/null
+++ b/cypress-tests-v2/cypress/e2e/spec/Payment/0003-VoidPayments.cy.js
@@ -0,0 +1,207 @@
+/*
+V2 Void/Cancel Payment Tests
+Test scenarios:
+1. Void payment in requires_capture state
+2. Void payment in requires_payment_method state
+3. Void payment in succeeded state (should fail)
+*/
+
+import * as fixtures from "../../../fixtures/imports";
+import State from "../../../utils/State";
+import getConnectorDetails, {
+  should_continue_further,
+} from "../../configs/Payment/Utils";
+
+let globalState;
+
+describe("[Payment] [Void/Cancel] [Payment Method: Card]", () => {
+  context("[Payment] [Void] [Requires Capture State]", () => {
+    let should_continue = true;
+
+    before("seed global state", () => {
+      cy.task("getGlobalState").then((state) => {
+        globalState = new State(state);
+      });
+    });
+
+    beforeEach(function () {
+      if (!should_continue) {
+        this.skip();
+      }
+    });
+
+    after("flush global state", () => {
+      cy.task("setGlobalState", globalState.data);
+    });
+
+    it("Create payment intent", () => {
+      const data = getConnectorDetails(globalState.get("connectorId"))[
+        "card_pm"
+      ]["PaymentIntent"];
+      const req_data = data["Request"];
+      const res_data = data["Response"];
+
+      cy.paymentIntentCreateCall(
+        globalState,
+        req_data,
+        res_data,
+        "no_three_ds",
+        "manual"
+      );
+
+      if (should_continue) should_continue = should_continue_further(data);
+    });
+
+    it("Confirm payment intent", () => {
+      const data = getConnectorDetails(globalState.get("connectorId"))[
+        "card_pm"
+      ]["No3DSManualCapture"];
+      const req_data = data["Request"];
+
+      cy.paymentConfirmCall(globalState, req_data, data);
+
+      if (should_continue) should_continue = should_continue_further(data);
+    });
+
+    it("Void payment intent", () => {
+      const data = getConnectorDetails(globalState.get("connectorId"))[
+        "card_pm"
+      ]["VoidAfterConfirm"];
+
+      cy.paymentVoidCall(globalState, fixtures.void_payment_body, data);
+
+      if (should_continue) should_continue = should_continue_further(data);
+    });
+  });
+
+  context(
+    "[Payment] [Void] [Requires Payment Method State - Should Fail]",
+    () => {
+      let should_continue = true;
+
+      before("seed global state", () => {
+        cy.task("getGlobalState").then((state) => {
+          globalState = new State(state);
+        });
+      });
+
+      beforeEach(function () {
+        if (!should_continue) {
+          this.skip();
+        }
+      });
+
+      after("flush global state", () => {
+        cy.task("setGlobalState", globalState.data);
+      });
+
+      it("Create payment intent", () => {
+        const data = getConnectorDetails(globalState.get("connectorId"))[
+          "card_pm"
+        ]["PaymentIntent"];
+        const req_data = data["Request"];
+        const res_data = data["Response"];
+
+        cy.paymentIntentCreateCall(
+          globalState,
+          req_data,
+          res_data,
+          "no_three_ds",
+          "manual"
+        );
+
+        if (should_continue) should_continue = should_continue_further(data);
+      });
+
+      it("Void payment intent - should fail", () => {
+        const data = getConnectorDetails(globalState.get("connectorId"))[
+          "card_pm"
+        ]["Void"];
+
+        // Use the ResponseCustom which contains the error response
+        const void_data = {
+          ...data,
+          Response: data.ResponseCustom,
+        };
+
+        cy.paymentVoidCall(
+          globalState,
+          fixtures.void_payment_body,
+          void_data
+        );
+
+        if (should_continue) should_continue = should_continue_further(data);
+      });
+    }
+  );
+
+  context("[Payment] [Void] [Succeeded State - Should Fail]", () => {
+    let should_continue = true;
+
+    before("seed global state", () => {
+      cy.task("getGlobalState").then((state) => {
+        globalState = new State(state);
+      });
+    });
+
+    beforeEach(function () {
+      if (!should_continue) {
+        this.skip();
+      }
+    });
+
+    after("flush global state", () => {
+      cy.task("setGlobalState", globalState.data);
+    });
+
+    it("Create payment intent", () => {
+      const data = getConnectorDetails(globalState.get("connectorId"))[
+        "card_pm"
+      ]["PaymentIntent"];
+
+      const req_data = data["Request"];
+      const res_data = data["Response"];
+
+      cy.paymentIntentCreateCall(
+        globalState,
+        req_data,
+        res_data,
+        "no_three_ds",
+        "automatic"
+      );
+
+      if (should_continue) should_continue = should_continue_further(data);
+    });
+
+    it("Confirm payment intent", () => {
+      const data = getConnectorDetails(globalState.get("connectorId"))[
+        "card_pm"
+      ]["No3DSAutoCapture"];
+      const req_data = data["Request"];
+
+      cy.paymentConfirmCall(globalState, req_data, data);
+
+      if (should_continue) should_continue = should_continue_further(data);
+    });
+
+    it("Void payment intent - should fail", () => {
+      const data = getConnectorDetails(globalState.get("connectorId"))[
+        "card_pm"
+      ]["VoidAfterConfirm"];
+
+      // Use the ResponseCustom which contains the error response
+      const void_data = {
+        ...data,
+        Response: data.ResponseCustom,
+      };
+
+      cy.paymentVoidCall(
+        globalState,
+        fixtures.void_payment_body,
+        void_data
+      );
+
+      if (should_continue) should_continue = should_continue_further(data);
+    });
+  });
+});
diff --git a/cypress-tests-v2/cypress/fixtures/imports.js b/cypress-tests-v2/cypress/fixtures/imports.js
index 30f0dfb50c2..4b3f8c4b89e 100644
--- a/cypress-tests-v2/cypress/fixtures/imports.js
+++ b/cypress-tests-v2/cypress/fixtures/imports.js
@@ -4,6 +4,7 @@ import merchant_account_body from "./merchant_account.json";
 import merchant_connector_account_body from "./merchant_connector_account.json";
 import organization_body from "./organization.json";
 import routing_body from "./routing.json";
+import void_payment_body from "./void_payment.json";
 
 export {
   api_key_body,
@@ -12,4 +13,5 @@ export {
   merchant_connector_account_body,
   organization_body,
   routing_body,
+  void_payment_body,
 };
diff --git a/cypress-tests-v2/cypress/fixtures/void_payment.json b/cypress-tests-v2/cypress/fixtures/void_payment.json
new file mode 100644
index 00000000000..471d90d6c48
--- /dev/null
+++ b/cypress-tests-v2/cypress/fixtures/void_payment.json
@@ -0,0 +1,3 @@
+{
+  "cancellation_reason": "requested_by_customer"
+}
diff --git a/cypress-tests-v2/cypress/support/commands.js b/cypress-tests-v2/cypress/support/commands.js
index e77a0f65143..7afa35152c6 100644
--- a/cypress-tests-v2/cypress/support/commands.js
+++ b/cypress-tests-v2/cypress/support/commands.js
@@ -27,7 +27,10 @@
 //  cy.task can only be used in support files (spec files or commands file)
 
 import { nanoid } from "nanoid";
-import { getValueByKey } from "../e2e/configs/Payment/Utils.js";
+import {
+  defaultErrorHandler,
+  getValueByKey,
+} from "../e2e/configs/Payment/Utils.js";
 import { isoTimeTomorrow, validateEnv } from "../utils/RequestBodyUtils.js";
 
 function logRequestId(xRequestId) {
@@ -55,7 +58,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
       },
       body: organizationCreateBody,
       failOnStatusCode: false,
@@ -91,7 +94,7 @@ Cypress.Commands.add("organizationRetrieveCall", (globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
     },
     failOnStatusCode: false,
   }).then((response) => {
@@ -135,7 +138,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
       },
       body: organizationUpdateBody,
       failOnStatusCode: false,
@@ -185,7 +188,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
         "X-Organization-Id": organization_id,
       },
       body: merchantAccountCreateBody,
@@ -230,7 +233,7 @@ Cypress.Commands.add("merchantAccountRetrieveCall", (globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
     },
     failOnStatusCode: false,
   }).then((response) => {
@@ -274,7 +277,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
       },
       body: merchantAccountUpdateBody,
       failOnStatusCode: false,
@@ -324,7 +327,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
         "x-merchant-id": merchant_id,
         ...customHeaders,
       },
@@ -369,7 +372,7 @@ Cypress.Commands.add("businessProfileRetrieveCall", (globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       ...customHeaders,
     },
     failOnStatusCode: false,
@@ -411,7 +414,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
         ...customHeaders,
       },
       body: businessProfileUpdateBody,
@@ -503,7 +506,7 @@ Cypress.Commands.add(
           url: url,
           headers: {
             "Content-Type": "application/json",
-            "Authorization": `admin-api-key=${api_key}`,
+            Authorization: `admin-api-key=${api_key}`,
             ...customHeaders,
           },
           body: mcaCreateBody,
@@ -551,7 +554,7 @@ Cypress.Commands.add("mcaRetrieveCall", (globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       ...customHeaders,
     },
     failOnStatusCode: false,
@@ -611,7 +614,7 @@ Cypress.Commands.add(
       url: url,
       headers: {
         "Content-Type": "application/json",
-        "Authorization": `admin-api-key=${api_key}`,
+        Authorization: `admin-api-key=${api_key}`,
         ...customHeaders,
       },
       body: mcaUpdateBody,
@@ -671,7 +674,7 @@ Cypress.Commands.add("apiKeyCreateCall", (apiKeyCreateBody, globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       ...customHeaders,
     },
     body: apiKeyCreateBody,
@@ -718,7 +721,7 @@ Cypress.Commands.add("apiKeyRetrieveCall", (globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       ...customHeaders,
     },
     failOnStatusCode: false,
@@ -768,7 +771,7 @@ Cypress.Commands.add("apiKeyUpdateCall", (apiKeyUpdateBody, globalState) => {
     url: url,
     headers: {
       "Content-Type": "application/json",
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       ...customHeaders,
     },
     body: apiKeyUpdateBody,
@@ -1176,7 +1179,7 @@ Cypress.Commands.add("merchantAccountsListCall", (globalState) => {
     method: "GET",
     url: url,
     headers: {
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       "Content-Type": "application/json",
     },
     failOnStatusCode: false,
@@ -1218,7 +1221,7 @@ Cypress.Commands.add("businessProfilesListCall", (globalState) => {
     method: "GET",
     url: url,
     headers: {
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       "Content-Type": "application/json",
       ...customHeaders,
     },
@@ -1261,7 +1264,7 @@ Cypress.Commands.add("mcaListCall", (globalState, service_type) => {
     method: "GET",
     url: url,
     headers: {
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       "Content-Type": "application/json",
       ...customHeaders,
     },
@@ -1323,7 +1326,7 @@ Cypress.Commands.add("apiKeysListCall", (globalState) => {
     method: "GET",
     url: url,
     headers: {
-      "Authorization": `admin-api-key=${api_key}`,
+      Authorization: `admin-api-key=${api_key}`,
       "Content-Type": "application/json",
       ...customHeaders,
     },
@@ -1354,13 +1357,64 @@ Cypress.Commands.add("apiKeysListCall", (globalState) => {
 // Payment API calls
 // Update the below commands while following the conventions
 // Below is an example of how the payment intent create call should look like (update the below command as per the need)
+
+Cypress.Commands.add(
+  "paymentVoidCall",
+  (globalState, voidRequestBody, data) => {
+    const { Request: reqData = {}, Response: resData } = data || {};
+
+    // Define the necessary variables and constants at the top
+    const api_key = globalState.get("apiKey");
+    const base_url = globalState.get("baseUrl");
+    const profile_id = globalState.get("profileId");
+    const payment_id = globalState.get("paymentID");
+    const url = `${base_url}/v2/payments/${payment_id}/cancel`;
+
+    // Apply connector-specific request data (including cancellation_reason)
+    for (const key in reqData) {
+      voidRequestBody[key] = reqData[key];
+    }
+
+    // Pass Custom Headers
+    const customHeaders = {
+      "x-profile-id": profile_id,
+    };
+
+    cy.request({
+      method: "POST",
+      url: url,
+      headers: {
+        Authorization: `api-key=${api_key}`,
+        "Content-Type": "application/json",
+        ...customHeaders,
+      },
+      body: voidRequestBody,
+      failOnStatusCode: false,
+    }).then((response) => {
+      // Logging x-request-id is mandatory
+      logRequestId(response.headers["x-request-id"]);
+
+      cy.wrap(response).then(() => {
+        expect(response.headers["content-type"]).to.include("application/json");
+        if (response.status === 200) {
+          for (const key in resData.body) {
+            expect(resData.body[key]).to.equal(response.body[key]);
+          }
+        } else {
+          defaultErrorHandler(response, resData);
+        }
+      });
+    });
+  }
+);
 Cypress.Commands.add(
   "paymentIntentCreateCall",
   (
     globalState,
     paymentRequestBody,
-    paymentResponseBody
-    /* Add more variables based on the need*/
+    paymentResponseBody,
+    authentication_type,
+    capture_method
   ) => {
     // Define the necessary variables and constants at the top
     // Also construct the URL here
@@ -1369,8 +1423,9 @@ Cypress.Commands.add(
     const profile_id = globalState.get("profileId");
     const url = `${base_url}/v2/payments/create-intent`;
 
-    // Update request body if needed
-    paymentRequestBody = {};
+    // Set capture_method and authentication_type as parameters (like V1)
+    paymentRequestBody.authentication_type = authentication_type;
+    paymentRequestBody.capture_method = capture_method;
 
     // Pass Custom Headers
     const customHeaders = {
@@ -1381,7 +1436,7 @@ Cypress.Commands.add(
       method: "POST",
       url: url,
       headers: {
-        "api-key": api_key,
+        Authorization: `api-key=${api_key}`,
         "Content-Type": "application/json",
         ...customHeaders,
       },
@@ -1391,28 +1446,113 @@ Cypress.Commands.add(
       // Logging x-request-id is mandatory
       logRequestId(response.headers["x-request-id"]);
 
-      if (response.status === 200) {
-        // Update the assertions based on the need
-        expect(response.body).to.deep.equal(paymentResponseBody);
-      } else if (response.status === 400) {
-        // Add 4xx validations here
-        expect(response.body).to.deep.equal(paymentResponseBody);
-      } else if (response.status === 500) {
-        // Add 5xx validations here
-        expect(response.body).to.deep.equal(paymentResponseBody);
-      } else {
-        // If status code is other than the ones mentioned above, default should be thrown
-        throw new Error(
-          `Payment intent create call failed with status ${response.status} and message: "${response.body.error.message}"`
-        );
-      }
+      cy.wrap(response).then(() => {
+        expect(response.headers["content-type"]).to.include("application/json");
+        if (response.status === 200) {
+          // Validate the payment create response - V2 uses different ID format
+          expect(response.body).to.have.property("id").and.to.be.a("string").and
+            .not.be.empty;
+          expect(response.body).to.have.property("status");
+
+          // Store the payment ID for future use
+          globalState.set("paymentID", response.body.id);
+
+          // Log payment creation success
+          cy.task(
+            "cli_log",
+            `Payment created with ID: ${response.body.id}, Status: ${response.body.status}`
+          );
+
+          if (paymentResponseBody && paymentResponseBody.body) {
+            for (const key in paymentResponseBody.body) {
+              if (paymentResponseBody.body[key] !== null) {
+                expect(response.body[key]).to.equal(
+                  paymentResponseBody.body[key]
+                );
+              }
+            }
+          }
+        } else {
+          defaultErrorHandler(response, paymentResponseBody);
+        }
+      });
     });
   }
 );
-Cypress.Commands.add("paymentIntentConfirmCall", (globalState) => {});
-Cypress.Commands.add("paymentIntentRetrieveCall", (globalState) => {});
+Cypress.Commands.add(
+  "paymentConfirmCall",
+  (globalState, paymentConfirmRequestBody, data) => {
+    const { Request: reqData = {}, Response: resData } = data || {};
 
-// templates for future use
-Cypress.Commands.add("", () => {
-  cy.request({}).then((response) => {});
-});
+    // Define the necessary variables and constants at the top
+    const api_key = globalState.get("apiKey");
+    const base_url = globalState.get("baseUrl");
+    const profile_id = globalState.get("profileId");
+    const payment_id = globalState.get("paymentID");
+    const url = `${base_url}/v2/payments/${payment_id}/confirm-intent`;
+
+    // Apply connector-specific request data
+    for (const key in reqData) {
+      paymentConfirmRequestBody[key] = reqData[key];
+    }
+
+    // Pass Custom Headers
+    const customHeaders = {
+      "x-profile-id": profile_id,
+    };
+
+    cy.request({
+      method: "POST",
+      url: url,
+      headers: {
+        Authorization: `api-key=${api_key}`,
+        "Content-Type": "application/json",
+        ...customHeaders,
+      },
+      body: paymentConfirmRequestBody,
+      failOnStatusCode: false,
+    }).then((response) => {
+      // Logging x-request-id is mandatory
+      logRequestId(response.headers["x-request-id"]);
+
+      cy.wrap(response).then(() => {
+        expect(response.headers["content-type"]).to.include("application/json");
+        if (response.status === 200) {
+          // Validate the payment confirm response
+          expect(response.body).to.have.property("id").and.to.be.a("string").and
+            .not.be.empty;
+          expect(response.body).to.have.property("status");
+
+          globalState.set("paymentID", response.body.id);
+
+          // Validate response body against expected data
+          if (resData && resData.body) {
+            for (const key in resData.body) {
+              // Skip validation if expected value is null or undefined
+              if (resData.body[key] == null) {
+                continue;
+              }
+              // Only validate if the field exists in the response and has a non-null value
+              if (
+                response.body.hasOwnProperty(key) &&
+                response.body[key] != null
+              ) {
+                // Use deep equal for object comparison, regular equal for primitives
+                if (
+                  typeof resData.body[key] === "object" &&
+                  typeof response.body[key] === "object"
+                ) {
+                  expect(response.body[key]).to.deep.equal(resData.body[key]);
+                } else {
+                  expect(response.body[key]).to.equal(resData.body[key]);
+                }
+              }
+            }
+          }
+        } else {
+          defaultErrorHandler(response, resData);
+        }
+      });
+    });
+  }
+);

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [X] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
This implementation adds comprehensive V2 API testing for payment void/cancel operations across different payment states. The feature introduces a new Cypress test suite that validates three critical scenarios: successfully voiding a payment in the requires_capture state `after manual capture confirmation`, attempting to void a payment in the `requires_payment_method` state, and attempting to void a completed payment in the `succeeded` state.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->
closes #9638 

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
<img width="1728" height="1117" alt="image" src="https://github.com/user-attachments/assets/8c5d6b12-3ccb-467e-a38f-13e1c9350d3c" />

<img width="1728" height="1061" alt="image" src="https://github.com/user-attachments/assets/4626ee99-8a0b-44c3-a2ed-f7f76c186209" />



## Checklist
<!-- Put an `x` in the boxes that apply -->

- [ ] I formatted the code `cargo +nightly fmt --all`
- [ ] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
