Bug: [FEATURE] Tokenization service



### Feature Description

Need of generic tokenization service is required which can be used to tokenize any data which could be used by the consumer in various other services, one of the usecases is proxy payments

### Possible Implementation

Use the locker to store the tokenized data and give out reference to that data to user through which it can be used in any place.

### Have you spent some time checking if this feature request has been raised before?

- [x] I checked and didn't find a similar issue

### Have you read the Contributing Guidelines?

- [x] I have read the [Contributing Guidelines](https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md)

### Are you willing to submit a PR?

None
diff --git a/api-reference-v2/api-reference/tokenization/tokenization--create.mdx b/api-reference-v2/api-reference/tokenization/tokenization--create.mdx
new file mode 100644
index 00000000000..a0002736185
--- /dev/null
+++ b/api-reference-v2/api-reference/tokenization/tokenization--create.mdx
@@ -0,0 +1,3 @@
+---
+openapi: post /v2/tokenize
+---
\ No newline at end of file
diff --git a/api-reference-v2/mint.json b/api-reference-v2/mint.json
index e56b9d684ec..8c49d3dd708 100644
--- a/api-reference-v2/mint.json
+++ b/api-reference-v2/mint.json
@@ -146,6 +146,10 @@
     {
       "group": "Proxy",
       "pages": ["api-reference/proxy/proxy"]
+    },
+    {
+      "group": "Tokenization",
+      "pages": ["api-reference/tokenization/tokenization--create"]
     }
   ],
   "footerSocials": {
diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json
index 00e3e7bc4ff..2347c6f9f49 100644
--- a/api-reference-v2/openapi_spec.json
+++ b/api-reference-v2/openapi_spec.json
@@ -3532,6 +3532,67 @@
           }
         ]
       }
+    },
+    "/v2/tokenize": {
+      "post": {
+        "tags": [
+          "Tokenization"
+        ],
+        "operationId": "create_token_vault_api",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/GenericTokenizationRequest"
+              },
+              "examples": {
+                "Create a token with customer_id": {
+                  "value": {
+                    "customer_id": "12345_cus_0196d94b9c207333a297cbcf31f2e8c8",
+                    "token_request": {
+                      "payment_method_data": {
+                        "card": {
+                          "card_holder_name": "test name"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "description": "Token created successfully",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GenericTokenizationResponse"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "Invalid request"
+          },
+          "401": {
+            "description": "Unauthorized"
+          },
+          "500": {
+            "description": "Internal server error"
+          }
+        },
+        "security": [
+          {
+            "ephemeral_key": []
+          },
+          {
+            "api_key": []
+          }
+        ]
+      }
     }
   },
   "components": {
@@ -11032,6 +11093,50 @@
           }
         }
       },
+      "GenericTokenizationRequest": {
+        "type": "object",
+        "required": [
+          "customer_id",
+          "token_request"
+        ],
+        "properties": {
+          "customer_id": {
+            "type": "string",
+            "description": "Customer ID for which the tokenization is requested",
+            "example": "12345_cus_01926c58bc6e77c09e809964e72af8c8"
+          },
+          "token_request": {
+            "type": "object",
+            "description": "Request for tokenization which contains the data to be tokenized"
+          }
+        }
+      },
+      "GenericTokenizationResponse": {
+        "type": "object",
+        "required": [
+          "id",
+          "created_at",
+          "flag"
+        ],
+        "properties": {
+          "id": {
+            "type": "string",
+            "description": "Unique identifier returned by the tokenization service",
+            "example": "12345_tok_01926c58bc6e77c09e809964e72af8c8"
+          },
+          "created_at": {
+            "type": "string",
+            "format": "date-time",
+            "description": "Created time of the tokenization id",
+            "example": "2024-02-24T11:04:09.922Z"
+          },
+          "flag": {
+            "type": "string",
+            "description": "Status of the tokenization id created",
+            "example": "enabled"
+          }
+        }
+      },
       "GiftCardAdditionalData": {
         "oneOf": [
           {
@@ -16595,6 +16700,10 @@
             "example": 900,
             "nullable": true,
             "minimum": 0
+          },
+          "tokenization_data": {
+            "description": "Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data",
+            "nullable": true
           }
         }
       },
@@ -16640,6 +16749,10 @@
             ],
             "nullable": true
           },
+          "tokenization_data": {
+            "description": "Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data",
+            "nullable": true
+          },
           "expires_at": {
             "type": "string",
             "format": "date-time",
@@ -16678,6 +16791,12 @@
             },
             "description": "The payment method that was created using this payment method session",
             "nullable": true
+          },
+          "associated_token_id": {
+            "type": "string",
+            "description": "The token-id created if there is tokenization_data present",
+            "example": "12345_tok_01926c58bc6e77c09e809964e72af8c8",
+            "nullable": true
           }
         }
       },
@@ -16941,6 +17060,10 @@
               }
             ],
             "nullable": true
+          },
+          "tokenization_data": {
+            "description": "Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data",
+            "nullable": true
           }
         }
       },
diff --git a/config/development.toml b/config/development.toml
index 7deb3b46992..039bd7c274b 100644
--- a/config/development.toml
+++ b/config/development.toml
@@ -84,28 +84,8 @@ redis_lock_timeout_in_seconds = 100
 redis_ttl_in_seconds = 172800
 
 [jwekey]
-vault_encryption_key = """
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwa6siKaSYqD1o4J3AbHq
-Km8oVTvep7GoN/C45qY60C7DO72H1O7Ujt6ZsSiK83EyI0CaUg3ORPS3ayobFNmu
-zR366ckK8GIf3BG7sVI6u/9751z4OvBHZMM9JFWa7Bx/RCPQ8aeM+iJoqf9auuQm
-3NCTlfaZJif45pShswR+xuZTR/bqnsOSP/MFROI9ch0NE7KRogy0tvrZe21lP24i
-Ro2LJJG+bYshxBddhxQf2ryJ85+/Trxdu16PunodGzCl6EMT3bvb4ZC41i15omqU
-aXXV1Z1wYUhlsO0jyd1bVvjyuE/KE1TbBS0gfR/RkacODmmE2zEdZ0EyyiXwqkmc
-oQIDAQAB
------END PUBLIC KEY-----
-"""
-rust_locker_encryption_key = """
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwa6siKaSYqD1o4J3AbHq
-Km8oVTvep7GoN/C45qY60C7DO72H1O7Ujt6ZsSiK83EyI0CaUg3ORPS3ayobFNmu
-zR366ckK8GIf3BG7sVI6u/9751z4OvBHZMM9JFWa7Bx/RCPQ8aeM+iJoqf9auuQm
-3NCTlfaZJif45pShswR+xuZTR/bqnsOSP/MFROI9ch0NE7KRogy0tvrZe21lP24i
-Ro2LJJG+bYshxBddhxQf2ryJ85+/Trxdu16PunodGzCl6EMT3bvb4ZC41i15omqU
-aXXV1Z1wYUhlsO0jyd1bVvjyuE/KE1TbBS0gfR/RkacODmmE2zEdZ0EyyiXwqkmc
-oQIDAQAB
------END PUBLIC KEY-----
-"""
+vault_encryption_key = ""
+rust_locker_encryption_key = ""
 vault_private_key = ""
 tunnel_private_key = ""
 
diff --git a/crates/api_models/Cargo.toml b/crates/api_models/Cargo.toml
index 120e9121388..32a798c3c0b 100644
--- a/crates/api_models/Cargo.toml
+++ b/crates/api_models/Cargo.toml
@@ -17,13 +17,14 @@ olap = []
 openapi = ["common_enums/openapi", "olap", "recon", "dummy_connector", "olap"]
 recon = []
 v1 = ["common_utils/v1"]
-v2 = ["common_types/v2", "common_utils/v2", "customer_v2", "refunds_v2"]
+v2 = ["common_types/v2", "common_utils/v2", "customer_v2", "refunds_v2", "tokenization_v2"]
 customer_v2 = ["common_utils/customer_v2"]
 payment_methods_v2 = ["common_utils/payment_methods_v2", "dep:reqwest"]
 refunds_v2 = []
 dynamic_routing = []
 control_center_theme = ["dep:actix-web", "dep:actix-multipart"]
 revenue_recovery = []
+tokenization_v2 = ["common_utils/tokenization_v2"]
 
 [dependencies]
 actix-multipart = { version = "0.6.1", optional = true }
diff --git a/crates/api_models/src/events.rs b/crates/api_models/src/events.rs
index 973bdea9eef..e0e57050c4e 100644
--- a/crates/api_models/src/events.rs
+++ b/crates/api_models/src/events.rs
@@ -22,6 +22,8 @@ use common_utils::{
 };
 
 use crate::customers::CustomerListRequest;
+#[cfg(feature = "tokenization_v2")]
+use crate::tokenization;
 #[allow(unused_imports)]
 use crate::{
     admin::*,
@@ -228,3 +230,8 @@ impl ApiEventMetric for PaymentMethodSessionResponse {
         })
     }
 }
+#[cfg(feature = "tokenization_v2")]
+impl ApiEventMetric for tokenization::GenericTokenizationRequest {}
+
+#[cfg(feature = "tokenization_v2")]
+impl ApiEventMetric for tokenization::GenericTokenizationResponse {}
diff --git a/crates/api_models/src/lib.rs b/crates/api_models/src/lib.rs
index fa3c34db930..a77baf7d942 100644
--- a/crates/api_models/src/lib.rs
+++ b/crates/api_models/src/lib.rs
@@ -40,6 +40,8 @@ pub mod refunds;
 pub mod relay;
 pub mod routing;
 pub mod surcharge_decision_configs;
+#[cfg(feature = "tokenization_v2")]
+pub mod tokenization;
 pub mod user;
 pub mod user_role;
 pub mod verifications;
diff --git a/crates/api_models/src/payment_methods.rs b/crates/api_models/src/payment_methods.rs
index 6e9a174c9f6..92761192d1c 100644
--- a/crates/api_models/src/payment_methods.rs
+++ b/crates/api_models/src/payment_methods.rs
@@ -2861,6 +2861,10 @@ pub struct PaymentMethodSessionRequest {
     /// If not provided, the session will expire in 15 minutes
     #[schema(example = 900, default = 900)]
     pub expires_in: Option<u32>,
+
+    /// Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data
+    #[schema(value_type = Option<serde_json::Value>)]
+    pub tokenization_data: Option<pii::SecretSerdeValue>,
 }
 
 #[cfg(feature = "v2")]
@@ -2877,6 +2881,10 @@ pub struct PaymentMethodsSessionUpdateRequest {
     /// The network tokenization configuration if applicable
     #[schema(value_type = Option<NetworkTokenization>)]
     pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+
+    /// Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data
+    #[schema(value_type = Option<serde_json::Value>)]
+    pub tokenization_data: Option<pii::SecretSerdeValue>,
 }
 
 #[cfg(feature = "v2")]
