Issue:
Bug: feat: Add schema to store chat request response



- add schema for chat, to store request and response
- store chats to chat schema asynchronously
- encrypt the sensitive data
- have endpoint to list the chat data and decrypt it properly


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 -->

- Store the user query and response from the ai service for the analysis.
- Allow the api only for internal user

### Additional Changes
This pull request introduces support for encrypted chat conversations and adds database models and APIs for storing and retrieving chat interactions. The changes span configuration, API models, database schema, and core logic to enable secure chat storage and querying, with proper secret management for encryption keys.

**Chat encryption and configuration:**
* Added `encryption_key` to `[chat]` sections in all config files and updated `ChatSettings` to use a secret for the encryption key, with secret management integration for secure handling.

**Chat API model extensions:**
* Added new API models for listing chat conversations (`ChatListRequest`, `ChatConversation`, `ChatListResponse`)

**Database schema and models for chat interactions:**
* Introduced `hyperswitch_ai_interaction` table and corresponding Rust models for storing encrypted chat queries and 

**Core chat logic improvements:**
* Enhanced chat workflow to fetch role information, set entity type, and use the decrypted chat encryption key for secure communication with the AI service. 

**Run this as part of migration**

 1.Manual Partition creation for next two year.
 2.Creates partitions for each 3-month range
 3.Add calendar event to re run this after two year. 

```
DO $$
DECLARE
    start_date date;
    end_date date;
    i int;
    partition_name text;
BEGIN
    -- Get start date as the beginning of the current quarter
    start_date := date_trunc('quarter', current_date)::date;

    -- Create 8 quarterly partitions (2 years)
    FOR i IN 1..8 LOOP
        end_date := (start_date + interval '3 month')::date;

        partition_name := format(
            'hyperswitch_ai_interaction_%s_q%s',
            to_char(start_date, 'YYYY'),
            extract(quarter from start_date)
        );

        EXECUTE format(
            'CREATE TABLE IF NOT EXISTS %I PARTITION OF hyperswitch_ai_interaction
             FOR VALUES FROM (%L) TO (%L)',
            partition_name, start_date, end_date
        );

        start_date := end_date;
    END LOOP;
END$$;
```
**General enhancements and constants:**
* Added default limit and offset constants for list operations, improving pagination support for chat conversation queries.
- [ ] 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
Closes #8847 


## How did you test it?
Hitting AI service, should store information in DB
```
curl --location 'http://localhost:8080/chat/ai/data' \
--header 'x-feature: integ-custom' \
--header 'x-chat-session-id: chat-dop' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer JWT' \
--data '{
        "message": "total count of payments"
    
}'
```
Can check hyperswitch AI interaction table for it.

Internal roles can see the list of interactions for the given merchant id
List

```
curl --location 'http://localhost:8080/chat/ai/list?merchant_id=merchant_id' \
--header 'Authorization: Bearer JWT' \
--data ''
```

## 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`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible


Testing:
Hitting AI service, should store information in DB
```
curl --location 'http://localhost:8080/chat/ai/data' \
--header 'x-feature: integ-custom' \
--header 'x-chat-session-id: chat-dop' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer JWT' \
--data '{
        "message": "total count of payments"
    
}'
```
Can check hyperswitch AI interaction table for it.

Internal roles can see the list of interactions for the given merchant id
List

```
curl --location 'http://localhost:8080/chat/ai/list?merchant_id=merchant_id' \
--header 'Authorization: Bearer JWT' \
--data ''
```

Patch:
diff --git a/config/config.example.toml b/config/config.example.toml
index b725be102c1..134e0a49e84 100644
--- a/config/config.example.toml
+++ b/config/config.example.toml
@@ -1257,6 +1257,7 @@ allow_connected_merchants = false # Enable or disable connected merchant account
 [chat]
 enabled = false                                # Enable or disable chat features
 hyperswitch_ai_host = "http://0.0.0.0:8000"    # Hyperswitch ai workflow host
+encryption_key = ""                            # Key to encrypt and decrypt chats
 
 [proxy_status_mapping]
 proxy_connector_http_status_code = false    # If enabled, the http status code of the connector will be proxied in the response
diff --git a/config/deployments/env_specific.toml b/config/deployments/env_specific.toml
index bfba035c1f3..fe8b09cd7db 100644
--- a/config/deployments/env_specific.toml
+++ b/config/deployments/env_specific.toml
@@ -419,6 +419,7 @@ max_random_schedule_delay_in_seconds = 300 # max random delay in seconds to sche
 [chat]
 enabled = false                                # Enable or disable chat features
 hyperswitch_ai_host = "http://0.0.0.0:8000"    # Hyperswitch ai workflow host
+encryption_key = ""                            # Key to encrypt and decrypt chats
 
 [proxy_status_mapping]
 proxy_connector_http_status_code = false    # If enabled, the http status code of the connector will be proxied in the response
diff --git a/config/development.toml b/config/development.toml
index 940e43b50ca..e4cbe3af226 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -1368,6 +1368,7 @@ version = "HOSTNAME"
 [chat]
 enabled = false
 hyperswitch_ai_host = "http://0.0.0.0:8000"
+encryption_key = ""
 
 [proxy_status_mapping]
 proxy_connector_http_status_code = false    # If enabled, the http status code of the connector will be proxied in the response
diff --git a/config/docker_compose.toml b/config/docker_compose.toml
index d299323f2c1..62f6830832c 100644
--- a/config/docker_compose.toml
+++ b/config/docker_compose.toml
@@ -1226,6 +1226,7 @@ allow_connected_merchants = true
 [chat]
 enabled = false
 hyperswitch_ai_host = "http://0.0.0.0:8000"
+encryption_key = ""
 
 [authentication_providers]
 click_to_pay = {connector_list = "adyen, cybersource, trustpay"}
diff --git a/crates/api_models/src/chat.rs b/crates/api_models/src/chat.rs
index c66b42cc4f4..975197fd3fc 100644
--- a/crates/api_models/src/chat.rs
+++ b/crates/api_models/src/chat.rs
@@ -1,12 +1,13 @@
 use common_utils::id_type;
 use masking::Secret;
+use time::PrimitiveDateTime;
 
 #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
 pub struct ChatRequest {
     pub message: Secret<String>,
 }
 
