Bug: Update and Retrieve PM APIs



### Feature Description

- Update Payment methods API
- Retrieve Payment Method API
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 6c93b0bb5bd..1a82dc0e26b 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -374,7 +374,7 @@ pub struct PaymentMethodUpdate {
 #[serde(deny_unknown_fields)]
 pub struct PaymentMethodUpdate {
     /// payment method data to be passed
-    pub payment_method_data: Option<PaymentMethodUpdateData>,
+    pub payment_method_data: PaymentMethodUpdateData,
 
     /// This is a 15 minute expiry token which shall be used from the client to authenticate and perform sessions from the SDK
     #[schema(max_length = 30, min_length = 30, example = "secret_k2uj3he2893eiu2d")]
@@ -990,6 +990,27 @@ impl From<CardDetailsPaymentMethod> for CardDetailFromLocker {
     }
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl From<CardDetail> for CardDetailFromLocker {
+    fn from(item: CardDetail) -> Self {
+        Self {
+            issuer_country: item.card_issuing_country,
+            last4_digits: Some(item.card_number.get_last4()),
+            card_number: Some(item.card_number),
+            expiry_month: Some(item.card_exp_month),
+            expiry_year: Some(item.card_exp_year),
+            card_holder_name: item.card_holder_name,
+            nick_name: item.nick_name,
+            card_isin: None,
+            card_issuer: item.card_issuer,
+            card_network: item.card_network,
+            card_type: item.card_type.map(|card| card.to_string()),
+            saved_to_locker: true,
+            card_fingerprint: None,
+        }
+    }
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 impl From<CardDetail> for CardDetailsPaymentMethod {
     fn from(item: CardDetail) -> Self {
diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs
index 1f4fd00bbc5..9e70cb2b96b 100644
--- a/crates/router/src/consts.rs
+++ b/crates/router/src/consts.rs
@@ -144,6 +144,10 @@ pub const ADD_VAULT_REQUEST_URL: &str = "/vault/add";
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub const VAULT_FINGERPRINT_REQUEST_URL: &str = "/fingerprint";
 
+/// Vault Retrieve request url
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub const VAULT_RETRIEVE_REQUEST_URL: &str = "/vault/retrieve";
+
 /// Vault Header content type
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub const VAULT_HEADER_CONTENT_TYPE: &str = "application/json";
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index cb26494b70d..8841ad7f383 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -25,7 +25,7 @@ use common_utils::{consts::DEFAULT_LOCALE, id_type};
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use common_utils::{
     crypto::{self, Encryptable},
-    ext_traits::{AsyncExt, Encode, ValueExt},
+    ext_traits::{AsyncExt, Encode, StringExt, ValueExt},
     fp_utils::when,
     generate_id,
     request::RequestContent,
@@ -80,7 +80,7 @@ const PAYMENT_METHOD_STATUS_UPDATE_TASK: &str = "PAYMENT_METHOD_STATUS_UPDATE";
 const PAYMENT_METHOD_STATUS_TAG: &str = "PAYMENT_METHOD_STATUS";
 
 #[instrument(skip_all)]
-pub async fn retrieve_payment_method(
+pub async fn retrieve_payment_method_core(
     pm_data: &Option<domain::PaymentMethodData>,
     state: &SessionState,
     payment_intent: &PaymentIntent,
@@ -877,16 +877,24 @@ pub async fn create_payment_method(
     .await
     .attach_printable("Failed to add Payment method to DB")?;
 
-    let vaulting_result =
-        vault_payment_method(state, &req.payment_method_data, merchant_account, key_store).await;
+    let payment_method_data = pm_types::PaymentMethodVaultingData::from(req.payment_method_data);
+
+    let vaulting_result = vault_payment_method(
+        state,
+        &payment_method_data,
+        merchant_account,
+        key_store,
+        None,
+    )
+    .await;
 
     let response = match vaulting_result {
         Ok(resp) => {
             let pm_update = create_pm_additional_data_update(
-                &req.payment_method_data,
+                &payment_method_data,
                 state,
                 key_store,
-                Some(resp.vault_id),
+                Some(resp.vault_id.get_string_repr().clone()),
                 Some(req.payment_method),
                 Some(req.payment_method_type),
             )
@@ -1041,16 +1049,24 @@ pub async fn payment_method_intent_confirm(
     .await
     .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound)?;
 
-    let vaulting_result =
-        vault_payment_method(state, &req.payment_method_data, merchant_account, key_store).await;
+    let payment_method_data = pm_types::PaymentMethodVaultingData::from(req.payment_method_data);
+
+    let vaulting_result = vault_payment_method(
+        state,
+        &payment_method_data,
+        merchant_account,
+        key_store,
+        None,
+    )
+    .await;
 
     let response = match vaulting_result {
         Ok(resp) => {
             let pm_update = create_pm_additional_data_update(
-                &req.payment_method_data,
+                &payment_method_data,
                 state,
                 key_store,
-                Some(resp.vault_id),
+                Some(resp.vault_id.get_string_repr().clone()),
                 Some(req.payment_method),
                 Some(req.payment_method_type),
             )
@@ -1220,15 +1236,17 @@ pub async fn create_payment_method_for_intent(
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub async fn create_pm_additional_data_update(
-    pmd: &api::PaymentMethodCreateData,
+    pmd: &pm_types::PaymentMethodVaultingData,
     state: &SessionState,
     key_store: &domain::MerchantKeyStore,
     vault_id: Option<String>,
     payment_method: Option<api_enums::PaymentMethod>,
     payment_method_type: Option<api_enums::PaymentMethodType>,
 ) -> RouterResult<storage::PaymentMethodUpdate> {
-    let card = match pmd.clone() {
-        api::PaymentMethodCreateData::Card(card) => api::PaymentMethodsData::Card(card.into()),
+    let card = match pmd {
+        pm_types::PaymentMethodVaultingData::Card(card) => {
+            api::PaymentMethodsData::Card(card.clone().into())
+        }
     };
 
     let pmd: Encryptable<Secret<serde_json::Value>> =
@@ -1255,15 +1273,17 @@ pub async fn create_pm_additional_data_update(
 #[instrument(skip_all)]
 pub async fn vault_payment_method(
     state: &SessionState,
-    pmd: &api::PaymentMethodCreateData,
+    pmd: &pm_types::PaymentMethodVaultingData,
     merchant_account: &domain::MerchantAccount,
     key_store: &domain::MerchantKeyStore,
+    existing_vault_id: Option<String>,
 ) -> 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)
         .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
         .attach_printable("Failed to get fingerprint_id from vault")?;
 
     // throw back error if payment method is duplicated
@@ -1286,7 +1306,10 @@ pub async fn vault_payment_method(
     )?;
 
     let resp_from_locker =
-        cards::vault_payment_method_in_locker(state, merchant_account, pmd).await?;
+        cards::vault_payment_method_in_locker(state, merchant_account, pmd, existing_vault_id)
+            .await
+            .change_context(errors::ApiErrorResponse::InternalServerError)
+            .attach_printable("Failed to vault payment method in locker")?;
 
     Ok(resp_from_locker)
 }
@@ -1656,6 +1679,152 @@ async fn generate_saved_pm_response(
     Ok(pma)
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn retrieve_payment_method(
+    state: SessionState,
+    pm: api::PaymentMethodId,
+    key_store: domain::MerchantKeyStore,
+    merchant_account: domain::MerchantAccount,
+) -> RouterResponse<api::PaymentMethodResponse> {
+    let db = state.store.as_ref();
+    let pm_id = id_type::GlobalPaymentMethodId::generate_from_string(pm.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 pmd = payment_method
+        .payment_method_data
+        .clone()
+        .map(|x| x.into_inner().expose())
+        .and_then(|v| serde_json::from_value::<api::PaymentMethodsData>(v).ok())
+        .and_then(|pmd| match pmd {
+            api::PaymentMethodsData::Card(card) => {
+                Some(api::PaymentMethodResponseData::Card(card.into()))
+            }
+            _ => None,
+        });
+
+    let resp = api::PaymentMethodResponse {
+        merchant_id: payment_method.merchant_id.to_owned(),
+        customer_id: payment_method.customer_id.to_owned(),
+        payment_method_id: payment_method.id.get_string_repr().to_string(),
+        payment_method: payment_method.payment_method,
+        payment_method_type: payment_method.payment_method_type,
+        metadata: payment_method.metadata.clone(),
+        created: Some(payment_method.created_at),
+        recurring_enabled: false,
+        last_used_at: Some(payment_method.last_used_at),
+        client_secret: payment_method.client_secret.clone(),
+        payment_method_data: pmd,
+    };
+
+    Ok(services::ApplicationResponse::Json(resp))
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all)]
+pub async fn update_payment_method(
+    state: SessionState,
+    merchant_account: domain::MerchantAccount,
+    req: api::PaymentMethodUpdate,
+    payment_method_id: &str,
+    key_store: domain::MerchantKeyStore,
+) -> RouterResponse<api::PaymentMethodResponse> {
+    let db = state.store.as_ref();
+
+    let pm_id = id_type::GlobalPaymentMethodId::generate_from_string(payment_method_id.to_string())
+        .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 current_vault_id = payment_method.locker_id.clone();
+
+    when(
+        payment_method.status == enums::PaymentMethodStatus::AwaitingData,
+        || {
+            Err(errors::ApiErrorResponse::InvalidRequestData {
+                message: "This Payment method is awaiting data and hence cannot be updated"
+                    .to_string(),
+            })
+        },
+    )?;
+
+    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 vault_request_data =
+        pm_transforms::generate_pm_vaulting_req_from_update_request(pmd, req.payment_method_data);
+
+    let vaulting_response = vault_payment_method(
+        &state,
+        &vault_request_data,
+        &merchant_account,
+        &key_store,
+        current_vault_id, // using current vault_id for now, will have to refactor this
+    ) // to generate new one on each vaulting later on
+    .await
+    .attach_printable("Failed to add payment method in vault")?;
+
+    let pm_update = create_pm_additional_data_update(
+        &vault_request_data,
+        &state,
+        &key_store,
+        Some(vaulting_response.vault_id.get_string_repr().clone()),
+        payment_method.payment_method,
+        payment_method.payment_method_type,
+    )
+    .await
+    .attach_printable("Unable to create Payment method data")?;
+
+    let payment_method = 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")?;
+
+    let response = pm_transforms::generate_payment_method_response(&payment_method)?;
+
+    // Add a PT task to handle payment_method delete from vault
+
+    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 a7ae7f9ca50..578655a927d 100644
--- a/crates/router/src/core/payment_methods/cards.rs
+++ b/crates/router/src/core/payment_methods/cards.rs
@@ -1418,26 +1418,26 @@ pub async fn get_fingerprint_id_from_locker<
 >(
     state: &routes::SessionState,
     data: &D,
-) -> errors::RouterResult<String> {
+) -> errors::CustomResult<String, errors::VaultError> {
     let key = data.get_vaulting_data_key();
     let data = serde_json::to_value(data)
-        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .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::ApiErrorResponse::InternalServerError)
+        .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::ApiErrorResponse::InternalServerError)
+        .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::ApiErrorResponse::InternalServerError)
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
         .attach_printable("Failed to parse data into VaultFingerprintResp")?;
 
     Ok(fingerprint_resp.fingerprint_id)
@@ -1448,31 +1448,70 @@ pub async fn get_fingerprint_id_from_locker<
 pub async fn vault_payment_method_in_locker(
     state: &routes::SessionState,
     merchant_account: &domain::MerchantAccount,
-    pmd: &api::PaymentMethodCreateData,
-) -> errors::RouterResult<pm_types::AddVaultResponse> {
+    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: uuid::Uuid::now_v7().to_string(),
-        data: pmd.clone(),
+        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::ApiErrorResponse::InternalServerError)
+    .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::ApiErrorResponse::InternalServerError)
+        .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::ApiErrorResponse::InternalServerError)
+        .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")
@@ -1783,18 +1822,6 @@ pub async fn update_customer_payment_method(
     }
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn update_customer_payment_method(
-    _state: routes::SessionState,
-    _merchant_account: domain::MerchantAccount,
-    _req: api::PaymentMethodUpdate,
-    _payment_method_id: &str,
-    _key_store: domain::MerchantKeyStore,
-) -> errors::RouterResponse<api::PaymentMethodResponse> {
-    todo!()
-}
-
 #[cfg(all(
     any(feature = "v1", feature = "v2"),
     not(feature = "payment_methods_v2")
@@ -5378,17 +5405,6 @@ pub async fn retrieve_payment_method(
     ))
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
-#[instrument(skip_all)]
-pub async fn retrieve_payment_method(
-    state: routes::SessionState,
-    pm: api::PaymentMethodId,
-    key_store: domain::MerchantKeyStore,
-    merchant_account: domain::MerchantAccount,
-) -> errors::RouterResponse<api::PaymentMethodResponse> {
-    todo!()
-}
-
 #[cfg(all(
     any(feature = "v2", feature = "v1"),
     not(feature = "payment_methods_v2")
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index ab21add60a8..78770c34579 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -15,6 +15,8 @@ use josekit::jwe;
 use router_env::tracing_actix_web::RequestId;
 use serde::{Deserialize, Serialize};
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use crate::types::payment_methods as pm_types;
 use crate::{
     configs::settings,
     core::errors::{self, CustomResult},
@@ -520,6 +522,29 @@ pub fn mk_add_card_response_hs(
     todo!()
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+pub fn generate_pm_vaulting_req_from_update_request(
+    pm_create: pm_types::PaymentMethodVaultingData,
+    pm_update: api::PaymentMethodUpdateData,
+) -> pm_types::PaymentMethodVaultingData {
+    match (pm_create, pm_update) {
+        (
+            pm_types::PaymentMethodVaultingData::Card(card_create),
+            api::PaymentMethodUpdateData::Card(update_card),
+        ) => pm_types::PaymentMethodVaultingData::Card(api::CardDetail {
+            card_number: card_create.card_number,
+            card_exp_month: card_create.card_exp_month,
+            card_exp_year: card_create.card_exp_year,
+            card_issuing_country: card_create.card_issuing_country,
+            card_network: card_create.card_network,
+            card_issuer: card_create.card_issuer,
+            card_type: card_create.card_type,
+            card_holder_name: update_card.card_holder_name,
+            nick_name: update_card.nick_name,
+        }),
+    }
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 pub fn generate_payment_method_response(
     pm: &domain::PaymentMethod,
@@ -798,6 +823,15 @@ pub fn get_card_detail(
     Ok(card_detail)
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+impl From<api::PaymentMethodCreateData> for pm_types::PaymentMethodVaultingData {
+    fn from(item: api::PaymentMethodCreateData) -> Self {
+        match item {
+            api::PaymentMethodCreateData::Card(card) => Self::Card(card),
+        }
+    }
+}
+
 //------------------------------------------------TokenizeService------------------------------------------------
 pub fn mk_crud_locker_request(
     locker: &settings::Locker,
diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs
index 23ac67c910d..4e484bda6c4 100644
--- a/crates/router/src/core/payments/helpers.rs
+++ b/crates/router/src/core/payments/helpers.rs
@@ -2226,15 +2226,16 @@ pub async fn make_pm_data<'a, F: Clone, R, D>(
         }
 
         (Some(_), _) => {
-            let (payment_method_data, payment_token) = payment_methods::retrieve_payment_method(
-                &request,
-                state,
-                &payment_data.payment_intent,
-                &payment_data.payment_attempt,
-                merchant_key_store,
-                Some(business_profile),
-            )
-            .await?;
+            let (payment_method_data, payment_token) =
+                payment_methods::retrieve_payment_method_core(
+                    &request,
+                    state,
+                    &payment_data.payment_intent,
+                    &payment_data.payment_attempt,
+                    merchant_key_store,
+                    Some(business_profile),
+                )
+                .await?;
 
             payment_data.token = payment_token;
 
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 9ff768c56fb..d5f73921a9d 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -1087,7 +1087,12 @@ impl PaymentMethods {
             .service(
                 web::resource("/{id}/confirm-intent")
                     .route(web::post().to(confirm_payment_method_intent_api)),
-            );
+            )
+            .service(
+                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)));
 
         route
     }
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 725d6af81af..3e3aada154f 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -15,7 +15,7 @@ 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,
+    payment_method_intent_create, retrieve_payment_method, update_payment_method,
 };
 use crate::{
     core::{
@@ -180,6 +180,65 @@ pub async fn confirm_payment_method_intent_api(
     .await
 }
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsUpdate))]
+pub async fn payment_method_update_api(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<String>,
+    json_payload: web::Json<payment_methods::PaymentMethodUpdate>,
+) -> HttpResponse {
+    let flow = Flow::PaymentMethodsUpdate;
+    let payment_method_id = path.into_inner();
+    let payload = json_payload.into_inner();
+
+    Box::pin(api::server_wrap(
+        flow,
+        state,
+        &req,
+        payload,
+        |state, auth, req, _| {
+            update_payment_method(
+                state,
+                auth.merchant_account,
+                req,
+                &payment_method_id,
+                auth.key_store,
+            )
+        },
+        &auth::HeaderAuth(auth::ApiKeyAuth),
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsRetrieve))]
+pub async fn payment_method_retrieve_api(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<String>,
+) -> HttpResponse {
+    let flow = Flow::PaymentMethodsRetrieve;
+    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, _| {
+            retrieve_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>,
@@ -667,6 +726,10 @@ pub async fn render_pm_collect_link(
     .await
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 #[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsRetrieve))]
 pub async fn payment_method_retrieve_api(
     state: web::Data<AppState>,
@@ -693,6 +756,10 @@ pub async fn payment_method_retrieve_api(
     .await
 }
 
+#[cfg(all(
+    any(feature = "v1", feature = "v2"),
+    not(feature = "payment_methods_v2")
+))]
 #[instrument(skip_all, fields(flow = ?Flow::PaymentMethodsUpdate))]
 pub async fn payment_method_update_api(
     state: web::Data<AppState>,
diff --git a/crates/router/src/types/api/payment_methods.rs b/crates/router/src/types/api/payment_methods.rs
index 28d387771b5..d66bf079d42 100644
--- a/crates/router/src/types/api/payment_methods.rs
+++ b/crates/router/src/types/api/payment_methods.rs
@@ -8,8 +8,8 @@ pub use api_models::payment_methods::{
     PaymentMethodIntentConfirm, PaymentMethodIntentConfirmInternal, PaymentMethodIntentCreate,
     PaymentMethodList, PaymentMethodListData, PaymentMethodListRequest, PaymentMethodListResponse,
     PaymentMethodMigrate, PaymentMethodResponse, PaymentMethodResponseData, PaymentMethodUpdate,
-    PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest, TokenizedCardValue1,
-    TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
+    PaymentMethodUpdateData, PaymentMethodsData, TokenizePayloadEncrypted, TokenizePayloadRequest,
+    TokenizedCardValue1, TokenizedCardValue2, TokenizedWalletValue1, TokenizedWalletValue2,
 };
 #[cfg(all(
     any(feature = "v2", feature = "v1"),
diff --git a/crates/router/src/types/payment_methods.rs b/crates/router/src/types/payment_methods.rs
index e55516fc3af..a1c0f8156fa 100644
--- a/crates/router/src/types/payment_methods.rs
+++ b/crates/router/src/types/payment_methods.rs
@@ -1,5 +1,7 @@
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use common_utils::generate_id;
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+use masking::Secret;
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 use crate::{
@@ -19,6 +21,21 @@ 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 {
@@ -36,7 +53,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: String,
+    pub vault_id: VaultId,
     pub data: D,
     pub ttl: i64,
 }
@@ -45,7 +62,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: String,
+    pub vault_id: VaultId,
     pub fingerprint_id: Option<String>,
 }
 
@@ -57,6 +74,10 @@ pub struct AddVault;
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct GetVaultFingerprint;
 
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct VaultRetrieve;
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[async_trait::async_trait]
 impl VaultingInterface for AddVault {
@@ -75,7 +96,21 @@ impl VaultingInterface for GetVaultFingerprint {
 
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[async_trait::async_trait]
-impl VaultingDataInterface for api::PaymentMethodCreateData {
+impl VaultingInterface for VaultRetrieve {
+    fn get_vaulting_request_url() -> &'static str {
+        consts::VAULT_RETRIEVE_REQUEST_URL
+    }
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
+pub enum PaymentMethodVaultingData {
+    Card(api::CardDetail),
+}
+
+#[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 {
             Self::Card(card) => card.card_number.to_string(),
@@ -101,3 +136,16 @@ pub struct SavedPMLPaymentsInfo {
     pub off_session_payment_flag: bool,
     pub is_connector_agnostic_mit_enabled: bool,
 }
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct VaultRetrieveRequest {
+    pub entity_id: common_utils::id_type::MerchantId,
+    pub vault_id: VaultId,
+}
+
+#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct VaultRetrieveResponse {
+    pub data: Secret<String>,
+}

## 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 -->
- Update PM API for v2
- Retrieve PM 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)?
-->
Vault dev is incomplete so cannot be tested.


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