@@ -2941,6 +2949,10 @@ pub struct PaymentMethodSessionResponse {
     #[schema(value_type = Option<NetworkTokenization>)]
     pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
 
+    /// Contains data to be passed on to tokenization service ( if present ) to create token_id for given JSON data
+    #[schema(value_type = Option<serde_json::Value>)]
+    pub tokenization_data: Option<pii::SecretSerdeValue>,
+
     /// The iso timestamp when the session will expire
     /// Trying to retrieve the session or any operations on the session after this time will result in an error
     #[schema(value_type = PrimitiveDateTime, example = "2023-01-18T11:04:09.922Z")]
@@ -2966,6 +2978,10 @@ pub struct PaymentMethodSessionResponse {
     /// The payment method that was created using this payment method session
     #[schema(value_type = Option<Vec<String>>)]
     pub associated_payment_methods: Option<Vec<id_type::GlobalPaymentMethodId>>,
+
+    /// The token-id created if there is tokenization_data present
+    #[schema(value_type = Option<String>, example = "12345_tok_01926c58bc6e77c09e809964e72af8c8")]
+    pub associated_token_id: Option<id_type::GlobalTokenId>,
 }
 
 #[cfg(feature = "v2")]
diff --git a/crates/api_models/src/tokenization.rs b/crates/api_models/src/tokenization.rs
new file mode 100644
index 00000000000..5ee044ec1fb
--- /dev/null
+++ b/crates/api_models/src/tokenization.rs
@@ -0,0 +1,30 @@
+use common_enums;
+use common_utils::id_type::{GlobalCustomerId, GlobalTokenId};
+use masking::Secret;
+use serde::{Deserialize, Serialize};
+use time::PrimitiveDateTime;
+use utoipa::{schema, ToSchema};
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Debug, Serialize, Deserialize, ToSchema)]
+pub struct GenericTokenizationResponse {
+    /// Unique identifier returned by the tokenization service
+    #[schema(value_type = String, example = "12345_tok_01926c58bc6e77c09e809964e72af8c8")]
+    pub id: GlobalTokenId,
+    /// Created time of the tokenization id
+    #[schema(value_type = PrimitiveDateTime,example = "2024-02-24T11:04:09.922Z")]
+    pub created_at: PrimitiveDateTime,
+    /// Status of the tokenization id created
+    #[schema(value_type = String,example = "enabled")]
+    pub flag: common_enums::TokenizationFlag,
+}
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Debug, Serialize, Deserialize, ToSchema)]
+pub struct GenericTokenizationRequest {
+    /// Customer ID for which the tokenization is requested
+    #[schema(value_type = String, example = "12345_cus_01926c58bc6e77c09e809964e72af8c8")]
+    pub customer_id: GlobalCustomerId,
+    /// Request for tokenization which contains the data to be tokenized
+    #[schema(value_type = Object,example = json!({ "city": "NY", "unit": "245" }))]
+    pub token_request: masking::Secret<serde_json::Value>,
+}
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index b3ab41b020a..0f0064414ca 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -29,7 +29,7 @@ pub mod diesel_exports {
         DbRequestIncrementalAuthorization as RequestIncrementalAuthorization,
         DbScaExemptionType as ScaExemptionType,
         DbSuccessBasedRoutingConclusiveState as SuccessBasedRoutingConclusiveState,
-        DbWebhookDeliveryAttempt as WebhookDeliveryAttempt,
+        DbTokenizationFlag as TokenizationFlag, DbWebhookDeliveryAttempt as WebhookDeliveryAttempt,
     };
 }
 
@@ -8299,6 +8299,28 @@ pub enum CryptoPadding {
     ZeroPadding,
 }
 
+#[derive(
+    Clone,
+    Copy,
+    Debug,
+    Eq,
+    PartialEq,
+    serde::Deserialize,
+    serde::Serialize,
+    strum::Display,
+    strum::EnumString,
+    ToSchema,
+)]
+#[router_derive::diesel_enum(storage_type = "db_enum")]
+#[serde(rename_all = "snake_case")]
+#[strum(serialize_all = "snake_case")]
+pub enum TokenizationFlag {
+    /// Token is active and can be used for payments
+    Enabled,
+    /// Token is inactive and cannot be used for payments
+    Disabled,
+}
+
 /// The type of token data to fetch for get-token endpoint
 
 #[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
diff --git a/crates/common_types/Cargo.toml b/crates/common_types/Cargo.toml
index 3f49f546a71..97695cb87d3 100644
--- a/crates/common_types/Cargo.toml
+++ b/crates/common_types/Cargo.toml
@@ -10,6 +10,7 @@ license.workspace = true
 default = []
 v1 = ["common_utils/v1"]
 v2 = ["common_utils/v2"]
+tokenization_v2 = ["common_utils/tokenization_v2"]
 
 [dependencies]
 diesel = "2.2.3"
diff --git a/crates/common_utils/Cargo.toml b/crates/common_utils/Cargo.toml
index 4f4322c3ca3..43f28817c7e 100644
--- a/crates/common_utils/Cargo.toml
+++ b/crates/common_utils/Cargo.toml
@@ -23,6 +23,7 @@ v2 = []
 customer_v2 = []
 payment_methods_v2 = []
 crypto_openssl = ["dep:openssl"]
+tokenization_v2 = []
 
 [dependencies]
 async-trait = { version = "0.1.79", optional = true }
diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs
index e3eba81b12f..bdbaa1eae6c 100644
--- a/crates/common_utils/src/consts.rs
+++ b/crates/common_utils/src/consts.rs
@@ -179,6 +179,10 @@ pub const DEFAULT_CARD_TESTING_GUARD_EXPIRY_IN_SECS: i32 = 3600;
 /// SOAP 1.1 Envelope Namespace
 pub const SOAP_ENV_NAMESPACE: &str = "http://schemas.xmlsoap.org/soap/envelope/";
 
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+/// Length of generated tokens
+pub const TOKEN_LENGTH: usize = 32;
+
 /// The tag name used for identifying the host in metrics.
 pub const METRICS_HOST_TAG_NAME: &str = "host";
 
diff --git a/crates/common_utils/src/events.rs b/crates/common_utils/src/events.rs
index f7a068b8e49..5ba16ee2c42 100644
--- a/crates/common_utils/src/events.rs
+++ b/crates/common_utils/src/events.rs
@@ -121,6 +121,10 @@ pub enum ApiEventsType {
     PaymentMethodSession {
         payment_method_session_id: id_type::GlobalPaymentMethodSessionId,
     },
+    #[cfg(feature = "v2")]
+    Token {
+        token_id: Option<id_type::GlobalTokenId>,
+    },
     ProcessTracker,
 }
 
diff --git a/crates/common_utils/src/id_type.rs b/crates/common_utils/src/id_type.rs
index 30b6a3888da..34a3844e76b 100644
--- a/crates/common_utils/src/id_type.rs
+++ b/crates/common_utils/src/id_type.rs
@@ -34,6 +34,7 @@ pub use self::global_id::{
     payment::{GlobalAttemptId, GlobalPaymentId},
     payment_methods::{GlobalPaymentMethodId, GlobalPaymentMethodSessionId},
     refunds::GlobalRefundId,
+    token::GlobalTokenId,
     CellId,
 };
 pub use self::{
diff --git a/crates/common_utils/src/id_type/global_id.rs b/crates/common_utils/src/id_type/global_id.rs
index bb296d7ef1a..b9ed173ce3e 100644
--- a/crates/common_utils/src/id_type/global_id.rs
+++ b/crates/common_utils/src/id_type/global_id.rs
@@ -2,6 +2,7 @@ pub(super) mod customer;
 pub(super) mod payment;
 pub(super) mod payment_methods;
 pub(super) mod refunds;
+pub(super) mod token;
 
 use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types};
 use error_stack::ResultExt;
@@ -27,6 +28,7 @@ pub(crate) enum GlobalEntity {
     PaymentMethod,
     Refund,
     PaymentMethodSession,
+    Token,
 }
 
 impl GlobalEntity {
@@ -38,6 +40,7 @@ impl GlobalEntity {
             Self::Attempt => "att",
             Self::Refund => "ref",
             Self::PaymentMethodSession => "pms",
+            Self::Token => "tok",
         }
     }
 }
diff --git a/crates/common_utils/src/id_type/global_id/token.rs b/crates/common_utils/src/id_type/global_id/token.rs
new file mode 100644
index 00000000000..929c03f0959
--- /dev/null
+++ b/crates/common_utils/src/id_type/global_id/token.rs
@@ -0,0 +1,37 @@
+use error_stack::ResultExt;
+
+use crate::{errors, generate_id_with_default_len, generate_time_ordered_id_without_prefix, types};
+
+crate::global_id_type!(
+    GlobalTokenId,
+    "A global id that can be used to identify a token.
+
+The format will be `<cell_id>_<entity_prefix>_<time_ordered_id>`.
+
+Example: `cell1_tok_uu1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p`"
+);
+
+// Database related implementations so that this field can be used directly in the database tables
+crate::impl_queryable_id_type!(GlobalTokenId);
+crate::impl_to_sql_from_sql_global_id_type!(GlobalTokenId);
+
+impl GlobalTokenId {
+    /// Get string representation of the id
+    pub fn get_string_repr(&self) -> &str {
+        self.0.get_string_repr()
+    }
+
+    /// Generate a new GlobalTokenId from a cell id
+    pub fn generate(cell_id: &crate::id_type::CellId) -> Self {
+        let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Token);
+        Self(global_id)
+    }
+}
+
+impl crate::events::ApiEventMetric for GlobalTokenId {
+    fn get_api_event_type(&self) -> Option<crate::events::ApiEventsType> {
+        Some(crate::events::ApiEventsType::Token {
+            token_id: Some(self.clone()),
+        })
+    }
+}
diff --git a/crates/common_utils/src/lib.rs b/crates/common_utils/src/lib.rs
index fd0c935035f..759329ba327 100644
--- a/crates/common_utils/src/lib.rs
+++ b/crates/common_utils/src/lib.rs
@@ -333,3 +333,10 @@ mod nanoid_tests {
         assert!(ref_id.is_ok())
     }
 }
+
+/// Module for tokenization-related functionality
+///
+/// This module provides types and functions for handling tokenized payment data,
+/// including response structures and token generation utilities.
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub mod tokenization;
diff --git a/crates/common_utils/src/tokenization.rs b/crates/common_utils/src/tokenization.rs
new file mode 100644
index 00000000000..aa0f3dda8c1
--- /dev/null
+++ b/crates/common_utils/src/tokenization.rs
@@ -0,0 +1,21 @@
+//! Module for tokenization-related functionality
+//!
+//! This module provides types and functions for handling tokenized payment data,
+//! including response structures and token generation utilities.
+
+use common_enums::ApiVersion;
+use diesel;
+use serde::{Deserialize, Serialize};
+use time::PrimitiveDateTime;
+
+use crate::{consts::TOKEN_LENGTH, id_type::GlobalTokenId};
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+/// Generates a new token string
+///
+/// # Returns
+/// A randomly generated token string of length `TOKEN_LENGTH`
+pub fn generate_token() -> String {
+    use nanoid::nanoid;
+    nanoid!(TOKEN_LENGTH)
+}
diff --git a/crates/diesel_models/Cargo.toml b/crates/diesel_models/Cargo.toml
index e10428c5daf..8f7c5f92908 100644
--- a/crates/diesel_models/Cargo.toml
+++ b/crates/diesel_models/Cargo.toml
@@ -15,6 +15,7 @@ v2 = ["common_utils/v2", "common_types/v2"]
 customer_v2 = []
 payment_methods_v2 = []
 refunds_v2 = []
+tokenization_v2 = []
 
 [dependencies]
 async-bb8-diesel = "0.2.1"
diff --git a/crates/diesel_models/src/enums.rs b/crates/diesel_models/src/enums.rs
index bd710dfdd6b..39ce33a5130 100644
--- a/crates/diesel_models/src/enums.rs
+++ b/crates/diesel_models/src/enums.rs
@@ -23,13 +23,16 @@ pub mod diesel_exports {
         DbRevenueRecoveryAlgorithmType as RevenueRecoveryAlgorithmType, DbRoleScope as RoleScope,
         DbRoutingAlgorithmKind as RoutingAlgorithmKind, DbScaExemptionType as ScaExemptionType,
         DbSuccessBasedRoutingConclusiveState as SuccessBasedRoutingConclusiveState,
-        DbTotpStatus as TotpStatus, DbTransactionType as TransactionType,
-        DbUserRoleVersion as UserRoleVersion, DbUserStatus as UserStatus,
-        DbWebhookDeliveryAttempt as WebhookDeliveryAttempt,
+        DbTokenizationFlag as TokenizationFlag, DbTotpStatus as TotpStatus,
+        DbTransactionType as TransactionType, DbUserRoleVersion as UserRoleVersion,
+        DbUserStatus as UserStatus, DbWebhookDeliveryAttempt as WebhookDeliveryAttempt,
     };
 }