-#[derive(Debug, serde::Deserialize, serde::Serialize)]
+#[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
 pub struct ChatResponse {
     pub response: Secret<serde_json::Value>,
     pub merchant_id: id_type::MerchantId,
@@ -16,3 +17,32 @@ pub struct ChatResponse {
     #[serde(skip_serializing)]
     pub row_count: Option<i32>,
 }
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct ChatListRequest {
+    pub merchant_id: Option<id_type::MerchantId>,
+    pub limit: Option<i64>,
+    pub offset: Option<i64>,
+}
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct ChatConversation {
+    pub id: String,
+    pub session_id: Option<String>,
+    pub user_id: Option<String>,
+    pub merchant_id: Option<String>,
+    pub profile_id: Option<String>,
+    pub org_id: Option<String>,
+    pub role_id: Option<String>,
+    pub user_query: Secret<String>,
+    pub response: Secret<serde_json::Value>,
+    pub database_query: Option<String>,
+    pub interaction_status: Option<String>,
+    #[serde(with = "common_utils::custom_serde::iso8601")]
+    pub created_at: PrimitiveDateTime,
+}
+
+#[derive(Debug, serde::Deserialize, serde::Serialize)]
+pub struct ChatListResponse {
+    pub conversations: Vec<ChatConversation>,
+}
diff --git a/crates/api_models/src/events/chat.rs b/crates/api_models/src/events/chat.rs
index 42fefe487e9..38f20b0c3bb 100644
--- a/crates/api_models/src/events/chat.rs
+++ b/crates/api_models/src/events/chat.rs
@@ -1,5 +1,8 @@
 use common_utils::events::{ApiEventMetric, ApiEventsType};
 
-use crate::chat::{ChatRequest, ChatResponse};
+use crate::chat::{ChatListRequest, ChatListResponse, ChatRequest, ChatResponse};
 
-common_utils::impl_api_event_type!(Chat, (ChatRequest, ChatResponse));
+common_utils::impl_api_event_type!(
+    Chat,
+    (ChatRequest, ChatResponse, ChatListRequest, ChatListResponse)
+);
diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs
index 28508749f35..59ec5377690 100644
--- a/crates/common_utils/src/consts.rs
+++ b/crates/common_utils/src/consts.rs
@@ -197,3 +197,9 @@ pub const REQUEST_TIME_OUT: u64 = 30;
 
 /// API client request timeout for ai service (in seconds)
 pub const REQUEST_TIME_OUT_FOR_AI_SERVICE: u64 = 120;
+
+/// Default limit for list operations (can be used across different entities)
+pub const DEFAULT_LIST_LIMIT: i64 = 100;
+
+/// Default offset for list operations (can be used across different entities)
+pub const DEFAULT_LIST_OFFSET: i64 = 0;
diff --git a/crates/diesel_models/src/hyperswitch_ai_interaction.rs b/crates/diesel_models/src/hyperswitch_ai_interaction.rs
new file mode 100644
index 00000000000..a22bd288c19
--- /dev/null
+++ b/crates/diesel_models/src/hyperswitch_ai_interaction.rs
@@ -0,0 +1,49 @@
+use common_utils::encryption::Encryption;
+use diesel::{self, Identifiable, Insertable, Queryable, Selectable};
+use serde::{Deserialize, Serialize};
+use time::PrimitiveDateTime;
+
+use crate::schema::hyperswitch_ai_interaction;
+
+#[derive(
+    Clone,
+    Debug,
+    Deserialize,
+    Identifiable,
+    Queryable,
+    Selectable,
+    Serialize,
+    router_derive::DebugAsDisplay,
+)]
+#[diesel(table_name = hyperswitch_ai_interaction, primary_key(id, created_at), check_for_backend(diesel::pg::Pg))]
+pub struct HyperswitchAiInteraction {
+    pub id: String,
+    pub session_id: Option<String>,
+    pub user_id: Option<String>,
+    pub merchant_id: Option<String>,
+    pub profile_id: Option<String>,
+    pub org_id: Option<String>,
+    pub role_id: Option<String>,
+    pub user_query: Option<Encryption>,
+    pub response: Option<Encryption>,
+    pub database_query: Option<String>,
+    pub interaction_status: Option<String>,
+    pub created_at: PrimitiveDateTime,
+}
+
+#[derive(router_derive::Setter, Clone, Debug, Insertable, router_derive::DebugAsDisplay)]
+#[diesel(table_name = hyperswitch_ai_interaction)]
+pub struct HyperswitchAiInteractionNew {
+    pub id: String,
+    pub session_id: Option<String>,
+    pub user_id: Option<String>,
+    pub merchant_id: Option<String>,
+    pub profile_id: Option<String>,
+    pub org_id: Option<String>,
+    pub role_id: Option<String>,
+    pub user_query: Option<Encryption>,
+    pub response: Option<Encryption>,
+    pub database_query: Option<String>,
+    pub interaction_status: Option<String>,
+    pub created_at: PrimitiveDateTime,
+}
diff --git a/crates/diesel_models/src/lib.rs b/crates/diesel_models/src/lib.rs
index caf979b2c5f..b715134f926 100644
--- a/crates/diesel_models/src/lib.rs
+++ b/crates/diesel_models/src/lib.rs
@@ -23,6 +23,7 @@ pub mod file;
 pub mod fraud_check;
 pub mod generic_link;
 pub mod gsm;
+pub mod hyperswitch_ai_interaction;
 #[cfg(feature = "kv_store")]
 pub mod kv;
 pub mod locker_mock_up;
@@ -69,10 +70,11 @@ pub type StorageResult<T> = error_stack::Result<T, errors::DatabaseError>;
 pub type PgPooledConn = async_bb8_diesel::Connection<diesel::PgConnection>;
 pub use self::{
     address::*, api_keys::*, callback_mapper::*, cards_info::*, configs::*, customers::*,
-    dispute::*, ephemeral_key::*, events::*, file::*, generic_link::*, locker_mock_up::*,
-    mandate::*, merchant_account::*, merchant_connector_account::*, payment_attempt::*,
-    payment_intent::*, payment_method::*, payout_attempt::*, payouts::*, process_tracker::*,
-    refund::*, reverse_lookup::*, user_authentication_method::*,
+    dispute::*, ephemeral_key::*, events::*, file::*, generic_link::*,
+    hyperswitch_ai_interaction::*, locker_mock_up::*, mandate::*, merchant_account::*,
+    merchant_connector_account::*, payment_attempt::*, payment_intent::*, payment_method::*,
+    payout_attempt::*, payouts::*, process_tracker::*, refund::*, reverse_lookup::*,
+    user_authentication_method::*,
 };
 /// The types and implementations provided by this module are required for the schema generated by
 /// `diesel_cli` 2.0 to work with the types defined in Rust code. This is because
diff --git a/crates/diesel_models/src/query.rs b/crates/diesel_models/src/query.rs
index 17eae2427e7..2dc6c18a1a1 100644
--- a/crates/diesel_models/src/query.rs
+++ b/crates/diesel_models/src/query.rs
@@ -21,6 +21,7 @@ pub mod fraud_check;
 pub mod generic_link;
 pub mod generics;
 pub mod gsm;
+pub mod hyperswitch_ai_interaction;
 pub mod locker_mock_up;
 pub mod mandate;
 pub mod merchant_account;
