Issue:
Bug: [FEAT]: Add support for visibility and updating additional token details





Pull request description:
## 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 PR introduces two new API:-
1) To get data from Redis for monitoring purpose **v2/recovery/data-backfill/redis-data/:id?key_type=Status**
2) To update additional token data(error code, hard decline flag and schedule at fields) **v2/recovery/data-backfill/update-token**

### 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)?
-->
cURL to get redis data (token type:- Tokens)
```
curl --location 'http://localhost:8080/v2/recovery/data-backfill/redis-data/10010?key_type=Tokens' \
--header 'Authorization: admin-api-key=test_admin'
```
Test case 1 (token is present)
Response:-
```
{
    "exists": true,
    "ttl_seconds": 3887994,
    "data": {
        "2401559361951038": "{\"payment_processor_token_details\":{\"payment_processor_token\":\"2401559361951038\",\"expiry_month\":\"02\",\"expiry_year\":\"27\",\"card_issuer\":\"Plus Credit Union\",\"last_four_digits\":null,\"card_network\":null,\"card_type\":\"card\"},\"inserted_by_attempt_id\":\"12345_att_0199517c62647b9090c328ed1b28ebf6\",\"error_code\":\"12\",\"daily_retry_history\":{},\"scheduled_at\":null,\"is_hard_decline\":false}"
    }
}
```
Test case 2 (token is not present)
```
{
    "error": {
        "type": "invalid_request",
        "message": "Redis data not found for connector customer id:- '100101'",
        "code": "IR_37"
    }
}
Router log:-
<img width="1353" height="758" alt="Screenshot 2025-09-29 at 19 32 47" src="https://github.com/user-attachments/assets/89198cc1-70ce-4ac4-9b20-4d53e7260754" />


```
cURL to get redis data (token type:- Status)
```
curl --location 'http://localhost:8080/v2/recovery/data-backfill/redis-data/100101?key_type=Status' \
--header 'Authorization: admin-api-key=test_admin'
```
Test case 3 (status is not present)
```
{
    "error": {
        "type": "invalid_request",
        "message": "Redis data not found for connector customer id:- '100101'",
        "code": "IR_37"
    }
}
```
cURL to update redis data 
```
curl --location --request PUT 'http://localhost:8080/v2/recovery/data-backfill/update-token' \
--header 'Content-Type: application/json' \
--header 'Authorization: admin-api-key=test_admin' \
--data '{
    "connector_customer_id": "57984238498234763874917211",
    "payment_processor_token": "2541911049890008",
    "scheduled_at": "2025-09-29T08:45:53.692126Z",
    "is_hard_decline": false,
    "error_code": "-1"
  }
'
```
Test case 4 (token is present)
```
{
    "updated": true,
    "message": "Successfully updated token '0008' for connector customer '10010'. Updated fields: scheduled_at: 2025-09-29T08:45:53.692126Z, is_hard_decline: false, error_code: -1"
}
```
Test case 5 (token is not present)
```
{
    "error": {
        "type": "invalid_request",
        "message": "Token '0008' not found for connector customer id:- '100101'",
        "code": "IR_37"
    }
}
```
<img width="1359" height="689" alt="Screenshot 2025-09-29 at 19 34 29" src="https://github.com/user-attachments/assets/675442da-0ac1-44fd-b3ab-a4ce921370fe" />



## 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


Testing:

cURL to get redis data (token type:- Tokens)
```
curl --location 'http://localhost:8080/v2/recovery/data-backfill/redis-data/10010?key_type=Tokens' \
--header 'Authorization: admin-api-key=test_admin'
```
Test case 1 (token is present)
Response:-
```
{
    "exists": true,
    "ttl_seconds": 3887994,
    "data": {
        "2401559361951038": "{\"payment_processor_token_details\":{\"payment_processor_token\":\"2401559361951038\",\"expiry_month\":\"02\",\"expiry_year\":\"27\",\"card_issuer\":\"Plus Credit Union\",\"last_four_digits\":null,\"card_network\":null,\"card_type\":\"card\"},\"inserted_by_attempt_id\":\"12345_att_0199517c62647b9090c328ed1b28ebf6\",\"error_code\":\"12\",\"daily_retry_history\":{},\"scheduled_at\":null,\"is_hard_decline\":false}"
    }
}
```
Test case 2 (token is not present)
```
{
    "error": {
        "type": "invalid_request",
        "message": "Redis data not found for connector customer id:- '100101'",
        "code": "IR_37"
    }
}
Router log:-
<img width="1353" height="758" alt="Screenshot 2025-09-29 at 19 32 47" src="https://github.com/user-attachments/assets/89198cc1-70ce-4ac4-9b20-4d53e7260754" />


```
cURL to get redis data (token type:- Status)
```
curl --location 'http://localhost:8080/v2/recovery/data-backfill/redis-data/100101?key_type=Status' \
--header 'Authorization: admin-api-key=test_admin'
```
Test case 3 (status is not present)
```
{
    "error": {
        "type": "invalid_request",
        "message": "Redis data not found for connector customer id:- '100101'",
        "code": "IR_37"
    }
}
```
cURL to update redis data 
```
curl --location --request PUT 'http://localhost:8080/v2/recovery/data-backfill/update-token' \
--header 'Content-Type: application/json' \
--header 'Authorization: admin-api-key=test_admin' \
--data '{
    "connector_customer_id": "57984238498234763874917211",
    "payment_processor_token": "2541911049890008",
    "scheduled_at": "2025-09-29T08:45:53.692126Z",
    "is_hard_decline": false,
    "error_code": "-1"
  }
'
```
Test case 4 (token is present)
```
{
    "updated": true,
    "message": "Successfully updated token '0008' for connector customer '10010'. Updated fields: scheduled_at: 2025-09-29T08:45:53.692126Z, is_hard_decline: false, error_code: -1"
}
```
Test case 5 (token is not present)
```
{
    "error": {
        "type": "invalid_request",
        "message": "Token '0008' not found for connector customer id:- '100101'",
        "code": "IR_37"
    }
}
```
<img width="1359" height="689" alt="Screenshot 2025-09-29 at 19 34 29" src="https://github.com/user-attachments/assets/675442da-0ac1-44fd-b3ab-a4ce921370fe" />

Patch:
diff --git a/crates/api_models/src/revenue_recovery_data_backfill.rs b/crates/api_models/src/revenue_recovery_data_backfill.rs
index 34c64b75547..8f0276a84c0 100644
--- a/crates/api_models/src/revenue_recovery_data_backfill.rs
+++ b/crates/api_models/src/revenue_recovery_data_backfill.rs
@@ -3,11 +3,11 @@ use std::{collections::HashMap, fs::File, io::BufReader};
 use actix_multipart::form::{tempfile::TempFile, MultipartForm};
 use actix_web::{HttpResponse, ResponseError};
 use common_enums::{CardNetwork, PaymentMethodType};
-use common_utils::events::ApiEventMetric;
+use common_utils::{events::ApiEventMetric, pii::PhoneNumberStrategy};
 use csv::Reader;
 use masking::Secret;
 use serde::{Deserialize, Serialize};
-use time::Date;
+use time::{Date, PrimitiveDateTime};
 
 #[derive(Debug, Deserialize, Serialize)]
 pub struct RevenueRecoveryBackfillRequest {
@@ -82,6 +82,24 @@ impl ApiEventMetric for CsvParsingError {
     }
 }
 