+
 pub use common_enums::*;
 use common_utils::pii;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub use common_utils::tokenization;
 use diesel::{deserialize::FromSqlRow, expression::AsExpression, sql_types::Jsonb};
 use router_derive::diesel_enum;
 use time::PrimitiveDateTime;
diff --git a/crates/diesel_models/src/lib.rs b/crates/diesel_models/src/lib.rs
index e5c7aea9d56..e34e7e552d8 100644
--- a/crates/diesel_models/src/lib.rs
+++ b/crates/diesel_models/src/lib.rs
@@ -140,3 +140,6 @@ pub(crate) mod metrics {
     counter_metric!(DATABASE_CALLS_COUNT, GLOBAL_METER);
     histogram_metric_f64!(DATABASE_CALL_TIME, GLOBAL_METER);
 }
+
+#[cfg(feature = "tokenization_v2")]
+pub mod tokenization;
diff --git a/crates/diesel_models/src/mod.rs b/crates/diesel_models/src/mod.rs
new file mode 100644
index 00000000000..3cdc13b0c8a
--- /dev/null
+++ b/crates/diesel_models/src/mod.rs
@@ -0,0 +1,2 @@
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub mod tokenization; 
\ No newline at end of file
diff --git a/crates/diesel_models/src/payment_methods_session.rs b/crates/diesel_models/src/payment_methods_session.rs
index 250fd44bdbf..037214387a7 100644
--- a/crates/diesel_models/src/payment_methods_session.rs
+++ b/crates/diesel_models/src/payment_methods_session.rs
@@ -1,3 +1,5 @@
+use common_utils::pii;
+
 #[cfg(feature = "v2")]
 #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
 pub struct PaymentMethodSession {
@@ -6,11 +8,13 @@ pub struct PaymentMethodSession {
     pub billing: Option<common_utils::encryption::Encryption>,
     pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
     pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+    pub tokenization_data: Option<pii::SecretSerdeValue>,
     pub return_url: Option<common_utils::types::Url>,
     #[serde(with = "common_utils::custom_serde::iso8601")]
     pub expires_at: time::PrimitiveDateTime,
     pub associated_payment_methods: Option<Vec<common_utils::id_type::GlobalPaymentMethodId>>,
     pub associated_payment: Option<common_utils::id_type::GlobalPaymentId>,
+    pub associated_token_id: Option<common_utils::id_type::GlobalTokenId>,
 }
 
 #[cfg(feature = "v2")]
@@ -22,10 +26,12 @@ impl PaymentMethodSession {
             billing,
             psp_tokenization,
             network_tokenization,
+            tokenization_data,
             expires_at,
             return_url,
             associated_payment_methods,
             associated_payment,
+            associated_token_id,
         } = self;
 
         Self {
@@ -34,10 +40,12 @@ impl PaymentMethodSession {
             billing: update_session.billing.or(billing),
             psp_tokenization: update_session.psp_tokenization.or(psp_tokenization),
             network_tokenization: update_session.network_tokenization.or(network_tokenization),
+            tokenization_data: update_session.tokenzation_data.or(tokenization_data),
             expires_at,
             return_url,
             associated_payment_methods,
             associated_payment,
+            associated_token_id,
         }
     }
 }
@@ -47,4 +55,5 @@ pub struct PaymentMethodsSessionUpdateInternal {
     pub billing: Option<common_utils::encryption::Encryption>,
     pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
     pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+    pub tokenzation_data: Option<masking::Secret<serde_json::Value>>,
 }
diff --git a/crates/diesel_models/src/query.rs b/crates/diesel_models/src/query.rs
index 9a886c473cd..7c8831b3811 100644
--- a/crates/diesel_models/src/query.rs
+++ b/crates/diesel_models/src/query.rs
@@ -39,6 +39,8 @@ pub mod relay;
 pub mod reverse_lookup;
 pub mod role;
 pub mod routing_algorithm;
+#[cfg(feature = "tokenization_v2")]
+pub mod tokenization;
 pub mod unified_translations;
 pub mod user;
 pub mod user_authentication_method;
diff --git a/crates/diesel_models/src/query/tokenization.rs b/crates/diesel_models/src/query/tokenization.rs
new file mode 100644
index 00000000000..0d818eb6636
--- /dev/null
+++ b/crates/diesel_models/src/query/tokenization.rs
@@ -0,0 +1,46 @@
+#[cfg(feature = "v2")]
+use common_enums;
+#[cfg(feature = "v2")]
+use common_utils::{
+    id_type::{GlobalTokenId, MerchantId},
+    tokenization as tokenization_utils,
+};
+#[cfg(feature = "v2")]
+use diesel::{
+    associations::HasTable,
+    deserialize::FromSqlRow,
+    expression::AsExpression,
+    pg::Pg,
+    serialize::{Output, ToSql},
+    sql_types::{Jsonb, Text},
+    AsChangeset, Identifiable, Insertable, Queryable, Selectable,
+};
+#[cfg(feature = "v2")]
+use serde::{Deserialize, Serialize};
+#[cfg(feature = "v2")]
+use time::PrimitiveDateTime;
+
+#[cfg(feature = "v2")]
+use crate::{
+    query::generics, schema_v2::tokenization, tokenization as tokenization_diesel, PgPooledConn,
+    StorageResult,
+};
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+impl tokenization_diesel::Tokenization {
+    pub async fn insert(self, conn: &PgPooledConn) -> StorageResult<Self> {
+        generics::generic_insert(conn, self).await
+    }
+
+    pub async fn find_by_id(
+        conn: &PgPooledConn,
+        id: &common_utils::id_type::GlobalTokenId,
+    ) -> StorageResult<Self> {
+        use diesel::ExpressionMethods;
+        generics::generic_find_one::<<Self as HasTable>::Table, _, _>(
+            conn,
+            tokenization::dsl::id.eq(id.to_owned()),
+        )
+        .await
+    }
+}
diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs
index 195b0fa4298..b6d8aedfa92 100644
--- a/crates/diesel_models/src/schema_v2.rs
+++ b/crates/diesel_models/src/schema_v2.rs
@@ -1379,6 +1379,26 @@ diesel::table! {
     }
 }
 
+diesel::table! {
+    use diesel::sql_types::*;
+    use crate::enums::diesel_exports::*;
+
+    tokenization (id) {
+        #[max_length = 64]
+        id -> Varchar,
+        #[max_length = 255]
+        merchant_id -> Varchar,
+        #[max_length = 64]
+        customer_id -> Varchar,
+        created_at -> Timestamp,
+        updated_at -> Timestamp,
+        #[max_length = 255]
+        locker_id -> Varchar,
+        flag -> TokenizationFlag,
+        version -> ApiVersion,
+    }
+}
+
 diesel::table! {
     use diesel::sql_types::*;
     use crate::enums::diesel_exports::*;
@@ -1532,6 +1552,7 @@ diesel::allow_tables_to_appear_in_same_query!(
     roles,
     routing_algorithm,
     themes,
+    tokenization,
     unified_translations,
     user_authentication_methods,
     user_key_store,
diff --git a/crates/diesel_models/src/tokenization.rs b/crates/diesel_models/src/tokenization.rs
new file mode 100644
index 00000000000..50a97e62c90
--- /dev/null
+++ b/crates/diesel_models/src/tokenization.rs
@@ -0,0 +1,61 @@
+#[cfg(feature = "v2")]
+use common_enums;
+#[cfg(feature = "v2")]
+use common_utils::{
+    id_type::{GlobalTokenId, MerchantId},
+    tokenization as tokenization_utils,
+};
+#[cfg(feature = "v2")]
+use diesel::{
+    associations::HasTable,
+    deserialize::FromSqlRow,
+    expression::AsExpression,
+    pg::Pg,
+    serialize::{Output, ToSql},
+    sql_types::{Jsonb, Text},
+    AsChangeset, Identifiable, Insertable, Queryable, Selectable,
+};
+#[cfg(feature = "v2")]
+use serde::{Deserialize, Serialize};
+#[cfg(feature = "v2")]
+use time::PrimitiveDateTime;
+
+#[cfg(feature = "v2")]
+use crate::{query::generics, schema_v2::tokenization, PgPooledConn, StorageResult};
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Clone, Debug, Identifiable, Insertable, Queryable)]
+#[diesel(table_name = tokenization)]
+pub struct Tokenization {
+    pub id: common_utils::id_type::GlobalTokenId,
+    pub merchant_id: common_utils::id_type::MerchantId,
+    pub customer_id: common_utils::id_type::GlobalCustomerId,
+    pub created_at: PrimitiveDateTime,
+    pub updated_at: PrimitiveDateTime,
+    pub locker_id: String,
+    pub flag: common_enums::enums::TokenizationFlag,
+    pub version: common_enums::enums::ApiVersion,
+}
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Clone, Debug, Insertable)]
+#[diesel(table_name = tokenization)]
+pub struct TokenizationNew {
+    pub id: common_utils::id_type::GlobalTokenId,
+    pub merchant_id: common_utils::id_type::MerchantId,
+    pub customer_id: common_utils::id_type::GlobalCustomerId,
+    pub locker_id: String,
+    pub created_at: PrimitiveDateTime,
+    pub updated_at: PrimitiveDateTime,
+    pub version: common_enums::enums::ApiVersion,
+    pub flag: common_enums::enums::TokenizationFlag,
+}
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Clone, Debug, AsChangeset)]
+#[diesel(table_name = tokenization)]
+pub struct TokenizationUpdate {
+    pub updated_at: Option<PrimitiveDateTime>,
+    pub version: Option<common_enums::enums::ApiVersion>,
+    pub flag: Option<common_enums::enums::TokenizationFlag>,
+}
diff --git a/crates/diesel_models/src/types.rs b/crates/diesel_models/src/types.rs
index bf463616c6d..696cc22783d 100644
--- a/crates/diesel_models/src/types.rs
+++ b/crates/diesel_models/src/types.rs
@@ -9,6 +9,7 @@ use diesel::{
 };
 use masking::{Secret, WithType};
 use serde::{self, Deserialize, Serialize};