diff --git a/crates/diesel_models/src/query/hyperswitch_ai_interaction.rs b/crates/diesel_models/src/query/hyperswitch_ai_interaction.rs
new file mode 100644
index 00000000000..91db3ec468e
--- /dev/null
+++ b/crates/diesel_models/src/query/hyperswitch_ai_interaction.rs
@@ -0,0 +1,32 @@
+use diesel::{associations::HasTable, ExpressionMethods};
+
+use crate::{
+    hyperswitch_ai_interaction::{HyperswitchAiInteraction, HyperswitchAiInteractionNew},
+    query::generics,
+    schema::hyperswitch_ai_interaction::dsl,
+    PgPooledConn, StorageResult,
+};
+
+impl HyperswitchAiInteractionNew {
+    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<HyperswitchAiInteraction> {
+        generics::generic_insert(conn, self).await
+    }
+}
+
+impl HyperswitchAiInteraction {
+    pub async fn filter_by_optional_merchant_id(
+        conn: &PgPooledConn,
+        merchant_id: Option<&common_utils::id_type::MerchantId>,
+        limit: i64,
+        offset: i64,
+    ) -> StorageResult<Vec<Self>> {
+        generics::generic_filter::<<Self as HasTable>::Table, _, _, _>(
+            conn,
+            dsl::merchant_id.eq(merchant_id.cloned()),
+            Some(limit),
+            Some(offset),
+            Some(dsl::created_at.desc()),
+        )
+        .await
+    }
+}
diff --git a/crates/diesel_models/src/query/utils.rs b/crates/diesel_models/src/query/utils.rs
index fe2f43d419b..96a41f10ca0 100644
--- a/crates/diesel_models/src/query/utils.rs
+++ b/crates/diesel_models/src/query/utils.rs
@@ -52,6 +52,12 @@ mod composite_key {
             self.0
         }
     }