+impl ApiEventMetric for RedisDataResponse {
+    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
+        Some(common_utils::events::ApiEventsType::Miscellaneous)
+    }
+}
+
+impl ApiEventMetric for UpdateTokenStatusRequest {
+    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
+        Some(common_utils::events::ApiEventsType::Miscellaneous)
+    }
+}
+
+impl ApiEventMetric for UpdateTokenStatusResponse {
+    fn get_api_event_type(&self) -> Option<common_utils::events::ApiEventsType> {
+        Some(common_utils::events::ApiEventsType::Miscellaneous)
+    }
+}
+
 #[derive(Debug, Clone, Serialize)]
 pub enum BackfillError {
     InvalidCardType(String),
@@ -96,6 +114,72 @@ pub struct BackfillQuery {
     pub cutoff_time: Option<String>,
 }
 
+#[derive(Debug, Serialize, Deserialize)]
+pub enum RedisKeyType {
+    Status, // for customer:{id}:status
+    Tokens, // for customer:{id}:tokens
+}
+
+#[derive(Debug, Deserialize)]
+pub struct GetRedisDataQuery {
+    pub key_type: RedisKeyType,
+}
+
+#[derive(Debug, Serialize)]
+pub struct RedisDataResponse {
+    pub exists: bool,
+    pub ttl_seconds: i64,
+    pub data: Option<serde_json::Value>,
+}
+
+#[derive(Debug, Serialize)]
+pub enum ScheduledAtUpdate {
+    SetToNull,
+    SetToDateTime(PrimitiveDateTime),
+}
+
+impl<'de> Deserialize<'de> for ScheduledAtUpdate {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: serde::Deserializer<'de>,
+    {
+        let value = serde_json::Value::deserialize(deserializer)?;
+
+        match value {
+            serde_json::Value::String(s) => {
+                if s.to_lowercase() == "null" {
+                    Ok(Self::SetToNull)
+                } else {
+                    // Parse as datetime using iso8601 deserializer
+                    common_utils::custom_serde::iso8601::deserialize(
+                        &mut serde_json::Deserializer::from_str(&format!("\"{}\"", s)),
+                    )
+                    .map(Self::SetToDateTime)
+                    .map_err(serde::de::Error::custom)
+                }
+            }
+            _ => Err(serde::de::Error::custom(
+                "Expected null variable or datetime iso8601 ",
+            )),
+        }
+    }
+}
+
+#[derive(Debug, Deserialize, Serialize)]
+pub struct UpdateTokenStatusRequest {
+    pub connector_customer_id: String,
+    pub payment_processor_token: Secret<String, PhoneNumberStrategy>,
+    pub scheduled_at: Option<ScheduledAtUpdate>,
+    pub is_hard_decline: Option<bool>,
+    pub error_code: Option<String>,
+}
+
+#[derive(Debug, Serialize)]
+pub struct UpdateTokenStatusResponse {
+    pub updated: bool,
+    pub message: String,
+}
+
 impl std::fmt::Display for BackfillError {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
diff --git a/crates/redis_interface/src/commands.rs b/crates/redis_interface/src/commands.rs
index b0bf47e955e..54e7eed7f11 100644
--- a/crates/redis_interface/src/commands.rs
+++ b/crates/redis_interface/src/commands.rs
@@ -485,6 +485,14 @@ impl super::RedisConnectionPool {
             .change_context(errors::RedisError::SetExpiryFailed)
     }
 
+    #[instrument(level = "DEBUG", skip(self))]
+    pub async fn get_ttl(&self, key: &RedisKey) -> CustomResult<i64, errors::RedisError> {
+        self.pool
+            .ttl(key.tenant_aware_key(self))
+            .await
+            .change_context(errors::RedisError::GetFailed)
+    }
+
     #[instrument(level = "DEBUG", skip(self))]
     pub async fn set_hash_fields<V>(
         &self,
diff --git a/crates/router/src/core/revenue_recovery_data_backfill.rs b/crates/router/src/core/revenue_recovery_data_backfill.rs
index 629b9e6a586..d6df7b75b57 100644
--- a/crates/router/src/core/revenue_recovery_data_backfill.rs
+++ b/crates/router/src/core/revenue_recovery_data_backfill.rs
@@ -1,10 +1,12 @@
 use std::collections::HashMap;
 
 use api_models::revenue_recovery_data_backfill::{
-    BackfillError, ComprehensiveCardData, RevenueRecoveryBackfillRequest,
-    RevenueRecoveryDataBackfillResponse, UnlockStatusResponse,
+    BackfillError, ComprehensiveCardData, GetRedisDataQuery, RedisDataResponse, RedisKeyType,
+    RevenueRecoveryBackfillRequest, RevenueRecoveryDataBackfillResponse, ScheduledAtUpdate,
+    UnlockStatusResponse, UpdateTokenStatusRequest, UpdateTokenStatusResponse,
 };
 use common_enums::{CardNetwork, PaymentMethodType};
+use error_stack::ResultExt;
 use hyperswitch_domain_models::api::ApplicationResponse;
 use masking::ExposeInterface;
 use router_env::{instrument, logger};
@@ -86,6 +88,150 @@ pub async fn unlock_connector_customer_status(
 
     Ok(ApplicationResponse::Json(response))
 }
+pub async fn get_redis_data(
+    state: SessionState,
+    connector_customer_id: &str,
+    key_type: &RedisKeyType,
+) -> RouterResult<ApplicationResponse<RedisDataResponse>> {
+    match storage::revenue_recovery_redis_operation::RedisTokenManager::get_redis_key_data_raw(
+        &state,
+        connector_customer_id,
+        key_type,
+    )
+    .await
+    {
+        Ok((exists, ttl_seconds, data)) => {
+            let response = RedisDataResponse {
+                exists,
+                ttl_seconds,
+                data,
+            };
+
+            logger::info!(
+                "Retrieved Redis data for connector customer {}, exists={}, ttl={}",
+                connector_customer_id,
+                exists,
+                ttl_seconds
+            );
+
+            Ok(ApplicationResponse::Json(response))
+        }
+        Err(error) => Err(
+            error.change_context(errors::ApiErrorResponse::GenericNotFoundError {
+                message: format!(
+                    "Redis data not found for connector customer id:- '{}'",
+                    connector_customer_id
+                ),
+            }),
+        ),
+    }
+}
+
+pub async fn redis_update_additional_details_for_revenue_recovery(
+    state: SessionState,
+    request: UpdateTokenStatusRequest,
+) -> RouterResult<ApplicationResponse<UpdateTokenStatusResponse>> {
+    // Get existing token
+    let existing_token = storage::revenue_recovery_redis_operation::
+        RedisTokenManager::get_payment_processor_token_using_token_id(
+            &state,
+            &request.connector_customer_id,
+            &request.payment_processor_token.clone().expose(),
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to retrieve existing token data")?;
+
+    // Check if token exists
+    let mut token_status = existing_token.ok_or_else(|| {
+        error_stack::Report::new(errors::ApiErrorResponse::GenericNotFoundError {
+            message: format!(
+                "Token '{:?}' not found for connector customer id:- '{}'",
+                request.payment_processor_token, request.connector_customer_id
+            ),
+        })
+    })?;
+
+    let mut updated_fields = Vec::new();
+
+    // Handle scheduled_at update
+    match request.scheduled_at {
+        Some(ScheduledAtUpdate::SetToDateTime(dt)) => {
+            // Field provided with datetime - update schedule_at field with datetime
+            token_status.scheduled_at = Some(dt);
+            updated_fields.push(format!("scheduled_at: {}", dt));
+            logger::info!(
+                "Set scheduled_at to '{}' for token '{:?}'",
+                dt,
+                request.payment_processor_token
+            );
+        }
+        Some(ScheduledAtUpdate::SetToNull) => {
+            // Field provided with "null" variable - set schedule_at field to null
+            token_status.scheduled_at = None;
+            updated_fields.push("scheduled_at: set to null".to_string());
+            logger::info!(
+                "Set scheduled_at to null for token '{:?}'",
+                request.payment_processor_token
+            );
+        }
+        None => {
+            // Field not provided - we don't update schedule_at field
+            logger::debug!("scheduled_at not provided in request - leaving unchanged");
+        }
+    }
+
+    // Update is_hard_decline field
+    request.is_hard_decline.map(|is_hard_decline| {
+        token_status.is_hard_decline = Some(is_hard_decline);
+        updated_fields.push(format!("is_hard_decline: {}", is_hard_decline));
+    });
+
+    // Update error_code field
+    request.error_code.as_ref().map(|error_code| {
+        token_status.error_code = Some(error_code.clone());
+        updated_fields.push(format!("error_code: {}", error_code));
+    });
+
+    // Update Redis with modified token
+    let mut tokens_map = HashMap::new();
+    tokens_map.insert(
+        request.payment_processor_token.clone().expose(),
+        token_status,
+    );
+
+    storage::revenue_recovery_redis_operation::
+        RedisTokenManager::update_or_add_connector_customer_payment_processor_tokens(
+            &state,
+            &request.connector_customer_id,
+            tokens_map,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to update token status in Redis")?;
+
+    let updated_fields_str = if updated_fields.is_empty() {
+        "no fields were updated".to_string()
+    } else {
+        updated_fields.join(", ")
+    };
+
+    let response = UpdateTokenStatusResponse {
+        updated: true,
+        message: format!(
+            "Successfully updated token '{:?}' for connector customer '{}'. Updated fields: {}",
+            request.payment_processor_token, request.connector_customer_id, updated_fields_str
+        ),
+    };
+
+    logger::info!(
+        "Updated token status for connector customer {}, token: {:?}",
+        request.connector_customer_id,
+        request.payment_processor_token
+    );
+
+    Ok(ApplicationResponse::Json(response))
+}
 
 async fn process_payment_method_record(
     state: &SessionState,
diff --git a/crates/router/src/routes.rs b/crates/router/src/routes.rs
index faefaffa547..a41c1df68f6 100644
--- a/crates/router/src/routes.rs
+++ b/crates/router/src/routes.rs
@@ -50,6 +50,8 @@ pub mod recon;
 pub mod refunds;
 #[cfg(feature = "v2")]
 pub mod revenue_recovery_data_backfill;
+#[cfg(feature = "v2")]
+pub mod revenue_recovery_redis;
 #[cfg(feature = "olap")]
 pub mod routing;
 #[cfg(feature = "v1")]
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 1de0029f767..9647be8caf1 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -3018,5 +3018,15 @@ impl RecoveryDataBackfill {
                     super::revenue_recovery_data_backfill::revenue_recovery_data_backfill_status,
                 ),
             ))
+            .service(web::resource("/redis-data/{token_id}").route(
+                web::get().to(
+                    super::revenue_recovery_redis::get_revenue_recovery_redis_data,
+                ),
+            ))
+            .service(web::resource("/update-token").route(
+                web::put().to(
+                    super::revenue_recovery_data_backfill::update_revenue_recovery_additional_redis_data,
+                ),
+            ))
     }
 }
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index 992edb61c35..922a0de1708 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -50,7 +50,7 @@ pub enum ApiIdentifier {
     ProfileAcquirer,
     ThreeDsDecisionRule,
     GenericTokenization,
-    RecoveryDataBackfill,
+    RecoveryRecovery,
 }
 
 impl From<Flow> for ApiIdentifier {
@@ -350,7 +350,7 @@ impl From<Flow> for ApiIdentifier {
                 Self::GenericTokenization
             }
 
-            Flow::RecoveryDataBackfill => Self::RecoveryDataBackfill,
+            Flow::RecoveryDataBackfill | Flow::RevenueRecoveryRedis => Self::RecoveryRecovery,
         }
     }
 }