+
 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize, FromSqlRow, AsExpression)]
 #[diesel(sql_type = Jsonb)]
 pub struct OrderDetailsWithAmount {
diff --git a/crates/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml
index e889d2c16c3..a3a2fc8e10c 100644
--- a/crates/hyperswitch_domain_models/Cargo.toml
+++ b/crates/hyperswitch_domain_models/Cargo.toml
@@ -17,6 +17,7 @@ v2 = ["api_models/v2", "diesel_models/v2", "common_utils/v2", "common_types/v2"]
 v1 = ["api_models/v1", "diesel_models/v1", "common_utils/v1", "common_types/v1"]
 customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2"]
 payment_methods_v2 = ["api_models/payment_methods_v2", "diesel_models/payment_methods_v2"]
+tokenization_v2 = ["api_models/tokenization_v2", "diesel_models/tokenization_v2"]
 refunds_v2 = ["api_models/refunds_v2"]
 dummy_connector = []
 revenue_recovery= []
diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs
index 1d24e3eedbc..eb37f8f45da 100644
--- a/crates/hyperswitch_domain_models/src/lib.rs
+++ b/crates/hyperswitch_domain_models/src/lib.rs
@@ -34,6 +34,8 @@ pub mod router_flow_types;
 pub mod router_request_types;
 pub mod router_response_types;
 pub mod routing;
+#[cfg(feature = "tokenization_v2")]
+pub mod tokenization;
 pub mod type_encryption;
 pub mod types;
 pub mod vault;
diff --git a/crates/hyperswitch_domain_models/src/payment_methods.rs b/crates/hyperswitch_domain_models/src/payment_methods.rs
index c2be89a97e6..2f135ca881e 100644
--- a/crates/hyperswitch_domain_models/src/payment_methods.rs
+++ b/crates/hyperswitch_domain_models/src/payment_methods.rs
@@ -36,7 +36,11 @@ use crate::{
 #[derive(Debug, serde::Deserialize, serde::Serialize, Clone)]
 pub struct VaultId(String);
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[cfg(any(
+    feature = "v2",
+    feature = "payment_methods_v2",
+    feature = "tokenization_v2"
+))]
 impl VaultId {
     pub fn get_string_repr(&self) -> &String {
         &self.0
@@ -625,9 +629,11 @@ pub struct PaymentMethodSession {
     pub return_url: Option<common_utils::types::Url>,
     pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
     pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+    pub tokenization_data: Option<pii::SecretSerdeValue>,
     pub expires_at: PrimitiveDateTime,
     pub associated_payment_methods: Option<Vec<id_type::GlobalPaymentMethodId>>,
     pub associated_payment: Option<id_type::GlobalPaymentId>,
+    pub associated_token_id: Option<id_type::GlobalTokenId>,
 }
 
 #[cfg(feature = "v2")]
@@ -642,10 +648,12 @@ impl super::behaviour::Conversion for PaymentMethodSession {
             billing: self.billing.map(|val| val.into()),
             psp_tokenization: self.psp_tokenization,
             network_tokenization: self.network_tokenization,
+            tokenization_data: self.tokenization_data,
             expires_at: self.expires_at,
             associated_payment_methods: self.associated_payment_methods,
             associated_payment: self.associated_payment,
             return_url: self.return_url,
+            associated_token_id: self.associated_token_id,
         })
     }
 
@@ -694,10 +702,12 @@ impl super::behaviour::Conversion for PaymentMethodSession {
                 billing,
                 psp_tokenization: storage_model.psp_tokenization,
                 network_tokenization: storage_model.network_tokenization,
+                tokenization_data: storage_model.tokenization_data,
                 expires_at: storage_model.expires_at,
                 associated_payment_methods: storage_model.associated_payment_methods,
                 associated_payment: storage_model.associated_payment,
                 return_url: storage_model.return_url,
+                associated_token_id: storage_model.associated_token_id,
             })
         }
         .await
@@ -713,10 +723,12 @@ impl super::behaviour::Conversion for PaymentMethodSession {
             billing: self.billing.map(|val| val.into()),
             psp_tokenization: self.psp_tokenization,
             network_tokenization: self.network_tokenization,
+            tokenization_data: self.tokenization_data,
             expires_at: self.expires_at,
             associated_payment_methods: self.associated_payment_methods,
             associated_payment: self.associated_payment,
             return_url: self.return_url,
+            associated_token_id: self.associated_token_id,
         })
     }
 }
@@ -878,6 +890,7 @@ pub enum PaymentMethodsSessionUpdateEnum {
         billing: Option<Encryptable<Address>>,
         psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
         network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+        tokenization_data: Option<pii::SecretSerdeValue>,
     },
 }
 
@@ -889,10 +902,12 @@ impl From<PaymentMethodsSessionUpdateEnum> for PaymentMethodsSessionUpdateIntern
                 billing,
                 psp_tokenization,
                 network_tokenization,
+                tokenization_data,
             } => Self {
                 billing,
                 psp_tokenization,
                 network_tokenization,
+                tokenization_data,
             },
         }
     }
@@ -907,10 +922,12 @@ impl PaymentMethodSession {
             billing,
             psp_tokenization,
             network_tokenization,
+            tokenization_data,
             expires_at,
             return_url,
             associated_payment_methods,
             associated_payment,
+            associated_token_id,
         } = self;
         Self {
             id,
@@ -918,10 +935,12 @@ impl PaymentMethodSession {
             billing: update_session.billing.or(billing),
             psp_tokenization: update_session.psp_tokenization.or(psp_tokenization),
             network_tokenization: update_session.network_tokenization.or(network_tokenization),
+            tokenization_data: update_session.tokenization_data.or(tokenization_data),
             expires_at,
             return_url,
             associated_payment_methods,
             associated_payment,
+            associated_token_id,
         }
     }
 }
@@ -931,6 +950,7 @@ pub struct PaymentMethodsSessionUpdateInternal {
     pub billing: Option<Encryptable<Address>>,
     pub psp_tokenization: Option<common_types::payment_methods::PspTokenization>,
     pub network_tokenization: Option<common_types::payment_methods::NetworkTokenization>,
+    pub tokenization_data: Option<pii::SecretSerdeValue>,
 }
 
 #[cfg(all(
diff --git a/crates/hyperswitch_domain_models/src/tokenization.rs b/crates/hyperswitch_domain_models/src/tokenization.rs
new file mode 100644
index 00000000000..4bbdaa2fb41
--- /dev/null
+++ b/crates/hyperswitch_domain_models/src/tokenization.rs
@@ -0,0 +1,105 @@
+use common_enums;
+use common_utils::{
+    self,
+    errors::{CustomResult, ValidationError},
+    id_type, pii,
+    types::{keymanager, MinorUnit},
+};
+use diesel_models::tokenization;
+use masking::{ExposeInterface, Secret};
+use serde::{Deserialize, Serialize};
+use time::PrimitiveDateTime;
+
+use crate::{merchant_key_store::MerchantKeyStore, types};
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct Tokenization {
+    pub id: common_utils::id_type::GlobalTokenId,
+    pub merchant_id: common_utils::id_type::MerchantId,
+    pub customer_id: common_utils::id_type::GlobalCustomerId,
+    pub locker_id: String,
+    pub created_at: PrimitiveDateTime,
+    pub updated_at: PrimitiveDateTime,
+    pub flag: common_enums::TokenizationFlag,
+    pub version: common_enums::ApiVersion,
+}
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct TokenizationNew {
+    pub id: common_utils::id_type::GlobalTokenId,
+    pub merchant_id: common_utils::id_type::MerchantId,
+    pub customer_id: common_utils::id_type::GlobalCustomerId,
+    pub locker_id: String,
+    pub flag: common_enums::TokenizationFlag,
+    pub version: common_enums::ApiVersion,
+}
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[derive(Clone, Debug, Serialize, Deserialize)]
+pub struct TokenizationResponse {
+    pub token: String,
+    pub created_at: PrimitiveDateTime,
+    pub flag: common_enums::TokenizationFlag,
+}
+
+impl From<Tokenization> for TokenizationResponse {
+    fn from(value: Tokenization) -> Self {
+        Self {
+            token: value.id.get_string_repr().to_string(),
+            created_at: value.created_at,
+            flag: value.flag,
+        }
+    }
+}
+
+#[async_trait::async_trait]
+impl super::behaviour::Conversion for Tokenization {
+    type DstType = diesel_models::tokenization::Tokenization;
+    type NewDstType = diesel_models::tokenization::Tokenization;
+
+    async fn convert(self) -> CustomResult<Self::DstType, ValidationError> {
+        Ok(diesel_models::tokenization::Tokenization {
+            id: self.id,
+            merchant_id: self.merchant_id,
+            customer_id: self.customer_id,
+            locker_id: self.locker_id,
+            created_at: self.created_at,
+            updated_at: self.updated_at,
+            version: self.version,
+            flag: self.flag,
+        })
+    }
+
+    async fn convert_back(
+        _state: &keymanager::KeyManagerState,
+        item: Self::DstType,
+        _key: &Secret<Vec<u8>>,
+        _key_manager_identifier: keymanager::Identifier,
+    ) -> CustomResult<Self, ValidationError> {
+        Ok(Self {
+            id: item.id,
+            merchant_id: item.merchant_id,
+            customer_id: item.customer_id,
+            locker_id: item.locker_id,
+            created_at: item.created_at,
+            updated_at: item.updated_at,
+            flag: item.flag,
+            version: item.version,
+        })
+    }
+
+    async fn construct_new(self) -> CustomResult<Self::NewDstType, ValidationError> {
+        Ok(diesel_models::tokenization::Tokenization {
+            id: self.id,
+            merchant_id: self.merchant_id,
+            customer_id: self.customer_id,
+            locker_id: self.locker_id,
+            created_at: self.created_at,
+            updated_at: self.updated_at,
+            version: self.version,
+            flag: self.flag,
+        })
+    }
+}
diff --git a/crates/masking/src/lib.rs b/crates/masking/src/lib.rs
index 49e9cbf54f7..35e55c8cb36 100644
--- a/crates/masking/src/lib.rs
+++ b/crates/masking/src/lib.rs
@@ -17,6 +17,8 @@ pub use abs::{ExposeInterface, ExposeOptionInterface, PeekInterface, SwitchStrat
 
 mod secret;
 mod strong_secret;
+#[cfg(feature = "serde")]
+pub use secret::JsonMaskStrategy;
 pub use secret::Secret;
 pub use strong_secret::StrongSecret;
 
diff --git a/crates/masking/src/secret.rs b/crates/masking/src/secret.rs
index ee65b1c015b..f2f519dd3ed 100644
--- a/crates/masking/src/secret.rs
+++ b/crates/masking/src/secret.rs
@@ -167,3 +167,258 @@ impl AsRef<[u8]> for Secret<Vec<u8>> {
         self.peek().as_slice()
     }
 }
