Bug: [FEATURE]: Add `customer_list_saved_payment_methods` to OLAP (v2)



Needed for the dashboard
diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index ba795d40594..cd076aa0d5b 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -2498,6 +2498,47 @@
         ]
       }
     },
+    "/v2/customers/{id}/saved-payment-methods": {
+      "delete": {
+        "tags": [
+          "Payment Methods"
+        ],
+        "summary": "Payment Method - List Customer Saved Payment Methods",
+        "description": "List the payment methods saved for a customer",
+        "operationId": "List Customer Saved Payment Methods",
+        "parameters": [
+          {
+            "name": "id",
+            "in": "path",
+            "description": "The unique identifier for the customer",
+            "required": true,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Payment Methods Retrieved",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/CustomerPaymentMethodsListResponse"
+                }
+              }
+            }
+          },
+          "404": {
+            "description": "Customer Not Found"
+          }
+        },
+        "security": [
+          {
+            "api_key": []
+          }
+        ]
+      }
+    },
     "/v2/payment-method-session": {
       "post": {
         "tags": [
diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs
index cc6f1b0e411..088ced76085 100644
--- a/crates/openapi/src/openapi_v2.rs
+++ b/crates/openapi/src/openapi_v2.rs
@@ -135,6 +135,7 @@ Never share your secret api keys. Keep them guarded and secure.
         routes::payment_method::payment_method_update_api,
         routes::payment_method::payment_method_retrieve_api,
         routes::payment_method::payment_method_delete_api,
+        routes::payment_method::list_customer_payment_method_api,
 
         //Routes for payment method session
         routes::payment_method::payment_method_session_create,
diff --git a/crates/openapi/src/routes/payment_method.rs b/crates/openapi/src/routes/payment_method.rs
index 3c1f66e6e76..15318322398 100644
--- a/crates/openapi/src/routes/payment_method.rs
+++ b/crates/openapi/src/routes/payment_method.rs
@@ -322,6 +322,26 @@ pub async fn payment_method_update_api() {}
 #[cfg(feature = "v2")]
 pub async fn payment_method_delete_api() {}
 
+/// Payment Method - List Customer Saved Payment Methods
+///
+/// List the payment methods saved for a customer
+#[utoipa::path(
+    delete,
+    path = "/v2/customers/{id}/saved-payment-methods",
+    params (
+        ("id" = String, Path, description = "The unique identifier for the customer"),
+    ),
+    responses(
+        (status = 200, description = "Payment Methods Retrieved", body = CustomerPaymentMethodsListResponse),
+        (status = 404, description = "Customer Not Found"),
+    ),
+    tag = "Payment Methods",
+    operation_id = "List Customer Saved Payment Methods",
+    security(("api_key" = []))
+)]
+#[cfg(feature = "v2")]
+pub async fn list_customer_payment_method_api() {}
+
 /// Payment Method Session - Create
 ///
 /// Create a payment method session for a customer
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 5bdb0f0819e..19b1bb3c7d7 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -1099,6 +1099,23 @@ pub async fn list_payment_methods_for_session(
     ))
 }
 
+#[cfg(all(feature = "v2", feature = "olap"))]
+#[instrument(skip_all)]
+pub async fn list_saved_payment_methods_for_customer(
+    state: SessionState,
+    merchant_account: domain::MerchantAccount,
+    key_store: domain::MerchantKeyStore,
+    customer_id: id_type::GlobalCustomerId,
+) -> RouterResponse<api::CustomerPaymentMethodsListResponse> {
+    let customer_payment_methods =
+        list_customer_payment_method_core(&state, &merchant_account, &key_store, &customer_id)
+            .await?;
+
+    Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
+        customer_payment_methods,
+    ))
+}
+
 #[cfg(feature = "v2")]
 /// Container for the inputs required for the required fields
 struct RequiredFieldsInput {
@@ -1463,11 +1480,7 @@ fn get_pm_list_context(
     Ok(payment_method_retrieval_context)
 }
 
-#[cfg(all(
-    feature = "v2",
-    feature = "payment_methods_v2",
-    feature = "customer_v2"
-))]
+#[cfg(all(feature = "v2", feature = "olap"))]
 pub async fn list_customer_payment_method_core(
     state: &SessionState,
     merchant_account: &domain::MerchantAccount,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index c5e1f8a1082..0609ba8d1a2 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -1015,6 +1015,10 @@ impl Customers {
                         .route(web::get().to(customers::customers_retrieve))
                         .route(web::delete().to(customers::customers_delete)),
                 )
+                .service(
+                    web::resource("/{id}/saved-payment-methods")
+                        .route(web::get().to(payment_methods::list_customer_payment_method_api)),
+                )
         }
         route
     }