diff --git a/crates/router/src/routes/revenue_recovery_data_backfill.rs b/crates/router/src/routes/revenue_recovery_data_backfill.rs
index 4203f52dfff..3a5c378e74c 100644
--- a/crates/router/src/routes/revenue_recovery_data_backfill.rs
+++ b/crates/router/src/routes/revenue_recovery_data_backfill.rs
@@ -1,6 +1,8 @@
 use actix_multipart::form::MultipartForm;
 use actix_web::{web, HttpRequest, HttpResponse};
-use api_models::revenue_recovery_data_backfill::{BackfillQuery, RevenueRecoveryDataBackfillForm};
+use api_models::revenue_recovery_data_backfill::{
+    BackfillQuery, GetRedisDataQuery, RevenueRecoveryDataBackfillForm, UpdateTokenStatusRequest,
+};
 use router_env::{instrument, tracing, Flow};
 
 use crate::{
@@ -66,6 +68,30 @@ pub async fn revenue_recovery_data_backfill(
     .await
 }
 
+#[instrument(skip_all, fields(flow = ?Flow::RecoveryDataBackfill))]
+pub async fn update_revenue_recovery_additional_redis_data(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    json_payload: web::Json<UpdateTokenStatusRequest>,
+) -> HttpResponse {
+    let flow = Flow::RecoveryDataBackfill;
+
+    Box::pin(api::server_wrap(
+        flow,
+        state,
+        &req,
+        json_payload.into_inner(),
+        |state, _: (), request, _| {
+            revenue_recovery_data_backfill::redis_update_additional_details_for_revenue_recovery(
+                state, request,
+            )
+        },
+        &auth::V2AdminApiAuth,
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
+
 #[instrument(skip_all, fields(flow = ?Flow::RecoveryDataBackfill))]
 pub async fn revenue_recovery_data_backfill_status(
     state: web::Data<AppState>,
diff --git a/crates/router/src/routes/revenue_recovery_redis.rs b/crates/router/src/routes/revenue_recovery_redis.rs
new file mode 100644
index 00000000000..fe6cbe5a97b
--- /dev/null
+++ b/crates/router/src/routes/revenue_recovery_redis.rs
@@ -0,0 +1,34 @@
+use actix_web::{web, HttpRequest, HttpResponse};
+use api_models::revenue_recovery_data_backfill::GetRedisDataQuery;
+use router_env::{instrument, tracing, Flow};
+
+use crate::{
+    core::{api_locking, revenue_recovery_data_backfill},
+    routes::AppState,
+    services::{api, authentication as auth},
+};
+
+#[instrument(skip_all, fields(flow = ?Flow::RevenueRecoveryRedis))]
+pub async fn get_revenue_recovery_redis_data(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    path: web::Path<String>,
+    query: web::Query<GetRedisDataQuery>,
+) -> HttpResponse {
+    let flow = Flow::RevenueRecoveryRedis;
+    let connector_customer_id = path.into_inner();
+    let key_type = &query.key_type;
+
+    Box::pin(api::server_wrap(
+        flow,
+        state,
+        &req,
+        (),
+        |state, _: (), _, _| {
+            revenue_recovery_data_backfill::get_redis_data(state, &connector_customer_id, key_type)
+        },
+        &auth::V2AdminApiAuth,
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
diff --git a/crates/router/src/types/storage/revenue_recovery_redis_operation.rs b/crates/router/src/types/storage/revenue_recovery_redis_operation.rs
index e89db0d1aa8..96b0a438355 100644
--- a/crates/router/src/types/storage/revenue_recovery_redis_operation.rs
+++ b/crates/router/src/types/storage/revenue_recovery_redis_operation.rs
@@ -1,6 +1,6 @@
 use std::collections::HashMap;
 
-use api_models;
+use api_models::revenue_recovery_data_backfill::{self, RedisKeyType};
 use common_enums::enums::CardNetwork;
 use common_utils::{date_time, errors::CustomResult, id_type};
 use error_stack::ResultExt;
@@ -755,13 +755,90 @@ impl RedisTokenManager {
         Ok(token)
     }
 
+    /// Get Redis key data for revenue recovery
+    #[instrument(skip_all)]
+    pub async fn get_redis_key_data_raw(
+        state: &SessionState,
+        connector_customer_id: &str,
+        key_type: &RedisKeyType,
+    ) -> CustomResult<(bool, i64, Option<serde_json::Value>), errors::StorageError> {
+        let redis_conn =
+            state
+                .store
+                .get_redis_conn()
+                .change_context(errors::StorageError::RedisError(
+                    errors::RedisError::RedisConnectionError.into(),
+                ))?;
+
+        let redis_key = match key_type {
+            RedisKeyType::Status => Self::get_connector_customer_lock_key(connector_customer_id),
+            RedisKeyType::Tokens => Self::get_connector_customer_tokens_key(connector_customer_id),
+        };
+
+        // Get TTL
+        let ttl = redis_conn
+            .get_ttl(&redis_key.clone().into())
+            .await
+            .map_err(|error| {
+                tracing::error!(operation = "get_ttl", err = ?error);
+                errors::StorageError::RedisError(errors::RedisError::GetHashFieldFailed.into())
+            })?;
+
+        // Get data based on key type and determine existence
+        let (key_exists, data) = match key_type {
+            RedisKeyType::Status => match redis_conn.get_key::<String>(&redis_key.into()).await {
+                Ok(status_value) => (true, serde_json::Value::String(status_value)),
+                Err(error) => {
+                    tracing::error!(operation = "get_status_key", err = ?error);
+                    (
+                        false,
+                        serde_json::Value::String(format!(
+                            "Error retrieving status key: {}",
+                            error
+                        )),
+                    )
+                }
+            },
+            RedisKeyType::Tokens => {
+                match redis_conn
+                    .get_hash_fields::<HashMap<String, String>>(&redis_key.into())
+                    .await
+                {
+                    Ok(hash_fields) => {
+                        let exists = !hash_fields.is_empty();
+                        let data = if exists {
+                            serde_json::to_value(hash_fields).unwrap_or(serde_json::Value::Null)
+                        } else {
+                            serde_json::Value::Object(serde_json::Map::new())
+                        };
+                        (exists, data)
+                    }
+                    Err(error) => {
+                        tracing::error!(operation = "get_tokens_hash", err = ?error);
+                        (false, serde_json::Value::Null)
+                    }
+                }
+            }
+        };
+
+        tracing::debug!(
+            connector_customer_id = connector_customer_id,
+            key_type = ?key_type,
+            exists = key_exists,
+            ttl = ttl,
+            "Retrieved Redis key data"
+        );
+
+        Ok((key_exists, ttl, Some(data)))
+    }
+
     /// Update Redis token with comprehensive card data
     #[instrument(skip_all)]
     pub async fn update_redis_token_with_comprehensive_card_data(
         state: &SessionState,
         customer_id: &str,
         token: &str,
-        card_data: &api_models::revenue_recovery_data_backfill::ComprehensiveCardData,
+        card_data: &revenue_recovery_data_backfill::ComprehensiveCardData,
         cutoff_datetime: Option<PrimitiveDateTime>,
     ) -> CustomResult<(), errors::StorageError> {
         // Get existing token data
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index 50c47489108..0213c5c9b27 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -658,6 +658,8 @@ pub enum Flow {
     TokenizationDelete,
     /// Payment method data backfill flow
     RecoveryDataBackfill,
+    /// Revenue recovery Redis operations flow
+    RevenueRecoveryRedis,
     /// Gift card balance check flow
     GiftCardBalanceCheck,
 }