+
+/// Strategy for masking JSON values
+#[cfg(feature = "serde")]
+pub enum JsonMaskStrategy {}
+
+#[cfg(feature = "serde")]
+impl Strategy<serde_json::Value> for JsonMaskStrategy {
+    fn fmt(value: &serde_json::Value, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match value {
+            serde_json::Value::Object(map) => {
+                write!(f, "{{")?;
+                let mut first = true;
+                for (key, val) in map {
+                    if !first {
+                        write!(f, ", ")?;
+                    }
+                    first = false;
+                    write!(f, "\"{}\":", key)?;
+                    Self::fmt(val, f)?;
+                }
+                write!(f, "}}")
+            }
+            serde_json::Value::Array(arr) => {
+                write!(f, "[")?;
+                let mut first = true;
+                for val in arr {
+                    if !first {
+                        write!(f, ", ")?;
+                    }
+                    first = false;
+                    Self::fmt(val, f)?;
+                }
+                write!(f, "]")
+            }
+            serde_json::Value::String(s) => {
+                // For strings, we show a masked version that gives a hint about the content
+                let masked = if s.len() <= 2 {
+                    "**".to_string()
+                } else if s.len() <= 6 {
+                    format!("{}**", &s[0..1])
+                } else {
+                    // For longer strings, show first and last character with length in between
+                    format!(
+                        "{}**{}**{}",
+                        &s[0..1],
+                        s.len() - 2,
+                        &s[s.len() - 1..s.len()]
+                    )
+                };
+                write!(f, "\"{}\"", masked)
+            }
+            serde_json::Value::Number(n) => {
+                // For numbers, we can show the order of magnitude
+                if n.is_i64() || n.is_u64() {
+                    let num_str = n.to_string();
+                    let masked_num = "*".repeat(num_str.len());
+                    write!(f, "{}", masked_num)
+                } else if n.is_f64() {
+                    // For floats, just use a generic mask
+                    write!(f, "**.**")
+                } else {
+                    write!(f, "0")
+                }
+            }
+            serde_json::Value::Bool(b) => {
+                // For booleans, we can show a hint about which one it is
+                write!(f, "{}", if *b { "**true" } else { "**false" })
+            }
+            serde_json::Value::Null => write!(f, "null"),
+        }
+    }
+}
+
+#[cfg(test)]
+#[cfg(feature = "serde")]
+mod tests {
+    use serde_json::json;
+
+    use super::*;
+
+    #[test]
+    #[allow(clippy::expect_used)]
+    fn test_json_mask_strategy() {
+        // Create a sample JSON with different types for testing
+        let original = json!({ "user": { "name": "John Doe", "email": "john@example.com", "age": 35, "verified": true }, "card": { "number": "4242424242424242", "cvv": 123, "amount": 99.99 }, "tags": ["personal", "premium"], "null_value": null, "short": "hi" });
+
+        // Apply the JsonMaskStrategy
+        let secret = Secret::<_, JsonMaskStrategy>::new(original.clone());
+        let masked_str = format!("{:?}", secret);
+
+        // Get specific values from original
+        let original_obj = original.as_object().expect("Original should be an object");
+        let user_obj = original_obj["user"]
+            .as_object()
+            .expect("User should be an object");
+        let name = user_obj["name"].as_str().expect("Name should be a string");
+        let email = user_obj["email"]
+            .as_str()
+            .expect("Email should be a string");
+        let age = user_obj["age"].as_i64().expect("Age should be a number");
+        let verified = user_obj["verified"]
+            .as_bool()
+            .expect("Verified should be a boolean");
+
+        let card_obj = original_obj["card"]
+            .as_object()
+            .expect("Card should be an object");
+        let card_number = card_obj["number"]
+            .as_str()
+            .expect("Card number should be a string");
+        let cvv = card_obj["cvv"].as_i64().expect("CVV should be a number");
+
+        let tags = original_obj["tags"]
+            .as_array()
+            .expect("Tags should be an array");
+        let tag1 = tags
+            .first()
+            .and_then(|v| v.as_str())
+            .expect("First tag should be a string");
+
+        // Now explicitly verify the masking patterns for each value type
+
+        // 1. String masking - pattern: first char + ** + length - 2 + ** + last char
+        let expected_name_mask = format!(
+            "\"{}**{}**{}\"",
+            &name[0..1],
+            name.len() - 2,
+            &name[name.len() - 1..]
+        );
+        let expected_email_mask = format!(
+            "\"{}**{}**{}\"",
+            &email[0..1],
+            email.len() - 2,
+            &email[email.len() - 1..]
+        );
+        let expected_card_mask = format!(
+            "\"{}**{}**{}\"",
+            &card_number[0..1],
+            card_number.len() - 2,
+            &card_number[card_number.len() - 1..]
+        );
+        let expected_tag1_mask = if tag1.len() <= 2 {
+            "\"**\"".to_string()
+        } else if tag1.len() <= 6 {
+            format!("\"{}**\"", &tag1[0..1])
+        } else {
+            format!(
+                "\"{}**{}**{}\"",
+                &tag1[0..1],
+                tag1.len() - 2,
+                &tag1[tag1.len() - 1..]
+            )
+        };
+        let expected_short_mask = "\"**\"".to_string(); // For "hi"
+
+        // 2. Number masking
+        let expected_age_mask = "*".repeat(age.to_string().len()); // Repeat * for the number of digits
+        let expected_cvv_mask = "*".repeat(cvv.to_string().len());
+
+        // 3. Boolean masking
+        let expected_verified_mask = if verified { "**true" } else { "**false" };
+
+        // Check that the masked output includes the expected masked patterns
+        assert!(
+            masked_str.contains(&expected_name_mask),
+            "Name not masked correctly. Expected: {}",
+            expected_name_mask
+        );
+        assert!(
+            masked_str.contains(&expected_email_mask),
+            "Email not masked correctly. Expected: {}",
+            expected_email_mask
+        );
+        assert!(
+            masked_str.contains(&expected_card_mask),
+            "Card number not masked correctly. Expected: {}",
+            expected_card_mask
+        );
+        assert!(
+            masked_str.contains(&expected_tag1_mask),
+            "Tag not masked correctly. Expected: {}",
+            expected_tag1_mask
+        );
+        assert!(
+            masked_str.contains(&expected_short_mask),
+            "Short string not masked correctly. Expected: {}",
+            expected_short_mask
+        );
+
+        assert!(
+            masked_str.contains(&expected_age_mask),
+            "Age not masked correctly. Expected: {}",
+            expected_age_mask
+        );
+        assert!(
+            masked_str.contains(&expected_cvv_mask),
+            "CVV not masked correctly. Expected: {}",
+            expected_cvv_mask
+        );
+
+        assert!(
+            masked_str.contains(expected_verified_mask),
+            "Boolean not masked correctly. Expected: {}",
+            expected_verified_mask
+        );
+
+        // Check structure preservation
+        assert!(
+            masked_str.contains("\"user\""),
+            "Structure not preserved - missing user object"
+        );
+        assert!(
+            masked_str.contains("\"card\""),
+            "Structure not preserved - missing card object"
+        );
+        assert!(
+            masked_str.contains("\"tags\""),
+            "Structure not preserved - missing tags array"
+        );
+        assert!(
+            masked_str.contains("\"null_value\":null"),
+            "Null value not preserved correctly"
+        );
+
+        // Additional security checks to ensure no original values are exposed
+        assert!(
+            !masked_str.contains(name),
+            "Original name value exposed in masked output"
+        );
+        assert!(
+            !masked_str.contains(email),
+            "Original email value exposed in masked output"
+        );
+        assert!(
+            !masked_str.contains(card_number),
+            "Original card number exposed in masked output"
+        );
+        assert!(
+            !masked_str.contains(&age.to_string()),
+            "Original age value exposed in masked output"
+        );
+        assert!(
+            !masked_str.contains(&cvv.to_string()),
+            "Original CVV value exposed in masked output"
+        );
+        assert!(
+            !masked_str.contains(tag1),
+            "Original tag value exposed in masked output"
+        );
+        assert!(
+            !masked_str.contains("hi"),
+            "Original short string value exposed in masked output"
+        );
+    }
+}
diff --git a/crates/openapi/Cargo.toml b/crates/openapi/Cargo.toml
index 33c48e2f0ae..2fea584e9b1 100644
--- a/crates/openapi/Cargo.toml
+++ b/crates/openapi/Cargo.toml
@@ -17,7 +17,7 @@ common_types = { version = "0.1.0", path = "../common_types" }
 router_env = { version = "0.1.0", path = "../router_env" }
 
 [features]
-v2 = ["api_models/v2", "api_models/customer_v2", "common_utils/v2", "api_models/payment_methods_v2", "common_utils/payment_methods_v2", "api_models/refunds_v2"]
+v2 = ["api_models/v2", "api_models/customer_v2", "common_utils/v2", "api_models/payment_methods_v2", "common_utils/payment_methods_v2", "api_models/refunds_v2", "api_models/tokenization_v2"]
 v1 = ["api_models/v1", "common_utils/v1"]
 
 [lints]
diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs
index 9b8387389fe..45f8e87798a 100644
--- a/crates/openapi/src/openapi_v2.rs
+++ b/crates/openapi/src/openapi_v2.rs
@@ -157,6 +157,9 @@ Never share your secret api keys. Keep them guarded and secure.
 
         // Routes for proxy
         routes::proxy::proxy_core,
+
+        // Route for tokenization
+        routes::tokenization::create_token_vault_api,
     ),
     components(schemas(
         common_utils::types::MinorUnit,
@@ -736,6 +739,8 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::proxy::ProxyResponse,
         api_models::proxy::TokenType,
         routes::payments::ForceSync,
+        api_models::tokenization::GenericTokenizationRequest,
+        api_models::tokenization::GenericTokenizationResponse,
     )),
     modifiers(&SecurityAddon)
 )]
diff --git a/crates/openapi/src/routes.rs b/crates/openapi/src/routes.rs
index 8f95de75b3f..f2298c17ee5 100644
--- a/crates/openapi/src/routes.rs
+++ b/crates/openapi/src/routes.rs
@@ -20,4 +20,5 @@ pub mod refunds;
 pub mod relay;
 pub mod revenue_recovery;
 pub mod routing;
+pub mod tokenization;
 pub mod webhook_events;