diff --git a/crates/router/src/routes/payment_methods.rs b/crates/router/src/routes/payment_methods.rs
index 86f1874ab09..9f3332855e3 100644
--- a/crates/router/src/routes/payment_methods.rs
+++ b/crates/router/src/routes/payment_methods.rs
@@ -579,6 +579,43 @@ pub async fn initiate_pm_collect_link_flow(
     .await
 }
 
+#[cfg(all(feature = "v2", feature = "olap"))]
+#[instrument(skip_all, fields(flow = ?Flow::CustomerPaymentMethodsList))]
+pub async fn list_customer_payment_method_api(
+    state: web::Data<AppState>,
+    customer_id: web::Path<id_type::GlobalCustomerId>,
+    req: HttpRequest,
+    query_payload: web::Query<api_models::payment_methods::PaymentMethodListRequest>,
+) -> HttpResponse {
+    let flow = Flow::CustomerPaymentMethodsList;
+    let payload = query_payload.into_inner();
+    let customer_id = customer_id.into_inner();
+
+    Box::pin(api::server_wrap(
+        flow,
+        state,
+        &req,
+        payload,
+        |state, auth: auth::AuthenticationData, _, _| {
+            payment_methods_routes::list_saved_payment_methods_for_customer(
+                state,
+                auth.merchant_account,
+                auth.key_store,
+                customer_id.clone(),
+            )
+        },
+        auth::auth_type(
+            &auth::HeaderAuth(auth::ApiKeyAuth),
+            &auth::JWTAuth {
+                permission: Permission::MerchantCustomerRead,
+            },
+            req.headers(),
+        ),
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
 #[cfg(all(any(feature = "v1", feature = "v2"), not(feature = "customer_v2")))]
 /// Generate a form link for collecting payment methods for a customer
 #[instrument(skip_all, fields(flow = ?Flow::PaymentMethodCollectLink))]

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

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

## Description
<!-- Describe your changes in detail -->
Add `customer_list_saved_payment_methods` to OLAP and allow JWT Auth

This endpoint allows retrieving saved payment methods for a customer

This PR enables the endpoint to be used from the dashboard

### Additional Changes

- [x] 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)?
-->
- Request

```bash
curl --location 'http://localhost:8080/v2/customers/12345_cus_0195187353c47d438edd6044cadb0969/saved-payment-methods' \
--header 'api-key: dev_Z0aXn9A50mSviMWnWLC02YHDhCxoLdKawgHzVMRwErbyyYQ5O4XvqjNYMQoCCaT1' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: pro_9glqJzp3eRd6XljDKDE9'
```

- Response

```json
{
    "customer_payment_methods": [
        {
            "id": "12345_pm_019518761b3075e0a4da6035422ce961",
            "customer_id": "12345_cus_0195187353c47d438edd6044cadb0969",
            "payment_method_type": "card",
            "payment_method_subtype": "credit",
            "recurring_enabled": true,
            "payment_method_data": {
                "card": {
                    "issuer_country": null,
                    "last4_digits": "4242",
                    "expiry_month": "02",
                    "expiry_year": "2025",
                    "card_holder_name": "joseph Doe",
                    "card_fingerprint": null,
                    "nick_name": null,
                    "card_network": null,
                    "card_isin": null,
                    "card_issuer": null,
                    "card_type": null,
                    "saved_to_locker": true
                }
            },
            "bank": null,
            "created": "2025-02-18T09:49:08.273Z",
            "requires_cvv": true,
            "last_used_at": "2025-02-18T09:49:08.273Z",
            "is_default": false,
            "billing": null
        }
    ]
}
```

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