Bug: Payment method delete API for v2




diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs
index af3c657c34a..445ad5ab800 100644
--- a/crates/hyperswitch_domain_models/src/payment_methods.rs
+++ b/crates/hyperswitch_domain_models/src/payment_methods.rs
@@ -14,6 +14,20 @@ use time::PrimitiveDateTime;
 
 use crate::type_encryption::{crypto_operation, AsyncLift, CryptoOperation};
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
+pub struct VaultId(String);
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl VaultId {
+    pub fn get_string_repr(&self) -> &String {
+        &self.0
+    }
+
+    pub fn generate(id: String) -> Self {
+        Self(id)
+    }
+}
 #[cfg(all(
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
@@ -67,7 +81,7 @@ pub struct PaymentMethod {
     pub payment_method_type: Option<storage_enums::PaymentMethodType>,
     pub metadata: Option<pii::SecretSerdeValue>,
     pub payment_method_data: OptionalEncryptableValue,
-    pub locker_id: Option<String>,
+    pub locker_id: Option<VaultId>,
     pub last_used_at: PrimitiveDateTime,
     pub connector_mandate_details: Option<pii::SecretSerdeValue>,
     pub customer_acceptance: Option<pii::SecretSerdeValue>,
@@ -302,7 +316,7 @@ impl super::behaviour::Conversion for PaymentMethod {
             payment_method_type: self.payment_method_type,
             metadata: self.metadata,
             payment_method_data: self.payment_method_data.map(|val| val.into()),
-            locker_id: self.locker_id,
+            locker_id: self.locker_id.map(|id| id.get_string_repr().clone()),
             last_used_at: self.last_used_at,
             connector_mandate_details: self.connector_mandate_details,
             customer_acceptance: self.customer_acceptance,
@@ -356,7 +370,7 @@ impl super::behaviour::Conversion for PaymentMethod {
                         .and_then(|val| val.try_into_optionaloperation())
                     })
                     .await?,
-                locker_id: item.locker_id,
+                locker_id: item.locker_id.map(VaultId::generate),
                 last_used_at: item.last_used_at,
                 connector_mandate_details: item.connector_mandate_details,
                 customer_acceptance: item.customer_acceptance,
@@ -415,7 +429,7 @@ impl super::behaviour::Conversion for PaymentMethod {
             payment_method_type: self.payment_method_type,
             metadata: self.metadata,
             payment_method_data: self.payment_method_data.map(|val| val.into()),
-            locker_id: self.locker_id,
+            locker_id: self.locker_id.map(|id| id.get_string_repr().clone()),
             last_used_at: self.last_used_at,
             connector_mandate_details: self.connector_mandate_details,
             customer_acceptance: self.customer_acceptance,
diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs
index 1b93f05d823..721dd9de1c4 100644
--- a/crates/router/src/consts.rs
+++ b/crates/router/src/consts.rs
@@ -149,6 +149,26 @@ pub const VAULT_FINGERPRINT_REQUEST_URL: &str = "/fingerprint";
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub const VAULT_RETRIEVE_REQUEST_URL: &str = "/vault/retrieve";
 
+/// Vault Delete request url
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub const VAULT_DELETE_REQUEST_URL: &str = "/vault/delete";
+
 /// Vault Header content type
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub const VAULT_HEADER_CONTENT_TYPE: &str = "application/json";
+
+/// Vault Add flow type
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub const VAULT_ADD_FLOW_TYPE: &str = "add_to_vault";
+
+/// Vault Retrieve flow type
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub const VAULT_RETRIEVE_FLOW_TYPE: &str = "retrieve_from_vault";
+
+/// Vault Delete flow type
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub const VAULT_DELETE_FLOW_TYPE: &str = "delete_from_vault";
+
+/// Vault Fingerprint fetch flow type
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub const VAULT_GET_FINGERPRINT_FLOW_TYPE: &str = "get_fingerprint_vault";
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 8841ad7f383..9a093a065e4 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -1124,7 +1124,7 @@ pub async fn create_payment_method_in_db(
     req: &api::PaymentMethodCreate,
     customer_id: &id_type::CustomerId,
     payment_method_id: id_type::GlobalPaymentMethodId,
-    locker_id: Option<String>,
+    locker_id: Option<domain::VaultId>,
     merchant_id: &id_type::MerchantId,
     pm_metadata: Option<common_utils::pii::SecretSerdeValue>,
     customer_acceptance: Option<common_utils::pii::SecretSerdeValue>,
@@ -1276,12 +1276,12 @@ pub async fn vault_payment_method(
     pmd: &pm_types::PaymentMethodVaultingData,
     merchant_account: &domain::MerchantAccount,
     key_store: &domain::MerchantKeyStore,
-    existing_vault_id: Option<String>,
+    existing_vault_id: Option<domain::VaultId>,
 ) -> RouterResult<pm_types::AddVaultResponse> {
     let db = &*state.store;
 
-    // get fingerprint_id from locker
-    let fingerprint_id_from_locker = cards::get_fingerprint_id_from_locker(state, pmd)
+    // get fingerprint_id from vault
+    let fingerprint_id_from_vault = vault::get_fingerprint_id_from_vault(state, pmd)
         .await
         .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed to get fingerprint_id from vault")?;
@@ -1292,7 +1292,7 @@ pub async fn vault_payment_method(
             db.find_payment_method_by_fingerprint_id(
                 &(state.into()),
                 key_store,
-                &fingerprint_id_from_locker,
+                &fingerprint_id_from_vault,
             )
             .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
@@ -1305,13 +1305,13 @@ pub async fn vault_payment_method(
         },
     )?;
 
-    let resp_from_locker =
-        cards::vault_payment_method_in_locker(state, merchant_account, pmd, existing_vault_id)
+    let resp_from_vault =
+        vault::add_payment_method_to_vault(state, merchant_account, pmd, existing_vault_id)
             .await
             .change_context(errors::ApiErrorResponse::InternalServerError)
-            .attach_printable("Failed to vault payment method in locker")?;
+            .attach_printable("Failed to add payment method in vault")?;
 
-    Ok(resp_from_locker)
+    Ok(resp_from_vault)
 }
 
 #[cfg(all(
@@ -1339,10 +1339,12 @@ async fn get_pm_list_context(
                     storage::PaymentTokenData::permanent_card(
                         Some(pm.get_id().clone()),
                         pm.locker_id
-                            .clone()
+                            .as_ref()
+                            .map(|id| id.get_string_repr().clone())
                             .or(Some(pm.get_id().get_string_repr().to_owned())),
                         pm.locker_id
-                            .clone()
+                            .as_ref()
+                            .map(|id| id.get_string_repr().clone())
                             .unwrap_or(pm.get_id().get_string_repr().to_owned()),
                     ),
                 ),
@@ -1767,20 +1769,16 @@ pub async fn update_payment_method(
         },
     )?;
 
-    let pmd: pm_types::PaymentMethodVaultingData = cards::retrieve_payment_method_from_vault(
-        &state,
-        &merchant_account,
-        &payment_method.customer_id,
-        &payment_method,
-    )
-    .await
-    .change_context(errors::ApiErrorResponse::InternalServerError)
-    .attach_printable("Failed to retrieve payment method from vault")?
-    .data
-    .expose()
-    .parse_struct("PaymentMethodCreateData")
-    .change_context(errors::ApiErrorResponse::InternalServerError)
-    .attach_printable("Failed to parse PaymentMethodCreateData")?;
+    let pmd: pm_types::PaymentMethodVaultingData =
+        vault::retrieve_payment_method_from_vault(&state, &merchant_account, &payment_method)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to retrieve payment method from vault")?
+            .data
+            .expose()
+            .parse_struct("PaymentMethodVaultingData")
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to parse PaymentMethodVaultingData")?;
 
     let vault_request_data =
         pm_transforms::generate_pm_vaulting_req_from_update_request(pmd, req.payment_method_data);
@@ -1825,6 +1823,76 @@ pub async fn update_payment_method(
     Ok(services::ApplicationResponse::Json(response))
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn delete_payment_method(
+    state: SessionState,
+    pm_id: api::PaymentMethodId,
+    key_store: domain::MerchantKeyStore,
+    merchant_account: domain::MerchantAccount,
+) -> RouterResponse<api::PaymentMethodDeleteResponse> {
+    let db = state.store.as_ref();
+    let key_manager_state = &(&state).into();
+
+    let pm_id = id_type::GlobalPaymentMethodId::generate_from_string(pm_id.payment_method_id)
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Unable to generate GlobalPaymentMethodId")?;
+
+    let payment_method = db
+        .find_payment_method(
+            &((&state).into()),
+            &key_store,
+            &pm_id,
+            merchant_account.storage_scheme,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::PaymentMethodNotFound)?;
+
+    let vault_id = payment_method
+        .locker_id
+        .clone()
+        .get_required_value("locker_id")
+        .attach_printable("Missing locker_id in PaymentMethod")?;
+
+    let _customer = db
+        .find_customer_by_global_id(
+            key_manager_state,
+            payment_method.customer_id.get_string_repr(),
+            merchant_account.get_id(),
+            &key_store,
+            merchant_account.storage_scheme,
+        )
+        .await
+        .to_not_found_response(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Customer not found for the payment method")?;
+
+    // Soft delete
+    let pm_update = storage::PaymentMethodUpdate::StatusUpdate {
+        status: Some(enums::PaymentMethodStatus::Inactive),
+    };
+    db.update_payment_method(
+        &((&state).into()),
+        &key_store,
+        payment_method,
+        pm_update,
+        merchant_account.storage_scheme,
+    )
+    .await
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to update payment method in db")?;
+
+    vault::delete_payment_method_data_from_vault(&state, &merchant_account, vault_id)
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to delete payment method from vault")?;
+
+    let response = api::PaymentMethodDeleteResponse {
+        payment_method_id: pm_id.get_string_repr().to_string(),
+    };
+
+    Ok(services::ApplicationResponse::Json(response))
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 impl pm_types::SavedPMLPaymentsInfo {
     pub async fn form_payments_info(
diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs
index 3c09db61a39..5f931205931 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -221,37 +221,6 @@ pub async fn create_payment_method(
     Ok(response)
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-async fn create_vault_request<R: pm_types::VaultingInterface>(
-    jwekey: &settings::Jwekey,
-    locker: &settings::Locker,
-    payload: Vec<u8>,
-) -> errors::CustomResult<Request, errors::VaultError> {
-    let private_key = jwekey.vault_private_key.peek().as_bytes();
-
-    let jws = services::encryption::jws_sign_payload(
-        &payload,
-        &locker.locker_signing_key_id,
-        private_key,
-    )
-    .await
-    .change_context(errors::VaultError::RequestEncryptionFailed)?;
-
-    let jwe_payload = payment_methods::create_jwe_body_for_vault(jwekey, &jws).await?;
-
-    let mut url = locker.host.to_owned();
-    url.push_str(R::get_vaulting_request_url());
-    let mut request = Request::new(services::Method::Post, &url);
-    request.add_header(
-        headers::CONTENT_TYPE,
-        router_consts::VAULT_HEADER_CONTENT_TYPE.into(),
-    );
-    request.set_body(common_utils::request::RequestContent::Json(Box::new(
-        jwe_payload,
-    )));
-    Ok(request)
-}
-
 #[cfg(all(
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
@@ -1411,107 +1380,6 @@ pub async fn add_payment_method(
     Ok(services::ApplicationResponse::Json(resp))
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn get_fingerprint_id_from_locker<
-    D: pm_types::VaultingDataInterface + serde::Serialize,
->(
-    state: &routes::SessionState,
-    data: &D,
-) -> errors::CustomResult<String, errors::VaultError> {
-    let key = data.get_vaulting_data_key();
-    let data = serde_json::to_value(data)
-        .change_context(errors::VaultError::RequestEncodingFailed)
-        .attach_printable("Failed to encode Vaulting data to value")?
-        .to_string();
-
-    let payload = pm_types::VaultFingerprintRequest { key, data }
-        .encode_to_vec()
-        .change_context(errors::VaultError::RequestEncodingFailed)
-        .attach_printable("Failed to encode VaultFingerprintRequest")?;
-
-    let resp = call_to_vault::<pm_types::GetVaultFingerprint>(state, payload)
-        .await
-        .change_context(errors::VaultError::VaultAPIError)
-        .attach_printable("Failed to get response from locker")?;
-
-    let fingerprint_resp: pm_types::VaultFingerprintResponse = resp
-        .parse_struct("VaultFingerprintResp")
-        .change_context(errors::VaultError::ResponseDeserializationFailed)
-        .attach_printable("Failed to parse data into VaultFingerprintResp")?;
-
-    Ok(fingerprint_resp.fingerprint_id)
-}
-
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn vault_payment_method_in_locker(
-    state: &routes::SessionState,
-    merchant_account: &domain::MerchantAccount,
-    pmd: &pm_types::PaymentMethodVaultingData,
-    existing_vault_id: Option<String>,
-) -> errors::CustomResult<pm_types::AddVaultResponse, errors::VaultError> {
-    let payload = pm_types::AddVaultRequest {
-        entity_id: merchant_account.get_id().to_owned(),
-        vault_id: pm_types::VaultId::generate(
-            existing_vault_id.unwrap_or(uuid::Uuid::now_v7().to_string()),
-        ),
-        data: pmd,
-        ttl: state.conf.locker.ttl_for_storage_in_secs,
-    }
-    .encode_to_vec()
-    .change_context(errors::VaultError::RequestEncodingFailed)
-    .attach_printable("Failed to encode AddVaultRequest")?;
-
-    let resp = call_to_vault::<pm_types::AddVault>(state, payload)
-        .await
-        .change_context(errors::VaultError::VaultAPIError)
-        .attach_printable("Failed to get response from locker")?;
-
-    let stored_pm_resp: pm_types::AddVaultResponse = resp
-        .parse_struct("AddVaultResponse")
-        .change_context(errors::VaultError::ResponseDeserializationFailed)
-        .attach_printable("Failed to parse data into AddVaultResponse")?;
-
-    Ok(stored_pm_resp)
-}
-
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn retrieve_payment_method_from_vault(
-    state: &routes::SessionState,
-    merchant_account: &domain::MerchantAccount,
-    customer_id: &id_type::CustomerId,
-    pm: &domain::PaymentMethod,
-) -> errors::CustomResult<pm_types::VaultRetrieveResponse, errors::VaultError> {
-    let payload = pm_types::VaultRetrieveRequest {
-        entity_id: merchant_account.get_id().to_owned(),
-        vault_id: pm_types::VaultId::generate(
-            pm.locker_id
-                .clone()
-                .ok_or(errors::VaultError::MissingRequiredField {
-                    field_name: "locker_id",
-                })
-                .attach_printable("Missing locker_id for VaultRetrieveRequest")?,
-        ),
-    }
-    .encode_to_vec()
-    .change_context(errors::VaultError::RequestEncodingFailed)
-    .attach_printable("Failed to encode VaultRetrieveRequest")?;
-
-    let resp = call_to_vault::<pm_types::VaultRetrieve>(state, payload)
-        .await
-        .change_context(errors::VaultError::VaultAPIError)
-        .attach_printable("Failed to get response from locker")?;
-
-    let stored_pm_resp: pm_types::VaultRetrieveResponse = resp
-        .parse_struct("VaultRetrieveResponse")
-        .change_context(errors::VaultError::ResponseDeserializationFailed)
-        .attach_printable("Failed to parse data into VaultRetrieveResponse")?;
-
-    Ok(stored_pm_resp)
-}
-
 #[cfg(all(
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
@@ -2266,37 +2134,6 @@ pub async fn add_card_to_hs_locker(
     Ok(stored_card)
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn call_to_vault<V: pm_types::VaultingInterface>(
-    state: &routes::SessionState,
-    payload: Vec<u8>,
-) -> errors::CustomResult<String, errors::VaultError> {
-    let locker = &state.conf.locker;
-    let jwekey = state.conf.jwekey.get_inner();
-
-    let request = create_vault_request::<V>(jwekey, locker, payload).await?;
-    let response = services::call_connector_api(state, request, "vault_in_locker")
-        .await
-        .change_context(errors::VaultError::VaultAPIError);
-
-    let jwe_body: services::JweBody = response
-        .get_response_inner("JweBody")
-        .change_context(errors::VaultError::ResponseDeserializationFailed)
-        .attach_printable("Failed to get JweBody from vault response")?;
-
-    let decrypted_payload = payment_methods::get_decrypted_vault_response_payload(
-        jwekey,
-        jwe_body,
-        locker.decryption_scheme.clone(),
-    )
-    .await
-    .change_context(errors::VaultError::ResponseDecryptionFailed)
-    .attach_printable("Error getting decrypted vault response payload")?;
-
-    Ok(decrypted_payload)
-}
-
 #[instrument(skip_all)]
 pub async fn call_locker_api<T>(
     state: &routes::SessionState,
@@ -5401,21 +5238,6 @@ pub async fn retrieve_payment_method(
     ))
 }
 
-#[cfg(all(
-    any(feature = "v2", feature = "v1"),
-    not(feature = "payment_methods_v2")
-))]
-#[instrument(skip_all)]
-#[cfg(all(feature = "v2", feature = "customer_v2"))]
-pub async fn delete_payment_method(
-    _state: routes::SessionState,
-    _merchant_account: domain::MerchantAccount,
-    _pm_id: api::PaymentMethodId,
-    _key_store: domain::MerchantKeyStore,
-) -> errors::RouterResponse<api::PaymentMethodDeleteResponse> {
-    todo!()
-}
-
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
 #[instrument(skip_all)]
 pub async fn delete_payment_method(
@@ -5518,17 +5340,6 @@ pub async fn delete_payment_method(
     ))
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn delete_payment_method(
-    _state: routes::SessionState,
-    _merchant_account: domain::MerchantAccount,
-    _pm_id: api::PaymentMethodId,
-    _key_store: domain::MerchantKeyStore,
-) -> errors::RouterResponse<api::PaymentMethodDeleteResponse> {
-    todo!()
-}
-
 pub async fn create_encrypted_data<T>(
     state: &routes::SessionState,
     key_store: &domain::MerchantKeyStore,
diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs
index 75278010ceb..7a24f2a30a2 100644
--- a/crates/router/src/core/payment_methods/vault.rs
+++ b/crates/router/src/core/payment_methods/vault.rs
@@ -1,4 +1,6 @@
 use common_enums::PaymentMethodType;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use common_utils::request;
 use common_utils::{
     crypto::{DecodeMessage, EncodeMessage, GcmAes256},
     ext_traits::{BytesExt, Encode},
@@ -23,6 +25,11 @@ use crate::{
     },
     utils::StringExt,
 };
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use crate::{
+    core::payment_methods::transformers as pm_transforms, headers, services, settings,
+    types::payment_methods as pm_types, utils::ConnectorResponseExt,
+};
 const VAULT_SERVICE_NAME: &str = "CARD";
 
 pub struct SupplementaryVaultData {
@@ -1172,6 +1179,191 @@ pub async fn delete_tokenized_data(
     }
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+async fn create_vault_request<R: pm_types::VaultingInterface>(
+    jwekey: &settings::Jwekey,
+    locker: &settings::Locker,
+    payload: Vec<u8>,
+) -> CustomResult<request::Request, errors::VaultError> {
+    let private_key = jwekey.vault_private_key.peek().as_bytes();
+
+    let jws = services::encryption::jws_sign_payload(
+        &payload,
+        &locker.locker_signing_key_id,
+        private_key,
+    )
+    .await
+    .change_context(errors::VaultError::RequestEncryptionFailed)?;
+
+    let jwe_payload = pm_transforms::create_jwe_body_for_vault(jwekey, &jws).await?;
+
+    let mut url = locker.host.to_owned();
+    url.push_str(R::get_vaulting_request_url());
+    let mut request = request::Request::new(services::Method::Post, &url);
+    request.add_header(
+        headers::CONTENT_TYPE,
+        consts::VAULT_HEADER_CONTENT_TYPE.into(),
+    );
+    request.set_body(request::RequestContent::Json(Box::new(jwe_payload)));
+    Ok(request)
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn call_to_vault<V: pm_types::VaultingInterface>(
+    state: &routes::SessionState,
+    payload: Vec<u8>,
+) -> CustomResult<String, errors::VaultError> {
+    let locker = &state.conf.locker;
+    let jwekey = state.conf.jwekey.get_inner();
+
+    let request = create_vault_request::<V>(jwekey, locker, payload).await?;
+    let response = services::call_connector_api(state, request, V::get_vaulting_flow_name())
+        .await
+        .change_context(errors::VaultError::VaultAPIError);
+
+    let jwe_body: services::JweBody = response
+        .get_response_inner("JweBody")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed to get JweBody from vault response")?;
+
+    let decrypted_payload = pm_transforms::get_decrypted_vault_response_payload(
+        jwekey,
+        jwe_body,
+        locker.decryption_scheme.clone(),
+    )
+    .await
+    .change_context(errors::VaultError::ResponseDecryptionFailed)
+    .attach_printable("Error getting decrypted vault response payload")?;
+
+    Ok(decrypted_payload)
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn get_fingerprint_id_from_vault<
+    D: pm_types::VaultingDataInterface + serde::Serialize,
+>(
+    state: &routes::SessionState,
+    data: &D,
+) -> CustomResult<String, errors::VaultError> {
+    let key = data.get_vaulting_data_key();
+    let data = serde_json::to_string(data)
+        .change_context(errors::VaultError::RequestEncodingFailed)
+        .attach_printable("Failed to encode Vaulting data to string")?;
+
+    let payload = pm_types::VaultFingerprintRequest { key, data }
+        .encode_to_vec()
+        .change_context(errors::VaultError::RequestEncodingFailed)
+        .attach_printable("Failed to encode VaultFingerprintRequest")?;
+
+    let resp = call_to_vault::<pm_types::GetVaultFingerprint>(state, payload)
+        .await
+        .change_context(errors::VaultError::VaultAPIError)
+        .attach_printable("Call to vault failed")?;
+
+    let fingerprint_resp: pm_types::VaultFingerprintResponse = resp
+        .parse_struct("VaultFingerprintResponse")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed to parse data into VaultFingerprintResponse")?;
+
+    Ok(fingerprint_resp.fingerprint_id)
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn add_payment_method_to_vault(
+    state: &routes::SessionState,
+    merchant_account: &domain::MerchantAccount,
+    pmd: &pm_types::PaymentMethodVaultingData,
+    existing_vault_id: Option<domain::VaultId>,
+) -> CustomResult<pm_types::AddVaultResponse, errors::VaultError> {
+    let payload = pm_types::AddVaultRequest {
+        entity_id: merchant_account.get_id().to_owned(),
+        vault_id: existing_vault_id
+            .unwrap_or(domain::VaultId::generate(uuid::Uuid::now_v7().to_string())),
+        data: pmd,
+        ttl: state.conf.locker.ttl_for_storage_in_secs,
+    }
+    .encode_to_vec()
+    .change_context(errors::VaultError::RequestEncodingFailed)
+    .attach_printable("Failed to encode AddVaultRequest")?;
+
+    let resp = call_to_vault::<pm_types::AddVault>(state, payload)
+        .await
+        .change_context(errors::VaultError::VaultAPIError)
+        .attach_printable("Call to vault failed")?;
+
+    let stored_pm_resp: pm_types::AddVaultResponse = resp
+        .parse_struct("AddVaultResponse")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed to parse data into AddVaultResponse")?;
+
+    Ok(stored_pm_resp)
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn retrieve_payment_method_from_vault(
+    state: &routes::SessionState,
+    merchant_account: &domain::MerchantAccount,
+    pm: &domain::PaymentMethod,
+) -> CustomResult<pm_types::VaultRetrieveResponse, errors::VaultError> {
+    let payload = pm_types::VaultRetrieveRequest {
+        entity_id: merchant_account.get_id().to_owned(),
+        vault_id: pm
+            .locker_id
+            .clone()
+            .ok_or(errors::VaultError::MissingRequiredField {
+                field_name: "locker_id",
+            })
+            .attach_printable("Missing locker_id for VaultRetrieveRequest")?,
+    }
+    .encode_to_vec()
+    .change_context(errors::VaultError::RequestEncodingFailed)
+    .attach_printable("Failed to encode VaultRetrieveRequest")?;
+
+    let resp = call_to_vault::<pm_types::VaultRetrieve>(state, payload)
+        .await
+        .change_context(errors::VaultError::VaultAPIError)
+        .attach_printable("Call to vault failed")?;
+
+    let stored_pm_resp: pm_types::VaultRetrieveResponse = resp
+        .parse_struct("VaultRetrieveResponse")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed to parse data into VaultRetrieveResponse")?;
+
+    Ok(stored_pm_resp)
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn delete_payment_method_data_from_vault(
+    state: &routes::SessionState,
+    merchant_account: &domain::MerchantAccount,
+    vault_id: domain::VaultId,
+) -> CustomResult<pm_types::VaultDeleteResponse, errors::VaultError> {
+    let payload = pm_types::VaultDeleteRequest {
+        entity_id: merchant_account.get_id().to_owned(),
+        vault_id,
+    }
+    .encode_to_vec()
+    .change_context(errors::VaultError::RequestEncodingFailed)
+    .attach_printable("Failed to encode VaultDeleteRequest")?;
+
+    let resp = call_to_vault::<pm_types::VaultDelete>(state, payload)
+        .await
+        .change_context(errors::VaultError::VaultAPIError)
+        .attach_printable("Call to vault failed")?;
+
+    let stored_pm_resp: pm_types::VaultDeleteResponse = resp
+        .parse_struct("VaultDeleteResponse")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed to parse data into VaultDeleteResponse")?;
+
+    Ok(stored_pm_resp)
+}
+
 // ********************************************** PROCESS TRACKER **********************************************
 
 pub async fn add_delete_tokenized_data_task(
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 54e4471b057..c267b113fcd 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -1091,7 +1091,8 @@ impl PaymentMethods {
                 web::resource("/{id}/update_saved_payment_method")
                     .route(web::patch().to(payment_method_update_api)),
             )
-            .service(web::resource("/{id}").route(web::get().to(payment_method_retrieve_api)));
+            .service(web::resource("/{id}").route(web::get().to(payment_method_retrieve_api)))
+            .service(web::resource("/{id}").route(web::delete().to(payment_method_delete_api)));
 
         route
     }
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 3e3aada154f..77c072448a2 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -14,8 +14,9 @@ use router_env::{instrument, logger, tracing, Flow};
 use super::app::{AppState, SessionState};
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use crate::core::payment_methods::{
-    create_payment_method, list_customer_payment_method_util, payment_method_intent_confirm,
-    payment_method_intent_create, retrieve_payment_method, update_payment_method,
+    create_payment_method, delete_payment_method, list_customer_payment_method_util,
+    payment_method_intent_confirm, payment_method_intent_create, retrieve_payment_method,
+    update_payment_method,
 };
 use crate::{
     core::{
@@ -239,6 +240,33 @@ pub async fn payment_method_retrieve_api(
     .await
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsDelete))]
+pub async fn payment_method_delete_api(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<String>,
+) -> HttpResponse {
+    let flow = Flow::PaymentMethodsDelete;
+    let payload = web::Json(PaymentMethodId {
+        payment_method_id: path.into_inner(),
+    })
+    .into_inner();
+
+    Box::pin(api::server_wrap(
+        flow,
+        state,
+        &req,
+        payload,
+        |state, auth, pm, _| {
+            delete_payment_method(state, pm, auth.key_store, auth.merchant_account)
+        },
+        &auth::HeaderAuth(auth::ApiKeyAuth),
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
 #[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsMigrate))]
 pub async fn migrate_payment_method_api(
     state: web::Data<AppState>,
@@ -796,6 +824,10 @@ pub async fn payment_method_update_api(
     .await
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 #[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsDelete))]
 pub async fn payment_method_delete_api(
     state: web::Data<AppState>,
diff --git a/crates/router/src/types/payment_methods.rs b/crates/router/src/types/payment_methods.rs
index a1c0f8156fa..29290f0b7fc 100644
--- a/crates/router/src/types/payment_methods.rs
+++ b/crates/router/src/types/payment_methods.rs
@@ -10,32 +10,17 @@ use crate::{
 };
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[async_trait::async_trait]
 pub trait VaultingInterface {
     fn get_vaulting_request_url() -> &'static str;
+
+    fn get_vaulting_flow_name() -> &'static str;
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[async_trait::async_trait]
 pub trait VaultingDataInterface {
     fn get_vaulting_data_key(&self) -> String;
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[derive(Debug, serde::Deserialize, serde::Serialize)]
-pub struct VaultId(String);
-
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-impl VaultId {
-    pub fn get_string_repr(&self) -> &String {
-        &self.0
-    }
-
-    pub fn generate(id: String) -> Self {
-        Self(id)
-    }
-}
-
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct VaultFingerprintRequest {
@@ -53,7 +38,7 @@ pub struct VaultFingerprintResponse {
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct AddVaultRequest<D> {
     pub entity_id: common_utils::id_type::MerchantId,
-    pub vault_id: VaultId,
+    pub vault_id: domain::VaultId,
     pub data: D,
     pub ttl: i64,
 }
@@ -62,7 +47,7 @@ pub struct AddVaultRequest<D> {
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct AddVaultResponse {
     pub entity_id: common_utils::id_type::MerchantId,
-    pub vault_id: VaultId,
+    pub vault_id: domain::VaultId,
     pub fingerprint_id: Option<String>,
 }
 
@@ -79,27 +64,51 @@ pub struct GetVaultFingerprint;
 pub struct VaultRetrieve;
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[async_trait::async_trait]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct VaultDelete;
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 impl VaultingInterface for AddVault {
     fn get_vaulting_request_url() -> &'static str {
         consts::ADD_VAULT_REQUEST_URL
     }
+
+    fn get_vaulting_flow_name() -> &'static str {
+        consts::VAULT_ADD_FLOW_TYPE
+    }
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[async_trait::async_trait]
 impl VaultingInterface for GetVaultFingerprint {
     fn get_vaulting_request_url() -> &'static str {
         consts::VAULT_FINGERPRINT_REQUEST_URL
     }
+
+    fn get_vaulting_flow_name() -> &'static str {
+        consts::VAULT_GET_FINGERPRINT_FLOW_TYPE
+    }
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[async_trait::async_trait]
 impl VaultingInterface for VaultRetrieve {
     fn get_vaulting_request_url() -> &'static str {
         consts::VAULT_RETRIEVE_REQUEST_URL
     }
+
+    fn get_vaulting_flow_name() -> &'static str {
+        consts::VAULT_RETRIEVE_FLOW_TYPE
+    }
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl VaultingInterface for VaultDelete {
+    fn get_vaulting_request_url() -> &'static str {
+        consts::VAULT_DELETE_REQUEST_URL
+    }
+
+    fn get_vaulting_flow_name() -> &'static str {
+        consts::VAULT_DELETE_FLOW_TYPE
+    }
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -109,7 +118,6 @@ pub enum PaymentMethodVaultingData {
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[async_trait::async_trait]
 impl VaultingDataInterface for PaymentMethodVaultingData {
     fn get_vaulting_data_key(&self) -> String {
         match &self {
@@ -141,7 +149,7 @@ pub struct SavedPMLPaymentsInfo {
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct VaultRetrieveRequest {
     pub entity_id: common_utils::id_type::MerchantId,
-    pub vault_id: VaultId,
+    pub vault_id: domain::VaultId,
 }
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
@@ -149,3 +157,17 @@ pub struct VaultRetrieveRequest {
 pub struct VaultRetrieveResponse {
     pub data: Secret<String>,
 }
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct VaultDeleteRequest {
+    pub entity_id: common_utils::id_type::MerchantId,
+    pub vault_id: domain::VaultId,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct VaultDeleteResponse {
+    pub entity_id: common_utils::id_type::MerchantId,
+    pub vault_id: domain::VaultId,
+}

## 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 -->
- Payment method delete API for v2


### 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).
-->


## 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)?
-->
Cannot be tested as vault dev is incomplete.

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

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