diff --git a/crates/openapi/src/routes/tokenization.rs b/crates/openapi/src/routes/tokenization.rs
new file mode 100644
index 00000000000..22f1227a9c0
--- /dev/null
+++ b/crates/openapi/src/routes/tokenization.rs
@@ -0,0 +1,33 @@
+use serde_json::json;
+use utoipa::OpenApi;
+
+#[cfg(feature = "v2")]
+#[utoipa::path(
+    post,
+    path = "/v2/tokenize",
+    request_body(
+        content = GenericTokenizationRequest,
+        examples(("Create a token with customer_id" = (
+            value = json!({
+                "customer_id": "12345_cus_0196d94b9c207333a297cbcf31f2e8c8",
+                "token_request": {
+                    "payment_method_data": {
+                        "card": {
+                            "card_holder_name": "test name"
+                        }
+                    }
+                }
+            })
+        )))
+    ),
+    responses(
+        (status = 200, description = "Token created successfully", body = GenericTokenizationResponse),
+        (status = 400, description = "Invalid request"),
+        (status = 401, description = "Unauthorized"),
+        (status = 500, description = "Internal server error")
+    ),
+    tag = "Tokenization",
+    operation_id = "create_token_vault_api",
+    security(("ephemeral_key" = []),("api_key" = []))
+)]
+pub async fn create_token_vault_api() {}
diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml
index 06fd5ce67b1..9f6d807189d 100644
--- a/crates/router/Cargo.toml
+++ b/crates/router/Cargo.toml
@@ -33,13 +33,14 @@ payouts = ["api_models/payouts", "common_enums/payouts", "hyperswitch_connectors
 payout_retry = ["payouts"]
 recon = ["email", "api_models/recon"]
 retry = []
-v2 = ["customer_v2", "payment_methods_v2", "common_default", "api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "kgraph_utils/v2", "common_utils/v2", "hyperswitch_connectors/v2","hyperswitch_interfaces/v2", "common_types/v2","revenue_recovery","scheduler/v2", "refunds_v2", "euclid/v2", "payment_methods/v2"]
+v2 = ["customer_v2", "payment_methods_v2", "common_default", "api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "kgraph_utils/v2", "common_utils/v2", "hyperswitch_connectors/v2","hyperswitch_interfaces/v2", "common_types/v2","revenue_recovery","scheduler/v2", "refunds_v2", "euclid/v2", "payment_methods/v2", "tokenization_v2"]
 v1 = ["common_default", "api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "hyperswitch_interfaces/v1", "kgraph_utils/v1", "common_utils/v1", "hyperswitch_connectors/v1", "common_types/v1","scheduler/v1", "payment_methods/v1"]
 customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2", "storage_impl/customer_v2"]
 payment_methods_v2 = ["api_models/payment_methods_v2", "diesel_models/payment_methods_v2", "hyperswitch_domain_models/payment_methods_v2", "storage_impl/payment_methods_v2", "common_utils/payment_methods_v2"]
 dynamic_routing = ["external_services/dynamic_routing", "storage_impl/dynamic_routing", "api_models/dynamic_routing"]
 revenue_recovery =["api_models/revenue_recovery","hyperswitch_interfaces/revenue_recovery","hyperswitch_domain_models/revenue_recovery","hyperswitch_connectors/revenue_recovery"]
 refunds_v2 = ["api_models/refunds_v2", "diesel_models/refunds_v2", "storage_impl/refunds_v2", "hyperswitch_domain_models/refunds_v2"]
+tokenization_v2 = ["api_models/tokenization_v2", "diesel_models/tokenization_v2", "hyperswitch_domain_models/tokenization_v2", "storage_impl/tokenization_v2"]
 
 # Partial Auth
 # The feature reduces the overhead of the router authenticating the merchant for every request, and trusts on `x-merchant-id` header to be present in the request.
@@ -48,7 +49,7 @@ partial-auth = []
 
 [dependencies]
 actix-cors = "0.6.5"
-actix-http = "3.6.0"
+actix-http = "3.6.0" 
 actix-multipart = "0.6.1"
 actix-rt = "2.9.0"
 actix-web = "4.5.1"
@@ -128,7 +129,7 @@ common_enums = { version = "0.1.0", path = "../common_enums" }
 common_utils = { version = "0.1.0", path = "../common_utils", features = ["signals", "async_ext", "logs", "metrics", "keymanager", "encryption_service"] }
 common_types = { version = "0.1.0", path = "../common_types" }
 currency_conversion = { version = "0.1.0", path = "../currency_conversion" }
-diesel_models = { version = "0.1.0", path = "../diesel_models", features = ["kv_store"], default-features = false }
+diesel_models = { version = "0.1.0", path = "../diesel_models", features = ["kv_store", "tokenization_v2"], default-features = false }
 euclid = { version = "0.1.0", path = "../euclid", features = ["valued_jit"] }
 events = { version = "0.1.0", path = "../events" }
 external_services = { version = "0.1.0", path = "../external_services" }
diff --git a/crates/router/src/core.rs b/crates/router/src/core.rs
index e67c3234b19..812d23165d5 100644
--- a/crates/router/src/core.rs
+++ b/crates/router/src/core.rs
@@ -67,3 +67,5 @@ pub mod proxy;
 pub mod relay;
 #[cfg(feature = "v2")]
 pub mod revenue_recovery;
+
+pub mod tokenization;
diff --git a/crates/router/src/core/payment_methods.rs b/crates/router/src/core/payment_methods.rs
index 702b81f9720..8558b43491b 100644
--- a/crates/router/src/core/payment_methods.rs
+++ b/crates/router/src/core/payment_methods.rs
@@ -71,7 +71,7 @@ use crate::{
     configs::settings,
     core::{
         payment_methods::transformers as pm_transforms, payments as payments_core,
-        utils as core_utils,
+        tokenization as tokenization_core, utils as core_utils,
     },
     db::errors::ConnectorErrorExt,
     headers, logger,
@@ -2569,10 +2569,12 @@ pub async fn payment_methods_session_create(
             billing,
             psp_tokenization: request.psp_tokenization,
             network_tokenization: request.network_tokenization,
+            tokenization_data: request.tokenization_data,
             expires_at,
             return_url: request.return_url,
             associated_payment_methods: None,
             associated_payment: None,
+            associated_token_id: None,
         };
 
     db.insert_payment_methods_session(
@@ -2589,6 +2591,7 @@ pub async fn payment_methods_session_create(
         payment_method_session_domain_model,
         client_secret.secret,
         None,
+        None,
     );
 
     Ok(services::ApplicationResponse::Json(response))
@@ -2638,6 +2641,7 @@ pub async fn payment_methods_session_update(
             billing,
             psp_tokenization: request.psp_tokenization,
             network_tokenization: request.network_tokenization,
+            tokenization_data: request.tokenization_data,
         };
 
     let update_state_change = db
@@ -2656,6 +2660,7 @@ pub async fn payment_methods_session_update(
         update_state_change,
         Secret::new("CLIENT_SECRET_REDACTED".to_string()),
         None, // TODO: send associated payments response based on the expandable param
+        None,
     );
 
     Ok(services::ApplicationResponse::Json(response))
@@ -2685,6 +2690,7 @@ pub async fn payment_methods_session_retrieve(
         payment_method_session_domain_model,
         Secret::new("CLIENT_SECRET_REDACTED".to_string()),
         None, // TODO: send associated payments response based on the expandable param
+        None,
     );
 
     Ok(services::ApplicationResponse::Json(response))
@@ -2873,6 +2879,8 @@ pub async fn payment_methods_session_confirm(
         })
         .or_else(|| payment_method_session_billing.clone());
 
+    let customer_id = payment_method_session.customer_id.clone();
+
     let create_payment_method_request = get_payment_method_create_request(
         request
             .payment_method_data
@@ -2881,7 +2889,7 @@ pub async fn payment_methods_session_confirm(
             .get_required_value("payment_method_data")?,
         request.payment_method_type,
         request.payment_method_subtype,
-        payment_method_session.customer_id.clone(),
+        customer_id.clone(),
         unified_billing_address.as_ref(),
         Some(&payment_method_session),
     )
@@ -2936,11 +2944,35 @@ pub async fn payment_methods_session_confirm(
         None => None,
     };
 
+    let tokenization_response = match payment_method_session.tokenization_data.clone() {
+        Some(tokenization_data) => {
+            let tokenization_response = tokenization_core::create_vault_token_core(
+                state.clone(),
+                &merchant_context.get_merchant_account().clone(),
+                &merchant_context.get_merchant_key_store().clone(),
+                api_models::tokenization::GenericTokenizationRequest {
+                    customer_id: customer_id.clone(),
+                    token_request: tokenization_data,
+                },
+            )
+            .await?;
+            let token = match tokenization_response {
+                services::ApplicationResponse::Json(response) => Some(response),
+                _ => None,
+            };
+            Some(token)
+        }
+        None => None,
+    };
+
+    logger::debug!(?tokenization_response, "Tokenization response");
+
     //TODO: update the payment method session with the payment id and payment method id
     let payment_method_session_response = transformers::generate_payment_method_session_response(
         payment_method_session,
         Secret::new("CLIENT_SECRET_REDACTED".to_string()),
         payments_response,
+        (tokenization_response.flatten()),
     );
 
     Ok(services::ApplicationResponse::Json(
diff --git a/crates/router/src/core/payment_methods/transformers.rs b/crates/router/src/core/payment_methods/transformers.rs
index 31ecd45e466..fd36f6d0ab7 100644
--- a/crates/router/src/core/payment_methods/transformers.rs
+++ b/crates/router/src/core/payment_methods/transformers.rs
@@ -1021,6 +1021,7 @@ pub fn generate_payment_method_session_response(
     payment_method_session: hyperswitch_domain_models::payment_methods::PaymentMethodSession,
     client_secret: Secret<String>,
     associated_payment: Option<api_models::payments::PaymentsResponse>,
+    tokenization_service_response: Option<api_models::tokenization::GenericTokenizationResponse>,
 ) -> api_models::payment_methods::PaymentMethodSessionResponse {
     let next_action = associated_payment
         .as_ref()
@@ -1034,6 +1035,10 @@ pub fn generate_payment_method_session_response(
             },
         );
 
+    let token_id = tokenization_service_response
+        .as_ref()
+        .map(|tokenization_service_response| tokenization_service_response.id.clone());
+
     api_models::payment_methods::PaymentMethodSessionResponse {
         id: payment_method_session.id,
         customer_id: payment_method_session.customer_id,
@@ -1043,12 +1048,14 @@ pub fn generate_payment_method_session_response(
             .map(From::from),
         psp_tokenization: payment_method_session.psp_tokenization,
         network_tokenization: payment_method_session.network_tokenization,
+        tokenization_data: payment_method_session.tokenization_data,
         expires_at: payment_method_session.expires_at,
         client_secret,
         next_action,
         return_url: payment_method_session.return_url,
         associated_payment_methods: payment_method_session.associated_payment_methods,
         authentication_details,
+        associated_token_id: token_id,
     }
 }
 
diff --git a/crates/router/src/core/payment_methods/vault.rs b/crates/router/src/core/payment_methods/vault.rs
index e29527f9fe7..c545bcac503 100644
--- a/crates/router/src/core/payment_methods/vault.rs
+++ b/crates/router/src/core/payment_methods/vault.rs
@@ -1355,6 +1355,30 @@ pub async fn retrieve_payment_method_from_vault_internal(
     Ok(stored_pm_resp)
 }
 
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[instrument(skip_all)]
+pub async fn retrive_value_from_vault(
+    state: &routes::SessionState,
+    request: pm_types::VaultRetrieveRequest,
+) -> CustomResult<serde_json::value::Value, errors::VaultError> {
+    let payload = request
+        .encode_to_vec()
+        .change_context(errors::VaultError::RequestEncodingFailed)
+        .attach_printable("Failed to encode VaultRetrieveRequest")?;
+
+    let resp = call_to_vault::<pm_types::VaultRetrieve>(state, payload)
+        .await
+        .change_context(errors::VaultError::VaultAPIError)
+        .attach_printable("Call to vault failed")?;
+
+    let stored_resp: serde_json::Value = resp
+        .parse_struct("VaultRetrieveResponse")
+        .change_context(errors::VaultError::ResponseDeserializationFailed)
+        .attach_printable("Failed to parse data into VaultRetrieveResponse")?;
+
+    Ok(stored_resp)
+}
+
 #[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
 #[instrument(skip_all)]
 pub async fn retrieve_payment_method_from_vault_external(
diff --git a/crates/router/src/core/tokenization.rs b/crates/router/src/core/tokenization.rs
new file mode 100644
index 00000000000..44bc53c77a0
--- /dev/null
+++ b/crates/router/src/core/tokenization.rs
@@ -0,0 +1,156 @@
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use std::sync::Arc;
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use actix_web::{web, HttpRequest, HttpResponse};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use api_models;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use common_enums::enums;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use common_utils::{
+    crypto::{DecodeMessage, EncodeMessage, GcmAes256},
+    errors::CustomResult,
+    ext_traits::{BytesExt, Encode, StringExt},
+    id_type,
+};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use error_stack::ResultExt;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use hyperswitch_domain_models;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use masking::{JsonMaskStrategy, Secret};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use router_env::{instrument, logger, tracing, Flow};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use serde::Serialize;
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use crate::{
+    core::{
+        errors::{self, RouterResponse, RouterResult},
+        payment_methods::vault as pm_vault,
+        tokenization,
+    },
+    routes::{app::StorageInterface, AppState, SessionState},
+    services::{self, api as api_service, authentication as auth},
+    types::{api, domain, payment_methods as pm_types},
+};
+
+#[instrument(skip_all)]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub async fn create_vault_token_core(
+    state: SessionState,
+    merchant_account: &domain::MerchantAccount,
+    merchant_key_store: &domain::MerchantKeyStore,
+    req: api_models::tokenization::GenericTokenizationRequest,
+) -> RouterResponse<api_models::tokenization::GenericTokenizationResponse> {
+    // Generate a unique vault ID
+    let vault_id = domain::VaultId::generate(uuid::Uuid::now_v7().to_string());
+    let db = state.store.as_ref();
+    let key_manager_state = &(&state).into();
+    let customer_id = req.customer_id.clone();
+    // Create vault request
+    let payload = pm_types::AddVaultRequest {
+        entity_id: merchant_account.get_id().to_owned(),
+        vault_id: vault_id.clone(),
+        data: req.token_request.clone(),
+        ttl: state.conf.locker.ttl_for_storage_in_secs,
+    }
+    .encode_to_vec()
+    .change_context(errors::ApiErrorResponse::InternalServerError)
+    .attach_printable("Failed to encode Request")?;
+
+    // Call the vault service
+    let resp = pm_vault::call_to_vault::<pm_types::AddVault>(&state, payload.clone())
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Call to vault failed")?;
+
+    // Parse the response
+    let stored_resp: pm_types::AddVaultResponse = resp
+        .parse_struct("AddVaultResponse")
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to parse data into AddVaultResponse")?;
+
+    // Create new tokenization record
+    let tokenization_new = hyperswitch_domain_models::tokenization::Tokenization {
+        id: id_type::GlobalTokenId::generate(&state.conf.cell_information.id),
+        merchant_id: merchant_account.get_id().clone(),
+        customer_id: customer_id.clone(),
+        locker_id: stored_resp.vault_id.get_string_repr().to_string(),
+        created_at: common_utils::date_time::now(),
+        updated_at: common_utils::date_time::now(),
+        flag: enums::TokenizationFlag::Enabled,
+        version: enums::ApiVersion::V2,
+    };
+
+    // Insert into database
+    let tokenization = db
+        .insert_tokenization(
+            tokenization_new,
+            &(merchant_key_store.clone()),
+            key_manager_state,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to insert tokenization record")?;
+
+    // Convert to TokenizationResponse
+    Ok(hyperswitch_domain_models::api::ApplicationResponse::Json(
+        api_models::tokenization::GenericTokenizationResponse {
+            id: tokenization.id,
+            created_at: tokenization.created_at,
+            flag: tokenization.flag,
+        },
+    ))
+}
+
+#[instrument(skip_all)]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub async fn get_token_vault_core(
+    state: SessionState,
+    merchant_account: &domain::MerchantAccount,
+    merchant_key_store: &domain::MerchantKeyStore,
+    query: id_type::GlobalTokenId,
+) -> CustomResult<serde_json::Value, errors::ApiErrorResponse> {
+    let db = state.store.as_ref();
+    let key_manager_state = &(&state).into();
+
+    let tokenization_record = db
+        .get_entity_id_vault_id_by_token_id(
+            &query,
+            &(merchant_key_store.clone()),
+            key_manager_state,
+        )
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to get tokenization record")?;
+
+    if tokenization_record.flag == enums::TokenizationFlag::Disabled {
+        return Err(errors::ApiErrorResponse::GenericNotFoundError {
+            message: "Tokenization is disabled for the id".to_string(),
+        }
+        .into());
+    }
+
+    let vault_request = pm_types::VaultRetrieveRequest {
+        entity_id: tokenization_record.merchant_id.clone(),
+        vault_id: hyperswitch_domain_models::payment_methods::VaultId::generate(
+            tokenization_record.locker_id.clone(),
+        ),
+    };
+
+    let vault_data = pm_vault::retrive_value_from_vault(&state, vault_request)
+        .await
+        .change_context(errors::ApiErrorResponse::InternalServerError)
+        .attach_printable("Failed to retrieve vault data")?;
+
+    let data_json = vault_data
+        .get("data")
+        .cloned()
+        .unwrap_or(serde_json::Value::Null);
+
+    // Create the response
+    Ok(data_json)
+}
diff --git a/crates/router/src/db.rs b/crates/router/src/db.rs
index 17938dbbe31..d77e1926260 100644
--- a/crates/router/src/db.rs
+++ b/crates/router/src/db.rs
@@ -61,7 +61,9 @@ use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};
 use masking::PeekInterface;
 use redis_interface::errors::RedisError;
 use router_env::logger;
-use storage_impl::{errors::StorageError, redis::kv_store::RedisConnInterface, MockDb};
+use storage_impl::{
+    errors::StorageError, redis::kv_store::RedisConnInterface, tokenization, MockDb,
+};
 
 pub use self::kafka_store::KafkaStore;
 use self::{fraud_check::FraudCheckInterface, organization::OrganizationInterface};
@@ -139,6 +141,7 @@ pub trait StorageInterface:
     + relay::RelayInterface
     + user::theme::ThemeInterface
     + payment_method_session::PaymentMethodsSessionInterface
+    + tokenization::TokenizationInterface
     + 'static
 {
     fn get_scheduler_db(&self) -> Box<dyn scheduler::SchedulerInterface>;
diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs
index 8c4ac07a32a..547846f8a0a 100644
--- a/crates/router/src/db/kafka_store.rs
+++ b/crates/router/src/db/kafka_store.rs
@@ -80,6 +80,7 @@ use crate::{
         refund::RefundInterface,
         reverse_lookup::ReverseLookupInterface,
         routing_algorithm::RoutingAlgorithmInterface,
+        tokenization::TokenizationInterface,
         unified_translations::UnifiedTranslationsInterface,
         AccountsStorageInterface, CommonStorageInterface, GlobalStorageInterface,
         MasterKeyInterface, StorageInterface,
@@ -87,7 +88,6 @@ use crate::{
     services::{kafka::KafkaProducer, Store},
     types::{domain, storage, AccessToken},
 };
-
 #[derive(Debug, Clone, Serialize)]
 pub struct TenantID(pub String);
 
@@ -4234,3 +4234,34 @@ impl CallbackMapperInterface for KafkaStore {
         self.diesel_store.find_call_back_mapper_by_id(id).await
     }
 }
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+#[async_trait::async_trait]
+impl TokenizationInterface for KafkaStore {
+    async fn insert_tokenization(
+        &self,
+        tokenization: hyperswitch_domain_models::tokenization::Tokenization,
+        merchant_key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        self.diesel_store
+            .insert_tokenization(tokenization, merchant_key_store, key_manager_state)
+            .await
+    }
+
+    async fn get_entity_id_vault_id_by_token_id(
+        &self,
+        token: &id_type::GlobalTokenId,
+        merchant_key_store: &hyperswitch_domain_models::merchant_key_store::MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        self.diesel_store
+            .get_entity_id_vault_id_by_token_id(token, merchant_key_store, key_manager_state)
+            .await
+    }
+}
+
+#[cfg(not(all(feature = "v2", feature = "tokenization_v2")))]
+impl TokenizationInterface for KafkaStore {}
diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs
index 0388f68225b..eb794a5c4fe 100644
--- a/crates/router/src/lib.rs
+++ b/crates/router/src/lib.rs
@@ -158,7 +158,10 @@ pub fn mk_app(
                 .service(routes::PaymentMethodSession::server(state.clone()))
                 .service(routes::Refunds::server(state.clone()));
         }
-
+        #[cfg(all(feature = "v2", feature = "oltp", feature = "tokenization_v2"))]
+        {
+            server_app = server_app.service(routes::Tokenization::server(state.clone()));
+        }
         #[cfg(feature = "v1")]
         {
             server_app = server_app
diff --git a/crates/router/src/routes.rs b/crates/router/src/routes.rs
index f36e7b6049b..21db7a4624d 100644
--- a/crates/router/src/routes.rs
+++ b/crates/router/src/routes.rs
@@ -47,6 +47,7 @@ pub mod recon;
 pub mod refunds;
 #[cfg(feature = "olap")]
 pub mod routing;
+pub mod tokenization;
 #[cfg(feature = "olap")]
 pub mod user;
 #[cfg(feature = "olap")]
@@ -78,6 +79,8 @@ pub use self::app::PaymentMethodSession;
 pub use self::app::Proxy;
 #[cfg(all(feature = "olap", feature = "recon", feature = "v1"))]
 pub use self::app::Recon;
+#[cfg(feature = "v2")]
+pub use self::app::Tokenization;
 pub use self::app::{
     ApiKeys, AppState, ApplePayCertificatesMigration, Cache, Cards, Configs, ConnectorOnboarding,
     Customers, Disputes, EphemeralKey, FeatureMatrix, Files, Forex, Gsm, Health, Hypersense,
diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs
index 173ac34bd3a..6071a9ee0b0 100644
--- a/crates/router/src/routes/app.rs
+++ b/crates/router/src/routes/app.rs
@@ -55,6 +55,8 @@ use super::recovery_webhooks::*;
 use super::refunds;
 #[cfg(feature = "olap")]
 use super::routing;
+#[cfg(all(feature = "oltp", feature = "v2"))]
+use super::tokenization as tokenization_routes;
 #[cfg(all(feature = "olap", feature = "v1"))]
 use super::verification::{apple_pay_merchant_registration, retrieve_apple_pay_verified_domains};
 #[cfg(feature = "oltp")]
@@ -1418,6 +1420,20 @@ impl PaymentMethodSession {
     }
 }
 
+#[cfg(all(feature = "v2", feature = "oltp"))]
+pub struct Tokenization;
+
+#[cfg(all(feature = "v2", feature = "oltp"))]
+impl Tokenization {
+    pub fn server(state: AppState) -> Scope {
+        let mut token_route = web::scope("/v2/tokenize").app_data(web::Data::new(state));
+        token_route = token_route.service(
+            web::resource("").route(web::post().to(tokenization_routes::create_token_vault_api)),
+        );
+        token_route
+    }
+}
+
 #[cfg(all(feature = "olap", feature = "recon", feature = "v1"))]
 pub struct Recon;
 
diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs
index 1f224d2177c..8f14d5b5532 100644
--- a/crates/router/src/routes/lock_utils.rs
+++ b/crates/router/src/routes/lock_utils.rs
@@ -44,6 +44,7 @@ pub enum ApiIdentifier {
     PaymentMethodSession,
     ProcessTracker,
     Proxy,
+    GenericTokenization,
 }
 
 impl From<Flow> for ApiIdentifier {
@@ -342,6 +343,8 @@ impl From<Flow> for ApiIdentifier {
 
             Flow::RevenueRecoveryRetrieve => Self::ProcessTracker,
             Flow::Proxy => Self::Proxy,
+
+            Flow::TokenizationCreate | Flow::TokenizationRetrieve => Self::GenericTokenization,
         }
     }
 }
diff --git a/crates/router/src/routes/tokenization.rs b/crates/router/src/routes/tokenization.rs
new file mode 100644
index 00000000000..6becca19df7
--- /dev/null
+++ b/crates/router/src/routes/tokenization.rs
@@ -0,0 +1,74 @@
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use std::sync::Arc;
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use actix_web::{web, HttpRequest, HttpResponse};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use api_models;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use common_utils::{
+    ext_traits::{BytesExt, Encode},
+    id_type,
+};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use error_stack::ResultExt;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use hyperswitch_domain_models;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use masking::Secret;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use router_env::{instrument, logger, tracing, Flow};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use serde::Serialize;
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use crate::{
+    core::{
+        api_locking,
+        errors::{self, RouterResult},
+        tokenization,
+    },
+    headers::X_CUSTOMER_ID,
+    routes::{app::StorageInterface, AppState, SessionState},
+    services::{self, api as api_service, authentication as auth},
+    types::{api, domain, payment_methods as pm_types},
+};
+
+#[instrument(skip_all, fields(flow = ?Flow::TokenizationCreate))]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub async fn create_token_vault_api(
+    state: web::Data<AppState>,
+    req: HttpRequest,
+    json_payload: web::Json<api_models::tokenization::GenericTokenizationRequest>,
+) -> HttpResponse {
+    let flow = Flow::TokenizationCreate;
+    let payload = json_payload.into_inner();
+    let customer_id = payload.customer_id.clone();
+    Box::pin(api_service::server_wrap(
+        flow,
+        state,
+        &req,
+        payload,
+        |state, auth: auth::AuthenticationData, request, _| async move {
+            tokenization::create_vault_token_core(
+                state,
+                &auth.merchant_account,
+                &auth.key_store,
+                request,
+            )
+            .await
+        },
+        auth::api_or_client_auth(
+            &auth::V2ApiKeyAuth {
+                is_connected_allowed: false,
+                is_platform_allowed: false,
+            },
+            &auth::V2ClientAuth(common_utils::types::authentication::ResourceId::Customer(
+                customer_id,
+            )),
+            req.headers(),
+        ),
+        api_locking::LockAction::NotApplicable,
+    ))
+    .await
+}
diff --git a/crates/router/src/types/payment_methods.rs b/crates/router/src/types/payment_methods.rs
index 342347cd793..f05442ed45d 100644
--- a/crates/router/src/types/payment_methods.rs
+++ b/crates/router/src/types/payment_methods.rs
@@ -44,7 +44,11 @@ pub struct VaultFingerprintResponse {
     pub fingerprint_id: String,
 }
 
-#[cfg(all(feature = "v2", feature = "payment_methods_v2"))]
+#[cfg(any(
+    feature = "v2",
+    feature = "payment_methods_v2",
+    feature = "tokenization_v2"
+))]
 #[derive(Debug, serde::Deserialize, serde::Serialize)]
 pub struct AddVaultRequest<D> {
     pub entity_id: id_type::MerchantId,
diff --git a/crates/router_env/src/logger/types.rs b/crates/router_env/src/logger/types.rs
index 60a8939aeb0..c4fe30334b9 100644
--- a/crates/router_env/src/logger/types.rs
+++ b/crates/router_env/src/logger/types.rs
@@ -586,6 +586,10 @@ pub enum Flow {
     TotalPaymentMethodCount,
     /// Process Tracker Revenue Recovery Workflow Retrieve
     RevenueRecoveryRetrieve,
+    /// Tokenization flow
+    TokenizationCreate,
+    /// Tokenization retrieve flow
+    TokenizationRetrieve,
     /// Clone Connector flow
     CloneConnector,
     ///Proxy Flow
diff --git a/crates/storage_impl/Cargo.toml b/crates/storage_impl/Cargo.toml
index ee849f78f46..4830201db74 100644
--- a/crates/storage_impl/Cargo.toml
+++ b/crates/storage_impl/Cargo.toml
@@ -18,6 +18,7 @@ v2 = ["api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "comm
 customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2"]
 payment_methods_v2 = ["diesel_models/payment_methods_v2", "api_models/payment_methods_v2", "hyperswitch_domain_models/payment_methods_v2"]
 refunds_v2 = ["diesel_models/refunds_v2"]
+tokenization_v2 = ["diesel_models/tokenization_v2", "api_models/tokenization_v2", "hyperswitch_domain_models/tokenization_v2"]
 
 [dependencies]
 # First Party dependencies
diff --git a/crates/storage_impl/src/lib.rs b/crates/storage_impl/src/lib.rs
index 6cc5f035a7a..05fc865860a 100644
--- a/crates/storage_impl/src/lib.rs
+++ b/crates/storage_impl/src/lib.rs
@@ -32,6 +32,9 @@ pub mod utils;
 
 use common_utils::{errors::CustomResult, types::keymanager::KeyManagerState};
 use database::store::PgPool;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use diesel_models::tokenization::Tokenization;
+pub mod tokenization;
 #[cfg(not(feature = "payouts"))]
 use hyperswitch_domain_models::{PayoutAttemptInterface, PayoutsInterface};
 pub use mock_db::MockDb;
@@ -502,3 +505,14 @@ impl UniqueConstraints for diesel_models::Customer {
 impl<T: DatabaseStore> PayoutAttemptInterface for RouterStore<T> {}
 #[cfg(not(feature = "payouts"))]
 impl<T: DatabaseStore> PayoutsInterface for RouterStore<T> {}
+
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+impl UniqueConstraints for diesel_models::tokenization::Tokenization {
+    fn unique_constraints(&self) -> Vec<String> {
+        vec![format!("id_{}", self.id.get_string_repr())]
+    }
+
+    fn table_name(&self) -> &str {
+        "tokenization"
+    }
+}
diff --git a/crates/storage_impl/src/mock_db.rs b/crates/storage_impl/src/mock_db.rs
index 1471f854de6..884d9747943 100644
--- a/crates/storage_impl/src/mock_db.rs
+++ b/crates/storage_impl/src/mock_db.rs
@@ -45,6 +45,8 @@ pub struct MockDb {
     pub mandates: Arc<Mutex<Vec<store::Mandate>>>,
     pub captures: Arc<Mutex<Vec<store::capture::Capture>>>,
     pub merchant_key_store: Arc<Mutex<Vec<store::merchant_key_store::MerchantKeyStore>>>,
+    #[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+    pub tokenizations: Arc<Mutex<Vec<store::tokenization::Tokenization>>>,
     pub business_profiles: Arc<Mutex<Vec<store::business_profile::Profile>>>,
     pub reverse_lookups: Arc<Mutex<Vec<store::ReverseLookup>>>,
     pub payment_link: Arc<Mutex<Vec<store::payment_link::PaymentLink>>>,
@@ -92,6 +94,8 @@ impl MockDb {
             mandates: Default::default(),
             captures: Default::default(),
             merchant_key_store: Default::default(),
+            #[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+            tokenizations: Default::default(),
             business_profiles: Default::default(),
             reverse_lookups: Default::default(),
             payment_link: Default::default(),
diff --git a/crates/storage_impl/src/tokenization.rs b/crates/storage_impl/src/tokenization.rs
new file mode 100644
index 00000000000..5ecb6b0a813
--- /dev/null
+++ b/crates/storage_impl/src/tokenization.rs
@@ -0,0 +1,174 @@
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use async_bb8_diesel::AsyncRunQueryDsl;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use common_utils::{
+    errors::CustomResult,
+    ext_traits::OptionExt,
+    id_type::{CellId, GlobalTokenId, MerchantId},
+    types::keymanager::KeyManagerState,
+};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use diesel::{ExpressionMethods, Insertable, RunQueryDsl};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use diesel_models::{
+    enums::TokenizationFlag as DbTokenizationFlag,
+    schema_v2::tokenization::dsl as tokenization_dsl, tokenization, PgPooledConn,
+};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use error_stack::{report, Report, ResultExt};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use hyperswitch_domain_models::tokenization::Tokenization;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use hyperswitch_domain_models::{
+    behaviour::{Conversion, ReverseConversion},
+    merchant_key_store::MerchantKeyStore,
+};
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use tokio::time;
+
+use super::MockDb;
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+use crate::{
+    connection, diesel_error_to_data_error, errors,
+    kv_router_store::{
+        FilterResourceParams, FindResourceBy, InsertResourceParams, UpdateResourceParams,
+    },
+    redis::kv_store::{Op, PartitionKey},
+    utils::{pg_connection_read, pg_connection_write},
+};
+use crate::{kv_router_store::KVRouterStore, DatabaseStore, RouterStore};
+
+#[cfg(not(all(feature = "v2", feature = "tokenization_v2")))]
+pub trait TokenizationInterface {}
+
+#[async_trait::async_trait]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+pub trait TokenizationInterface {
+    async fn insert_tokenization(
+        &self,
+        tokenization: hyperswitch_domain_models::tokenization::Tokenization,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>;
+
+    async fn get_entity_id_vault_id_by_token_id(
+        &self,
+        token: &common_utils::id_type::GlobalTokenId,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>;
+}
+
+#[async_trait::async_trait]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+impl<T: DatabaseStore> TokenizationInterface for RouterStore<T> {
+    async fn insert_tokenization(
+        &self,
+        tokenization: hyperswitch_domain_models::tokenization::Tokenization,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        let conn = connection::pg_connection_write(self).await?;
+
+        tokenization
+            .construct_new()
+            .await
+            .change_context(errors::StorageError::EncryptionError)?
+            .insert(&conn)
+            .await
+            .map_err(|error| report!(errors::StorageError::from(error)))?
+            .convert(
+                key_manager_state,
+                merchant_key_store.key.get_inner(),
+                merchant_key_store.merchant_id.clone().into(),
+            )
+            .await
+            .change_context(errors::StorageError::DecryptionError)
+    }
+
+    async fn get_entity_id_vault_id_by_token_id(
+        &self,
+        token: &common_utils::id_type::GlobalTokenId,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        let conn = connection::pg_connection_read(self).await?;
+
+        let tokenization = diesel_models::tokenization::Tokenization::find_by_id(&conn, token)
+            .await
+            .map_err(|error| report!(errors::StorageError::from(error)))?;
+
+        let domain = tokenization
+            .convert(
+                key_manager_state,
+                merchant_key_store.key.get_inner(),
+                merchant_key_store.merchant_id.clone().into(),
+            )
+            .await
+            .change_context(errors::StorageError::DecryptionError)?;
+
+        Ok(domain)
+    }
+}
+
+#[async_trait::async_trait]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+impl<T: DatabaseStore> TokenizationInterface for KVRouterStore<T> {
+    async fn insert_tokenization(
+        &self,
+        tokenization: hyperswitch_domain_models::tokenization::Tokenization,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        self.router_store
+            .insert_tokenization(tokenization, merchant_key_store, key_manager_state)
+            .await
+    }
+
+    async fn get_entity_id_vault_id_by_token_id(
+        &self,
+        token: &common_utils::id_type::GlobalTokenId,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        self.router_store
+            .get_entity_id_vault_id_by_token_id(token, merchant_key_store, key_manager_state)
+            .await
+    }
+}
+
+#[async_trait::async_trait]
+#[cfg(all(feature = "v2", feature = "tokenization_v2"))]
+impl TokenizationInterface for MockDb {
+    async fn insert_tokenization(
+        &self,
+        tokenization: hyperswitch_domain_models::tokenization::Tokenization,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        Err(errors::StorageError::MockDbError)?
+    }
+    async fn get_entity_id_vault_id_by_token_id(
+        &self,
+        token: &common_utils::id_type::GlobalTokenId,
+        merchant_key_store: &MerchantKeyStore,
+        key_manager_state: &KeyManagerState,
+    ) -> CustomResult<hyperswitch_domain_models::tokenization::Tokenization, errors::StorageError>
+    {
+        Err(errors::StorageError::MockDbError)?
+    }
+}
+
+#[cfg(not(all(feature = "v2", feature = "tokenization_v2")))]
+impl TokenizationInterface for MockDb {}
+
+#[cfg(not(all(feature = "v2", feature = "tokenization_v2")))]
+impl<T: DatabaseStore> TokenizationInterface for KVRouterStore<T> {}
+
+#[cfg(not(all(feature = "v2", feature = "tokenization_v2")))]
+impl<T: DatabaseStore> TokenizationInterface for RouterStore<T> {}
diff --git a/v2_migrations/2025-04-25-105138_tokenization_service_creation/down.sql b/v2_migrations/2025-04-25-105138_tokenization_service_creation/down.sql
new file mode 100644
index 00000000000..0eabe21fc74
--- /dev/null
+++ b/v2_migrations/2025-04-25-105138_tokenization_service_creation/down.sql
@@ -0,0 +1,3 @@
+-- This file should undo anything in `up.sql`
+DROP TABLE IF EXISTS tokenization;
+DROP TYPE "TokenizationFlag";
\ No newline at end of file
diff --git a/v2_migrations/2025-04-25-105138_tokenization_service_creation/up.sql b/v2_migrations/2025-04-25-105138_tokenization_service_creation/up.sql
new file mode 100644
index 00000000000..bfffd383ee5
--- /dev/null
+++ b/v2_migrations/2025-04-25-105138_tokenization_service_creation/up.sql
@@ -0,0 +1,13 @@
+-- Your SQL goes here
+CREATE TYPE "TokenizationFlag" AS ENUM ('enabled', 'disabled');
+
+CREATE TABLE IF NOT EXISTS tokenization (
+    id VARCHAR(64) PRIMARY KEY,  -- GlobalTokenId
+    merchant_id VARCHAR(255) NOT NULL,
+    customer_id VARCHAR(64) NOT NULL,
+    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    locker_id VARCHAR(255) NOT NULL,
+    flag "TokenizationFlag" NOT NULL DEFAULT 'enabled',
+    version "ApiVersion" NOT NULL DEFAULT 'v2'  -- ApiVersion enum
+);
\ No newline at end of file

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

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

## Description
<!-- Describe your changes in detail -->
Create a new set of endpoints for giving tokenization as a service for generic usage, current motivation of the service is to be used in proxy payment service.

### Additional Changes

- [ ] This PR modifies the API contract
- [x] 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)?
-->

**Create a token**
```bash
curl --location 'http: //localhost:8080/v2/tokenize' \
--header 'x-profile-id: pro_neU1Qn8gnIich0LAaQXm' \
--header 'Authorization: publishable-key=PUBLISHABLE_KEY,client-secret=CLIENT_SECRET' \
--header 'Content-Type: application/json' \
--data '{
    "customer_id": customer_id,
    "token_request": {
        "payment_method_data": {
            "card": {
                "card_holder_name": "Narayan Bhat"
            }
        }
    }
}'
```

Response
```json
{
    "id": "12345_tok_01966c6515157c3193db1c2502435ad5",
    "created_at": "2025-04-25 10:01:26.037519",
    "flag": "enabled"
}
```

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

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