+    impl CompositeKey for <schema::hyperswitch_ai_interaction::table as diesel::Table>::PrimaryKey {
+        type UK = schema::hyperswitch_ai_interaction::dsl::id;
+        fn get_local_unique_key(&self) -> Self::UK {
+            self.0
+        }
+    }
     impl CompositeKey for <schema_v2::incremental_authorization::table as diesel::Table>::PrimaryKey {
         type UK = schema_v2::incremental_authorization::dsl::authorization_id;
         fn get_local_unique_key(&self) -> Self::UK {
@@ -139,6 +145,7 @@ impl_get_primary_key_for_composite!(
     schema::customers::table,
     schema::blocklist::table,
     schema::incremental_authorization::table,
+    schema::hyperswitch_ai_interaction::table,
     schema_v2::incremental_authorization::table,
     schema_v2::blocklist::table
 );
diff --git a/crates/diesel_models/src/schema.rs b/crates/diesel_models/src/schema.rs
index 79df62ac4b2..271d2a79ba0 100644
--- a/crates/diesel_models/src/schema.rs
+++ b/crates/diesel_models/src/schema.rs
@@ -632,6 +632,62 @@ diesel::table! {
     }
 }
 
+diesel::table! {
+    use diesel::sql_types::*;
+    use crate::enums::diesel_exports::*;
+
+    hyperswitch_ai_interaction (id, created_at) {
+        #[max_length = 64]
+        id -> Varchar,
+        #[max_length = 64]
+        session_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        user_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        merchant_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        profile_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        org_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        role_id -> Nullable<Varchar>,
+        user_query -> Nullable<Bytea>,
+        response -> Nullable<Bytea>,
+        database_query -> Nullable<Text>,
+        #[max_length = 64]
+        interaction_status -> Nullable<Varchar>,
+        created_at -> Timestamp,
+    }
+}
+
+diesel::table! {
+    use diesel::sql_types::*;
+    use crate::enums::diesel_exports::*;
+
+    hyperswitch_ai_interaction_default (id, created_at) {
+        #[max_length = 64]
+        id -> Varchar,
+        #[max_length = 64]
+        session_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        user_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        merchant_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        profile_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        org_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        role_id -> Nullable<Varchar>,
+        user_query -> Nullable<Bytea>,
+        response -> Nullable<Bytea>,
+        database_query -> Nullable<Text>,
+        #[max_length = 64]
+        interaction_status -> Nullable<Varchar>,
+        created_at -> Timestamp,
+    }
+}
+
 diesel::table! {
     use diesel::sql_types::*;
     use crate::enums::diesel_exports::*;
@@ -1667,6 +1723,8 @@ diesel::allow_tables_to_appear_in_same_query!(
     fraud_check,
     gateway_status_map,
     generic_link,
+    hyperswitch_ai_interaction,
+    hyperswitch_ai_interaction_default,
     incremental_authorization,
     locker_mock_up,
     mandate,
diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs
index b2e674f34a5..4195475f88d 100644
--- a/crates/diesel_models/src/schema_v2.rs
+++ b/crates/diesel_models/src/schema_v2.rs
@@ -646,6 +646,62 @@ diesel::table! {
     }
 }
 
+diesel::table! {
+    use diesel::sql_types::*;
+    use crate::enums::diesel_exports::*;
+
+    hyperswitch_ai_interaction (id, created_at) {
+        #[max_length = 64]
+        id -> Varchar,
+        #[max_length = 64]
+        session_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        user_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        merchant_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        profile_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        org_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        role_id -> Nullable<Varchar>,
+        user_query -> Nullable<Bytea>,
+        response -> Nullable<Bytea>,
+        database_query -> Nullable<Text>,
+        #[max_length = 64]
+        interaction_status -> Nullable<Varchar>,
+        created_at -> Timestamp,
+    }
+}
+
+diesel::table! {
+    use diesel::sql_types::*;
+    use crate::enums::diesel_exports::*;
+
+    hyperswitch_ai_interaction_default (id, created_at) {
+        #[max_length = 64]
+        id -> Varchar,
+        #[max_length = 64]
+        session_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        user_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        merchant_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        profile_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        org_id -> Nullable<Varchar>,
+        #[max_length = 64]
+        role_id -> Nullable<Varchar>,
+        user_query -> Nullable<Bytea>,
+        response -> Nullable<Bytea>,
+        database_query -> Nullable<Text>,
+        #[max_length = 64]
+        interaction_status -> Nullable<Varchar>,
+        created_at -> Timestamp,
+    }
+}
+
 diesel::table! {
     use diesel::sql_types::*;
     use crate::enums::diesel_exports::*;
@@ -1622,6 +1678,8 @@ diesel::allow_tables_to_appear_in_same_query!(
     fraud_check,
     gateway_status_map,
     generic_link,
+    hyperswitch_ai_interaction,
+    hyperswitch_ai_interaction_default,
     incremental_authorization,
     locker_mock_up,
     mandate,
diff --git a/crates/hyperswitch_domain_models/src/chat.rs b/crates/hyperswitch_domain_models/src/chat.rs
index 31b9f806db7..9243f535c07 100644
--- a/crates/hyperswitch_domain_models/src/chat.rs
+++ b/crates/hyperswitch_domain_models/src/chat.rs
@@ -12,4 +12,5 @@ pub struct HyperswitchAiDataRequest {
     pub profile_id: id_type::ProfileId,
     pub org_id: id_type::OrganizationId,
     pub query: GetDataMessage,
+    pub entity_type: common_enums::EntityType,
 }
diff --git a/crates/router/src/configs/secrets_transformers.rs b/crates/router/src/configs/secrets_transformers.rs
index 3f85f8e2b3a..53ce32b033e 100644
--- a/crates/router/src/configs/secrets_transformers.rs
+++ b/crates/router/src/configs/secrets_transformers.rs
@@ -298,6 +298,29 @@ impl SecretsHandler for settings::UserAuthMethodSettings {
     }
 }
 
+#[async_trait::async_trait]
+impl SecretsHandler for settings::ChatSettings {
+    async fn convert_to_raw_secret(
+        value: SecretStateContainer<Self, SecuredSecret>,
+        secret_management_client: &dyn SecretManagementInterface,
+    ) -> CustomResult<SecretStateContainer<Self, RawSecret>, SecretsManagementError> {
+        let chat_settings = value.get_inner();
+
+        let encryption_key = if chat_settings.enabled {
+            secret_management_client
+                .get_secret(chat_settings.encryption_key.clone())
+                .await?
+        } else {
+            chat_settings.encryption_key.clone()
+        };
+
+        Ok(value.transition_state(|chat_settings| Self {
+            encryption_key,
+            ..chat_settings
+        }))
+    }
+}
+
 #[async_trait::async_trait]
 impl SecretsHandler for settings::NetworkTokenizationService {
     async fn convert_to_raw_secret(
@@ -450,9 +473,14 @@ pub(crate) async fn fetch_raw_secrets(
         })
         .await;
 
+    #[allow(clippy::expect_used)]
+    let chat = settings::ChatSettings::convert_to_raw_secret(conf.chat, secret_management_client)
+        .await
+        .expect("Failed to decrypt chat configs");
+
     Settings {
         server: conf.server,
-        chat: conf.chat,
+        chat,
         master_database,
         redis: conf.redis,
         log: conf.log,
diff --git a/crates/router/src/configs/settings.rs b/crates/router/src/configs/settings.rs
index 84bc63ca799..1923af66b35 100644
--- a/crates/router/src/configs/settings.rs
+++ b/crates/router/src/configs/settings.rs
@@ -71,7 +71,7 @@ pub struct Settings<S: SecretState> {
     pub server: Server,
     pub proxy: Proxy,
     pub env: Env,
-    pub chat: ChatSettings,
+    pub chat: SecretStateContainer<ChatSettings, S>,
     pub master_database: SecretStateContainer<Database, S>,
     #[cfg(feature = "olap")]
     pub replica_database: SecretStateContainer<Database, S>,
@@ -207,6 +207,7 @@ pub struct Platform {
 pub struct ChatSettings {
     pub enabled: bool,
     pub hyperswitch_ai_host: String,
+    pub encryption_key: Secret<String>,
 }
 
 #[derive(Debug, Clone, Default, Deserialize)]
@@ -1048,8 +1049,7 @@ impl Settings<SecuredSecret> {
         self.secrets.get_inner().validate()?;
         self.locker.validate()?;
         self.connectors.validate("connectors")?;
-        self.chat.validate()?;
-
+        self.chat.get_inner().validate()?;
         self.cors.validate()?;
 
         self.scheduler
diff --git a/crates/router/src/core/chat.rs b/crates/router/src/core/chat.rs
index 837a259bed4..a690986a04a 100644
--- a/crates/router/src/core/chat.rs
+++ b/crates/router/src/core/chat.rs
@@ -1,18 +1,24 @@
 use api_models::chat as chat_api;
 use common_utils::{
     consts,
+    crypto::{DecodeMessage, GcmAes256},
     errors::CustomResult,
     request::{Method, RequestBuilder, RequestContent},
 };
 use error_stack::ResultExt;
 use external_services::http_client;
 use hyperswitch_domain_models::chat as chat_domain;
-use router_env::{instrument, logger, tracing};
+use masking::ExposeInterface;
+use router_env::{
+    instrument, logger,
+    tracing::{self, Instrument},
+};
 
 use crate::{
     db::errors::chat::ChatErrors,
     routes::{app::SessionStateInfo, SessionState},
-    services::{authentication as auth, ApplicationResponse},
+    services::{authentication as auth, authorization::roles, ApplicationResponse},
+    utils,
 };
 
 #[instrument(skip_all, fields(?session_id))]
@@ -22,15 +28,34 @@ pub async fn get_data_from_hyperswitch_ai_workflow(
     req: chat_api::ChatRequest,
     session_id: Option<&str>,
 ) -> CustomResult<ApplicationResponse<chat_api::ChatResponse>, ChatErrors> {
-    let url = format!("{}/webhook", state.conf.chat.hyperswitch_ai_host);
-    let request_id = state.get_request_id();
+    let role_info = roles::RoleInfo::from_role_id_org_id_tenant_id(
+        &state,
+        &user_from_token.role_id,
+        &user_from_token.org_id,
+        user_from_token
+            .tenant_id
+            .as_ref()
+            .unwrap_or(&state.tenant.tenant_id),
+    )
+    .await
+    .change_context(ChatErrors::InternalServerError)
+    .attach_printable("Failed to retrieve role information")?;
+    let url = format!(
+        "{}/webhook",
+        state.conf.chat.get_inner().hyperswitch_ai_host
+    );
+    let request_id = state
+        .get_request_id()
+        .unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
+
     let request_body = chat_domain::HyperswitchAiDataRequest {
         query: chat_domain::GetDataMessage {
-            message: req.message,
+            message: req.message.clone(),
         },
-        org_id: user_from_token.org_id,
-        merchant_id: user_from_token.merchant_id,
-        profile_id: user_from_token.profile_id,
+        org_id: user_from_token.org_id.clone(),
+        merchant_id: user_from_token.merchant_id.clone(),
+        profile_id: user_from_token.profile_id.clone(),
+        entity_type: role_info.get_entity_type(),
     };
     logger::info!("Request for AI service: {:?}", request_body);
 
@@ -38,11 +63,9 @@ pub async fn get_data_from_hyperswitch_ai_workflow(
         .method(Method::Post)
         .url(&url)
         .attach_default_headers()
+        .header(consts::X_REQUEST_ID, &request_id)
         .set_body(RequestContent::Json(Box::new(request_body.clone())));
 
-    if let Some(request_id) = request_id {
-        request_builder = request_builder.header(consts::X_REQUEST_ID, &request_id);
-    }
     if let Some(session_id) = session_id {
         request_builder = request_builder.header(consts::X_CHAT_SESSION_ID, session_id);
     }
@@ -57,10 +80,132 @@ pub async fn get_data_from_hyperswitch_ai_workflow(
     .await
     .change_context(ChatErrors::InternalServerError)
     .attach_printable("Error when sending request to AI service")?
-    .json::<_>()
+    .json::<chat_api::ChatResponse>()
     .await
     .change_context(ChatErrors::InternalServerError)
     .attach_printable("Error when deserializing response from AI service")?;
 
-    Ok(ApplicationResponse::Json(response))
+    let response_to_return = response.clone();
+    tokio::spawn(
+        async move {
+            let new_hyperswitch_ai_interaction = utils::chat::construct_hyperswitch_ai_interaction(
+                &state,
+                &user_from_token,
+                &req,
+                &response,
+                &request_id,
+            )
+            .await;
+
+            match new_hyperswitch_ai_interaction {
+                Ok(interaction) => {
+                    let db = state.store.as_ref();
+                    if let Err(e) = db.insert_hyperswitch_ai_interaction(interaction).await {
+                        logger::error!("Failed to insert hyperswitch_ai_interaction: {:?}", e);
+                    }
+                }
+                Err(e) => {
+                    logger::error!("Failed to construct hyperswitch_ai_interaction: {:?}", e);
+                }
+            }
+        }
+        .in_current_span(),
+    );
+
+    Ok(ApplicationResponse::Json(response_to_return))
+}
+
+#[instrument(skip_all)]
+pub async fn list_chat_conversations(
+    state: SessionState,
+    user_from_token: auth::UserFromToken,
+    req: chat_api::ChatListRequest,
+) -> CustomResult<ApplicationResponse<chat_api::ChatListResponse>, ChatErrors> {
+    let role_info = roles::RoleInfo::from_role_id_org_id_tenant_id(
+        &state,
+        &user_from_token.role_id,
+        &user_from_token.org_id,
+        user_from_token
+            .tenant_id
+            .as_ref()
+            .unwrap_or(&state.tenant.tenant_id),
+    )
+    .await
+    .change_context(ChatErrors::InternalServerError)
+    .attach_printable("Failed to retrieve role information")?;
+
+    if !role_info.is_internal() {
+        return Err(error_stack::Report::new(ChatErrors::UnauthorizedAccess)
+            .attach_printable("Only internal roles are allowed for this operation"));
+    }
+
+    let db = state.store.as_ref();
+    let hyperswitch_ai_interactions = db
+        .list_hyperswitch_ai_interactions(
+            req.merchant_id,
+            req.limit.unwrap_or(consts::DEFAULT_LIST_LIMIT),
+            req.offset.unwrap_or(consts::DEFAULT_LIST_OFFSET),
+        )
+        .await
+        .change_context(ChatErrors::InternalServerError)
+        .attach_printable("Error when fetching hyperswitch_ai_interactions")?;
+
+    let encryption_key = state.conf.chat.get_inner().encryption_key.clone().expose();
+    let key = match hex::decode(&encryption_key) {
+        Ok(key) => key,
+        Err(e) => {
+            router_env::logger::error!("Failed to decode encryption key: {}", e);
+            encryption_key.as_bytes().to_vec()
+        }
+    };
+
+    let mut conversations = Vec::new();
+
+    for interaction in hyperswitch_ai_interactions {
+        let user_query_encrypted = interaction
+            .user_query
+            .ok_or(ChatErrors::InternalServerError)
+            .attach_printable("Missing user_query field in hyperswitch_ai_interaction")?;
+        let response_encrypted = interaction
+            .response
+            .ok_or(ChatErrors::InternalServerError)
+            .attach_printable("Missing response field in hyperswitch_ai_interaction")?;
+
+        let user_query_decrypted_bytes = GcmAes256
+            .decode_message(&key, user_query_encrypted.into_inner())
+            .change_context(ChatErrors::InternalServerError)
+            .attach_printable("Failed to decrypt user query")?;
+
+        let response_decrypted_bytes = GcmAes256
+            .decode_message(&key, response_encrypted.into_inner())
+            .change_context(ChatErrors::InternalServerError)
+            .attach_printable("Failed to decrypt response")?;
+
+        let user_query_decrypted = String::from_utf8(user_query_decrypted_bytes)
+            .change_context(ChatErrors::InternalServerError)
+            .attach_printable("Failed to convert decrypted user query to string")?;
+
+        let response_decrypted = serde_json::from_slice(&response_decrypted_bytes)
+            .change_context(ChatErrors::InternalServerError)
+            .attach_printable("Failed to deserialize decrypted response")?;
+
+        conversations.push(chat_api::ChatConversation {
+            id: interaction.id,
+            session_id: interaction.session_id,
+            user_id: interaction.user_id,
+            merchant_id: interaction.merchant_id,
+            profile_id: interaction.profile_id,
+            org_id: interaction.org_id,
+            role_id: interaction.role_id,
+            user_query: user_query_decrypted.into(),
+            response: response_decrypted,
+            database_query: interaction.database_query,
+            interaction_status: interaction.interaction_status,
+            created_at: interaction.created_at,
+        });
+    }
+
+    return Ok(ApplicationResponse::Json(chat_api::ChatListResponse {
+        conversations,
+    }));
 }
diff --git a/crates/router/src/core/errors/chat.rs b/crates/router/src/core/errors/chat.rs
index a96afa67de8..d23f0e9bb77 100644
--- a/crates/router/src/core/errors/chat.rs
+++ b/crates/router/src/core/errors/chat.rs
@@ -6,6 +6,8 @@ pub enum ChatErrors {
     MissingConfigError,
     #[error("Chat response deserialization failed")]
     ChatResponseDeserializationFailed,
+    #[error("Unauthorized access")]
+    UnauthorizedAccess,
 }
 
 impl common_utils::errors::ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ChatErrors {
@@ -22,6 +24,9 @@ impl common_utils::errors::ErrorSwitch<api_models::errors::types::ApiErrorRespon
             Self::ChatResponseDeserializationFailed => {
                 AER::BadRequest(ApiError::new(sub_code, 2, self.get_error_message(), None))
             }
+            Self::UnauthorizedAccess => {
+                AER::Unauthorized(ApiError::new(sub_code, 3, self.get_error_message(), None))
+            }
         }
     }
 }
@@ -32,6 +37,7 @@ impl ChatErrors {
             Self::InternalServerError => "Something went wrong".to_string(),
             Self::MissingConfigError => "Missing webhook url".to_string(),
             Self::ChatResponseDeserializationFailed => "Failed to parse chat response".to_string(),
+            Self::UnauthorizedAccess => "Not authorized to access the resource".to_string(),
         }
     }
 }
diff --git a/crates/router/src/db.rs b/crates/router/src/db.rs
index f675e316aef..ab3b7cba577 100644
--- a/crates/router/src/db.rs
+++ b/crates/router/src/db.rs
@@ -20,6 +20,7 @@ pub mod fraud_check;
 pub mod generic_link;
 pub mod gsm;
 pub mod health_check;
+pub mod hyperswitch_ai_interaction;
 pub mod kafka_store;
 pub mod locker_mock_up;
 pub mod mandate;
@@ -137,6 +138,7 @@ pub trait StorageInterface:
     + user::sample_data::BatchSampleDataInterface
     + health_check::HealthCheckDbInterface
     + user_authentication_method::UserAuthenticationMethodInterface
+    + hyperswitch_ai_interaction::HyperswitchAiInteractionInterface
     + authentication::AuthenticationInterface
     + generic_link::GenericLinkInterface
     + relay::RelayInterface
diff --git a/crates/router/src/db/hyperswitch_ai_interaction.rs b/crates/router/src/db/hyperswitch_ai_interaction.rs
new file mode 100644
index 00000000000..4ecf741a088
--- /dev/null
+++ b/crates/router/src/db/hyperswitch_ai_interaction.rs
@@ -0,0 +1,123 @@
+use diesel_models::hyperswitch_ai_interaction as storage;
+use error_stack::report;
+use router_env::{instrument, tracing};
+
+use super::MockDb;
+use crate::{
+    connection,
+    core::errors::{self, CustomResult},
+    services::Store,
+};
+
+#[async_trait::async_trait]
+pub trait HyperswitchAiInteractionInterface {
+    async fn insert_hyperswitch_ai_interaction(
+        &self,
+        hyperswitch_ai_interaction: storage::HyperswitchAiInteractionNew,
+    ) -> CustomResult<storage::HyperswitchAiInteraction, errors::StorageError>;
+
+    async fn list_hyperswitch_ai_interactions(
+        &self,
+        merchant_id: Option<common_utils::id_type::MerchantId>,
+        limit: i64,
+        offset: i64,
+    ) -> CustomResult<Vec<storage::HyperswitchAiInteraction>, errors::StorageError>;
+}
+
+#[async_trait::async_trait]
+impl HyperswitchAiInteractionInterface for Store {
+    #[instrument(skip_all)]
+    async fn insert_hyperswitch_ai_interaction(
+        &self,
+        hyperswitch_ai_interaction: storage::HyperswitchAiInteractionNew,
+    ) -> CustomResult<storage::HyperswitchAiInteraction, errors::StorageError> {
+        let conn = connection::pg_connection_write(self).await?;
+        hyperswitch_ai_interaction
+            .insert(&conn)
+            .await
+            .map_err(|error| report!(errors::StorageError::from(error)))
+    }
+
+    #[instrument(skip_all)]
+    async fn list_hyperswitch_ai_interactions(
+        &self,
+        merchant_id: Option<common_utils::id_type::MerchantId>,
+        limit: i64,
+        offset: i64,
+    ) -> CustomResult<Vec<storage::HyperswitchAiInteraction>, errors::StorageError> {
+        let conn = connection::pg_connection_read(self).await?;
+        storage::HyperswitchAiInteraction::filter_by_optional_merchant_id(
+            &conn,
+            merchant_id.as_ref(),
+            limit,
+            offset,
+        )
+        .await
+        .map_err(|error| report!(errors::StorageError::from(error)))
+    }
+}
+
+#[async_trait::async_trait]
+impl HyperswitchAiInteractionInterface for MockDb {
+    async fn insert_hyperswitch_ai_interaction(
+        &self,
+        hyperswitch_ai_interaction: storage::HyperswitchAiInteractionNew,
+    ) -> CustomResult<storage::HyperswitchAiInteraction, errors::StorageError> {
+        let mut hyperswitch_ai_interactions = self.hyperswitch_ai_interactions.lock().await;
+        let hyperswitch_ai_interaction = storage::HyperswitchAiInteraction {
+            id: hyperswitch_ai_interaction.id,
+            session_id: hyperswitch_ai_interaction.session_id,
+            user_id: hyperswitch_ai_interaction.user_id,
+            merchant_id: hyperswitch_ai_interaction.merchant_id,
+            profile_id: hyperswitch_ai_interaction.profile_id,
+            org_id: hyperswitch_ai_interaction.org_id,
+            role_id: hyperswitch_ai_interaction.role_id,
+            user_query: hyperswitch_ai_interaction.user_query,
+            response: hyperswitch_ai_interaction.response,
+            database_query: hyperswitch_ai_interaction.database_query,
+            interaction_status: hyperswitch_ai_interaction.interaction_status,
+            created_at: hyperswitch_ai_interaction.created_at,
+        };
+        hyperswitch_ai_interactions.push(hyperswitch_ai_interaction.clone());
+        Ok(hyperswitch_ai_interaction)
+    }
+
+    async fn list_hyperswitch_ai_interactions(
+        &self,
+        merchant_id: Option<common_utils::id_type::MerchantId>,
+        limit: i64,
+        offset: i64,
+    ) -> CustomResult<Vec<storage::HyperswitchAiInteraction>, errors::StorageError> {
+        let hyperswitch_ai_interactions = self.hyperswitch_ai_interactions.lock().await;
+
+        let offset_usize = offset.try_into().unwrap_or_else(|_| {
+            common_utils::consts::DEFAULT_LIST_OFFSET
+                .try_into()
+                .unwrap_or(usize::MIN)
+        });
+
+        let limit_usize = limit.try_into().unwrap_or_else(|_| {
+            common_utils::consts::DEFAULT_LIST_LIMIT
+                .try_into()
+                .unwrap_or(usize::MAX)
+        });
+
+        let filtered_interactions: Vec<storage::HyperswitchAiInteraction> =
+            hyperswitch_ai_interactions
+                .iter()
+                .filter(
+                    |interaction| match (merchant_id.as_ref(), &interaction.merchant_id) {
+                        (Some(merchant_id), Some(interaction_merchant_id)) => {
+                            interaction_merchant_id == &merchant_id.get_string_repr().to_owned()
+                        }
+                        (None, _) => true,
+                        _ => false,
+                    },
+                )
+                .skip(offset_usize)
+                .take(limit_usize)
+                .cloned()
+                .collect();
+        Ok(filtered_interactions)
+    }
+}
diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs
index 9eaef17b9c5..68ef8d19619 100644
--- a/crates/router/src/db/kafka_store.rs
+++ b/crates/router/src/db/kafka_store.rs
@@ -43,6 +43,7 @@ use time::PrimitiveDateTime;
 use super::{
     dashboard_metadata::DashboardMetadataInterface,
     ephemeral_key::ClientSecretInterface,
+    hyperswitch_ai_interaction::HyperswitchAiInteractionInterface,
     role::RoleInterface,
     user::{sample_data::BatchSampleDataInterface, theme::ThemeInterface, UserInterface},
     user_authentication_method::UserAuthenticationMethodInterface,
@@ -4127,6 +4128,29 @@ impl UserAuthenticationMethodInterface for KafkaStore {
     }
 }
 
+#[async_trait::async_trait]
+impl HyperswitchAiInteractionInterface for KafkaStore {
+    async fn insert_hyperswitch_ai_interaction(
+        &self,
+        hyperswitch_ai_interaction: storage::HyperswitchAiInteractionNew,
+    ) -> CustomResult<storage::HyperswitchAiInteraction, errors::StorageError> {
+        self.diesel_store
+            .insert_hyperswitch_ai_interaction(hyperswitch_ai_interaction)
+            .await
+    }
+
+    async fn list_hyperswitch_ai_interactions(
+        &self,
+        merchant_id: Option<id_type::MerchantId>,
+        limit: i64,
+        offset: i64,
+    ) -> CustomResult<Vec<storage::HyperswitchAiInteraction>, errors::StorageError> {
+        self.diesel_store
+            .list_hyperswitch_ai_interactions(merchant_id, limit, offset)
+            .await
+    }
+}
+
 #[async_trait::async_trait]
 impl ThemeInterface for KafkaStore {
     async fn insert_theme(
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index ef3f8081b9a..f12730d7b63 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -2343,12 +2343,16 @@ pub struct Chat;
 impl Chat {
     pub fn server(state: AppState) -> Scope {
         let mut route = web::scope("/chat").app_data(web::Data::new(state.clone()));
-        if state.conf.chat.enabled {
+        if state.conf.chat.get_inner().enabled {
             route = route.service(
-                web::scope("/ai").service(
-                    web::resource("/data")
-                        .route(web::post().to(chat::get_data_from_hyperswitch_ai_workflow)),
-                ),
+                web::scope("/ai")
+                    .service(
+                        web::resource("/data")
+                            .route(web::post().to(chat::get_data_from_hyperswitch_ai_workflow)),
+                    )
+                    .service(
+                        web::resource("/list").route(web::get().to(chat::get_all_conversations)),
+                    ),
             );
         }
         route
diff --git a/crates/router/src/routes/chat.rs b/crates/router/src/routes/chat.rs
index e3970cc6a4c..f670bb8e166 100644
--- a/crates/router/src/routes/chat.rs
+++ b/crates/router/src/routes/chat.rs
@@ -45,3 +45,24 @@ pub async fn get_data_from_hyperswitch_ai_workflow(
     ))
     .await
 }
+
+#[instrument(skip_all)]
+pub async fn get_all_conversations(
+    state: web::Data<AppState>,
+    http_req: HttpRequest,
+    payload: web::Query<chat_api::ChatListRequest>,
+) -> HttpResponse {
+    let flow = Flow::ListAllChatInteractions;
+    Box::pin(api::server_wrap(
+        flow.clone(),
+        state,
+        &http_req,
+        payload.into_inner(),
+        |state, user: auth::UserFromToken, payload, _| {
+            chat_core::list_chat_conversations(state, user, payload)
+        },
+        &auth::DashboardNoPermissionAuth,
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index 0c42909b457..c3efb561b42 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -315,7 +315,7 @@ impl From<Flow> for ApiIdentifier {
             | Flow::ListAllThemesInLineage
             | Flow::CloneConnector => Self::User,
 
-            Flow::GetDataFromHyperswitchAiFlow => Self::AiWorkflow,
+            Flow::GetDataFromHyperswitchAiFlow | Flow::ListAllChatInteractions => Self::AiWorkflow,
 
             Flow::ListRolesV2
             | Flow::ListInvitableRolesAtEntityLevel
diff --git a/crates/router/src/types/storage.rs b/crates/router/src/types/storage.rs
index 5d4c4a8bb29..e9c26dd30c2 100644
--- a/crates/router/src/types/storage.rs
+++ b/crates/router/src/types/storage.rs
@@ -21,6 +21,7 @@ pub mod file;
 pub mod fraud_check;
 pub mod generic_link;
 pub mod gsm;
+pub mod hyperswitch_ai_interaction;
 #[cfg(feature = "kv_store")]
 pub mod kv;
 pub mod locker_mock_up;
@@ -75,8 +76,9 @@ pub use self::{
     blocklist_fingerprint::*, blocklist_lookup::*, business_profile::*, callback_mapper::*,
     capture::*, cards_info::*, configs::*, customers::*, dashboard_metadata::*, dispute::*,
     dynamic_routing_stats::*, ephemeral_key::*, events::*, file::*, fraud_check::*,
-    generic_link::*, gsm::*, locker_mock_up::*, mandate::*, merchant_account::*,
-    merchant_connector_account::*, merchant_key_store::*, payment_link::*, payment_method::*,
-    process_tracker::*, refund::*, reverse_lookup::*, role::*, routing_algorithm::*,
-    subscription::*, unified_translations::*, user::*, user_authentication_method::*, user_role::*,
+    generic_link::*, gsm::*, hyperswitch_ai_interaction::*, locker_mock_up::*, mandate::*,
+    merchant_account::*, merchant_connector_account::*, merchant_key_store::*, payment_link::*,
+    payment_method::*, process_tracker::*, refund::*, reverse_lookup::*, role::*,
+    routing_algorithm::*, subscription::*, unified_translations::*, user::*,
+    user_authentication_method::*, user_role::*,
 };
diff --git a/crates/router/src/types/storage/hyperswitch_ai_interaction.rs b/crates/router/src/types/storage/hyperswitch_ai_interaction.rs
new file mode 100644
index 00000000000..30ba3efb49d
--- /dev/null
+++ b/crates/router/src/types/storage/hyperswitch_ai_interaction.rs
@@ -0,0 +1 @@
+pub use diesel_models::hyperswitch_ai_interaction::*;
diff --git a/crates/router/src/utils.rs b/crates/router/src/utils.rs
index e2acbc4db23..71f1ed404b2 100644
--- a/crates/router/src/utils.rs
+++ b/crates/router/src/utils.rs
@@ -1,3 +1,4 @@
+pub mod chat;
 #[cfg(feature = "olap")]
 pub mod connector_onboarding;
 pub mod currency;
diff --git a/crates/router/src/utils/chat.rs b/crates/router/src/utils/chat.rs
new file mode 100644
index 00000000000..c32b6190a95
--- /dev/null
+++ b/crates/router/src/utils/chat.rs
@@ -0,0 +1,70 @@
+use api_models::chat as chat_api;
+use common_utils::{type_name, types::keymanager::Identifier};
+use diesel_models::hyperswitch_ai_interaction::{
+    HyperswitchAiInteraction, HyperswitchAiInteractionNew,
+};
+use error_stack::ResultExt;
+use hyperswitch_domain_models::type_encryption::{crypto_operation, CryptoOperation};
+use masking::ExposeInterface;
+
+use crate::{
+    core::errors::{self, CustomResult},
+    routes::SessionState,
+    services::authentication as auth,
+};
+
+pub async fn construct_hyperswitch_ai_interaction(
+    state: &SessionState,
+    user_from_token: &auth::UserFromToken,
+    req: &chat_api::ChatRequest,
+    response: &chat_api::ChatResponse,
+    request_id: &str,
+) -> CustomResult<HyperswitchAiInteractionNew, errors::ApiErrorResponse> {
+    let encryption_key = state.conf.chat.get_inner().encryption_key.clone().expose();
+    let key = match hex::decode(&encryption_key) {
+        Ok(key) => key,
+        Err(e) => {
+            router_env::logger::error!("Failed to decode encryption key: {}", e);
+            // Fallback to using the string as bytes, which was the previous behavior
+            encryption_key.as_bytes().to_vec()
+        }
+    };
+    let encrypted_user_query = crypto_operation::<String, masking::WithType>(
+        &state.into(),
+        type_name!(HyperswitchAiInteraction),
+        CryptoOperation::Encrypt(req.message.clone()),
+        Identifier::Merchant(user_from_token.merchant_id.clone()),
+        &key,
+    )
+    .await
+    .and_then(|val| val.try_into_operation())
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to encrypt user query")?;
+
+    let encrypted_response = crypto_operation::<serde_json::Value, masking::WithType>(
+        &state.into(),
+        type_name!(HyperswitchAiInteraction),
+        CryptoOperation::Encrypt(response.response.clone()),
+        Identifier::Merchant(user_from_token.merchant_id.clone()),
+        &key,
+    )
+    .await
+    .and_then(|val| val.try_into_operation())
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to encrypt response")?;
+
+    Ok(HyperswitchAiInteractionNew {
+        id: request_id.to_owned(),
+        session_id: Some(request_id.to_string()),
+        user_id: Some(user_from_token.user_id.clone()),
+        merchant_id: Some(user_from_token.merchant_id.get_string_repr().to_string()),
+        profile_id: Some(user_from_token.profile_id.get_string_repr().to_string()),
+        org_id: Some(user_from_token.org_id.get_string_repr().to_string()),
+        role_id: Some(user_from_token.role_id.clone()),
+        user_query: Some(encrypted_user_query.into()),
+        response: Some(encrypted_response.into()),
+        database_query: response.query_executed.clone().map(|q| q.expose()),
+        interaction_status: Some(response.status.clone()),
+        created_at: common_utils::date_time::now(),
+    })
+}
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index ae5f34fd78f..2345469a4e1 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -357,6 +357,8 @@ pub enum Flow {
     GsmRuleDelete,
     /// Get data from embedded flow
     GetDataFromHyperswitchAiFlow,
+    // List all chat interactions
+    ListAllChatInteractions,
     /// User Sign Up
     UserSignUp,
     /// User Sign Up
diff --git a/crates/storage_impl/src/mock_db.rs b/crates/storage_impl/src/mock_db.rs
index 884d9747943..b3fc53fb8cf 100644
--- a/crates/storage_impl/src/mock_db.rs
+++ b/crates/storage_impl/src/mock_db.rs
@@ -65,6 +65,8 @@ pub struct MockDb {
     pub user_authentication_methods:
         Arc<Mutex<Vec<store::user_authentication_method::UserAuthenticationMethod>>>,
     pub themes: Arc<Mutex<Vec<store::user::theme::Theme>>>,
+    pub hyperswitch_ai_interactions:
+        Arc<Mutex<Vec<store::hyperswitch_ai_interaction::HyperswitchAiInteraction>>>,
 }
 
 impl MockDb {
@@ -113,6 +115,7 @@ impl MockDb {
             user_key_store: Default::default(),
             user_authentication_methods: Default::default(),
             themes: Default::default(),
+            hyperswitch_ai_interactions: Default::default(),
         })
     }
 
diff --git a/loadtest/config/development.toml b/loadtest/config/development.toml
index 7508208069d..d85f5251c39 100644
--- a/loadtest/config/development.toml
+++ b/loadtest/config/development.toml
@@ -829,8 +829,7 @@ billing_connectors_which_requires_invoice_sync_call = "recurly"
 [chat]
 enabled = false
 hyperswitch_ai_host = "http://0.0.0.0:8000"
-
-
+encryption_key = ""
 
 [revenue_recovery.card_config.amex]
 max_retries_per_day = 20
@@ -846,4 +845,4 @@ max_retry_count_for_thirty_day = 20
 
 [revenue_recovery.card_config.discover]
 max_retries_per_day = 20
-max_retry_count_for_thirty_day = 20
\ No newline at end of file
+max_retry_count_for_thirty_day = 20
diff --git a/migrations/2025-07-21-120614_add_table_for_hyperswitch_ai_interactions/down.sql b/migrations/2025-07-21-120614_add_table_for_hyperswitch_ai_interactions/down.sql
new file mode 100644
index 00000000000..8cd51507c46
--- /dev/null
+++ b/migrations/2025-07-21-120614_add_table_for_hyperswitch_ai_interactions/down.sql
@@ -0,0 +1,3 @@
+-- This file should undo anything in `up.sql`
+-- CASCADE will automatically drop all child partitions
+DROP TABLE IF EXISTS hyperswitch_ai_interaction CASCADE;
diff --git a/migrations/2025-07-21-120614_add_table_for_hyperswitch_ai_interactions/up.sql b/migrations/2025-07-21-120614_add_table_for_hyperswitch_ai_interactions/up.sql
new file mode 100644
index 00000000000..e67da66d139
--- /dev/null
+++ b/migrations/2025-07-21-120614_add_table_for_hyperswitch_ai_interactions/up.sql
@@ -0,0 +1,21 @@
+-- Your SQL goes here
+CREATE TABLE hyperswitch_ai_interaction (
+    id VARCHAR(64) NOT NULL,
+    session_id VARCHAR(64),
+    user_id VARCHAR(64),
+    merchant_id VARCHAR(64),
+    profile_id VARCHAR(64),
+    org_id VARCHAR(64),
+    role_id VARCHAR(64),
+    user_query BYTEA,
+    response BYTEA,
+    database_query TEXT,
+    interaction_status VARCHAR(64),
+    created_at TIMESTAMP NOT NULL,
+    PRIMARY KEY (id, created_at)
+) PARTITION BY RANGE (created_at);
+
+-- Create a default partition
+CREATE TABLE hyperswitch_ai_interaction_default
+    PARTITION OF hyperswitch_ai_interaction DEFAULT;
+