Issue:
Bug: [DOCS] Add Api-Refrence  for Blocklist



This PR adds the api contracts(utoipa) for all blocklist apis.

Pull request description:
## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [x] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
This PR adds the api contracts(utoipa) for blocklist apis.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->


## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
The test cases  can be found out  here in this [PR](https://github.com/juspay/hyperswitch/pull/3056).
## 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
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable


Testing:

The test cases  can be found out  here in this [PR](https://github.com/juspay/hyperswitch/pull/3056).

Patch:
diff --git a/crates/api_models/src/blocklist.rs b/crates/api_models/src/blocklist.rs
index fc838eed5ce..888b9106ccc 100644
--- a/crates/api_models/src/blocklist.rs
+++ b/crates/api_models/src/blocklist.rs
@@ -1,7 +1,8 @@
 use common_enums::enums;
 use common_utils::events::ApiEventMetric;
+use utoipa::ToSchema;
 
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 #[serde(rename_all = "snake_case", tag = "type", content = "data")]
 pub enum BlocklistRequest {
     CardBin(String),
@@ -12,9 +13,10 @@ pub enum BlocklistRequest {
 pub type AddToBlocklistRequest = BlocklistRequest;
 pub type DeleteFromBlocklistRequest = BlocklistRequest;
 
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct BlocklistResponse {
     pub fingerprint_id: String,
+    #[schema(value_type = BlocklistDataKind)]
     pub data_kind: enums::BlocklistDataKind,
     #[serde(with = "common_utils::custom_serde::iso8601")]
     pub created_at: time::PrimitiveDateTime,
@@ -23,8 +25,9 @@ pub struct BlocklistResponse {
 pub type AddToBlocklistResponse = BlocklistResponse;
 pub type DeleteFromBlocklistResponse = BlocklistResponse;
 
-#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
+#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
 pub struct ListBlocklistQuery {
+    #[schema(value_type = BlocklistDataKind)]
     pub data_kind: enums::BlocklistDataKind,
     #[serde(default = "default_list_limit")]
     pub limit: u16,
diff --git a/crates/router/src/db/blocklist.rs b/crates/router/src/db/blocklist.rs
index c263bef63c5..93361552de7 100644
--- a/crates/router/src/db/blocklist.rs
+++ b/crates/router/src/db/blocklist.rs
@@ -163,41 +163,49 @@ impl BlocklistInterface for KafkaStore {
     #[instrument(skip_all)]
     async fn insert_blocklist_entry(
         &self,
-        _pm_blocklist: storage::BlocklistNew,
+        pm_blocklist: storage::BlocklistNew,
     ) -> CustomResult<storage::Blocklist, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store.insert_blocklist_entry(pm_blocklist).await
     }
 
     async fn find_blocklist_entry_by_merchant_id_fingerprint_id(
         &self,
-        _merchant_id: &str,
-        _fingerprint_id: &str,
+        merchant_id: &str,
+        fingerprint: &str,
     ) -> CustomResult<storage::Blocklist, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .find_blocklist_entry_by_merchant_id_fingerprint_id(merchant_id, fingerprint)
+            .await
     }
 
     async fn delete_blocklist_entry_by_merchant_id_fingerprint_id(
         &self,
-        _merchant_id: &str,
-        _fingerprint_id: &str,
+        merchant_id: &str,
+        fingerprint: &str,
     ) -> CustomResult<storage::Blocklist, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .delete_blocklist_entry_by_merchant_id_fingerprint_id(merchant_id, fingerprint)
+            .await
     }
 
     async fn list_blocklist_entries_by_merchant_id_data_kind(
         &self,
-        _merchant_id: &str,
-        _data_kind: common_enums::BlocklistDataKind,
-        _limit: i64,
-        _offset: i64,
+        merchant_id: &str,
+        data_kind: common_enums::BlocklistDataKind,
+        limit: i64,
+        offset: i64,
     ) -> CustomResult<Vec<storage::Blocklist>, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .list_blocklist_entries_by_merchant_id_data_kind(merchant_id, data_kind, limit, offset)
+            .await
     }
 
     async fn list_blocklist_entries_by_merchant_id(
         &self,
-        _merchant_id: &str,
+        merchant_id: &str,
     ) -> CustomResult<Vec<storage::Blocklist>, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .list_blocklist_entries_by_merchant_id(merchant_id)
+            .await
     }
 }
diff --git a/crates/router/src/db/blocklist_fingerprint.rs b/crates/router/src/db/blocklist_fingerprint.rs
index 9da7c7d8fb2..d9107d3d1c1 100644
--- a/crates/router/src/db/blocklist_fingerprint.rs
+++ b/crates/router/src/db/blocklist_fingerprint.rs
@@ -80,16 +80,20 @@ impl BlocklistFingerprintInterface for KafkaStore {
     #[instrument(skip_all)]
     async fn insert_blocklist_fingerprint_entry(
         &self,
-        _pm_fingerprint_new: storage::BlocklistFingerprintNew,
+        pm_fingerprint_new: storage::BlocklistFingerprintNew,
     ) -> CustomResult<storage::BlocklistFingerprint, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .insert_blocklist_fingerprint_entry(pm_fingerprint_new)
+            .await
     }
 
     async fn find_blocklist_fingerprint_by_merchant_id_fingerprint_id(
         &self,
-        _merchant_id: &str,
-        _fingerprint_id: &str,
+        merchant_id: &str,
+        fingerprint: &str,
     ) -> CustomResult<storage::BlocklistFingerprint, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .find_blocklist_fingerprint_by_merchant_id_fingerprint_id(merchant_id, fingerprint)
+            .await
     }
 }
diff --git a/crates/router/src/db/blocklist_lookup.rs b/crates/router/src/db/blocklist_lookup.rs
index 0dfd81c8b8a..f5fb4ea9ed8 100644
--- a/crates/router/src/db/blocklist_lookup.rs
+++ b/crates/router/src/db/blocklist_lookup.rs
@@ -102,24 +102,30 @@ impl BlocklistLookupInterface for KafkaStore {
     #[instrument(skip_all)]
     async fn insert_blocklist_lookup_entry(
         &self,
-        _blocklist_lookup_entry: storage::BlocklistLookupNew,
+        blocklist_lookup_entry: storage::BlocklistLookupNew,
     ) -> CustomResult<storage::BlocklistLookup, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .insert_blocklist_lookup_entry(blocklist_lookup_entry)
+            .await
     }
 
     async fn find_blocklist_lookup_entry_by_merchant_id_fingerprint(
         &self,
-        _merchant_id: &str,
-        _fingerprint: &str,
+        merchant_id: &str,
+        fingerprint: &str,
     ) -> CustomResult<storage::BlocklistLookup, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .find_blocklist_lookup_entry_by_merchant_id_fingerprint(merchant_id, fingerprint)
+            .await
     }
 
     async fn delete_blocklist_lookup_entry_by_merchant_id_fingerprint(
         &self,
-        _merchant_id: &str,
-        _fingerprint: &str,
+        merchant_id: &str,
+        fingerprint: &str,
     ) -> CustomResult<storage::BlocklistLookup, errors::StorageError> {
-        Err(errors::StorageError::KafkaError)?
+        self.diesel_store
+            .delete_blocklist_lookup_entry_by_merchant_id_fingerprint(merchant_id, fingerprint)
+            .await
     }
 }
diff --git a/crates/router/src/openapi.rs b/crates/router/src/openapi.rs
index 79b38e03f31..174926c7d36 100644
--- a/crates/router/src/openapi.rs
+++ b/crates/router/src/openapi.rs
@@ -119,6 +119,9 @@ Never share your secret api keys. Keep them guarded and secure.
         crate::routes::gsm::get_gsm_rule,
         crate::routes::gsm::update_gsm_rule,
         crate::routes::gsm::delete_gsm_rule,
+        crate::routes::blocklist::add_entry_to_blocklist,
+        crate::routes::blocklist::list_blocked_payment_methods,
+        crate::routes::blocklist::remove_entry_from_blocklist
     ),
     components(schemas(
         crate::types::api::refunds::RefundRequest,
@@ -370,7 +373,11 @@ Never share your secret api keys. Keep them guarded and secure.
         api_models::payments::PaymentLinkResponse,
         api_models::payments::RetrievePaymentLinkResponse,
         api_models::payments::PaymentLinkInitiateRequest,
-        api_models::payments::PaymentLinkStatus
+        api_models::payments::PaymentLinkStatus,
+        api_models::blocklist::BlocklistRequest,
+        api_models::blocklist::BlocklistResponse,
+        api_models::blocklist::ListBlocklistQuery,
+        common_enums::enums::BlocklistDataKind
     )),
     modifiers(&SecurityAddon)
 )]
diff --git a/crates/router/src/routes/blocklist.rs b/crates/router/src/routes/blocklist.rs
index 7c268dddeec..9c93f49ab83 100644
--- a/crates/router/src/routes/blocklist.rs
+++ b/crates/router/src/routes/blocklist.rs
@@ -8,6 +8,18 @@ use crate::{
     services::{api, authentication as auth, authorization::permissions::Permission},
 };
 
+#[utoipa::path(
+    post,
+    path = "/blocklist",
+    request_body = BlocklistRequest,
+    responses(
+        (status = 200, description = "Fingerprint Blocked", body = BlocklistResponse),
+        (status = 400, description = "Invalid Data")
+    ),
+    tag = "Blocklist",
+    operation_id = "Block a Fingerprint",
+    security(("api_key" = []))
+)]
 pub async fn add_entry_to_blocklist(
     state: web::Data<AppState>,
     req: HttpRequest,
@@ -32,6 +44,18 @@ pub async fn add_entry_to_blocklist(
     .await
 }
 
+#[utoipa::path(
+    delete,
+    path = "/blocklist",
+    request_body = BlocklistRequest,
+    responses(
+        (status = 200, description = "Fingerprint Unblocked", body = BlocklistResponse),
+        (status = 400, description = "Invalid Data")
+    ),
+    tag = "Blocklist",
+    operation_id = "Unblock a Fingerprint",
+    security(("api_key" = []))
+)]
 pub async fn remove_entry_from_blocklist(
     state: web::Data<AppState>,
     req: HttpRequest,
@@ -56,6 +80,20 @@ pub async fn remove_entry_from_blocklist(
     .await
 }
 
+#[utoipa::path(
+    get,
+    path = "/blocklist",
+    params (
+        ("data_kind" = BlocklistDataKind, Query, description = "Kind of the fingerprint list requested"),
+    ),
+    responses(
+        (status = 200, description = "Blocked Fingerprints", body = BlocklistResponse),
+        (status = 400, description = "Invalid Data")
+    ),
+    tag = "Blocklist",
+    operation_id = "List Blocked fingerprints of a particular kind",
+    security(("api_key" = []))
+)]
 pub async fn list_blocked_payment_methods(
     state: web::Data<AppState>,
     req: HttpRequest,
diff --git a/openapi/openapi_spec.json b/openapi/openapi_spec.json
index 3e582cfed52..c50f687a181 100644
--- a/openapi/openapi_spec.json
+++ b/openapi/openapi_spec.json
@@ -382,6 +382,117 @@
         ]
       }
     },
+    "/blocklist": {
+      "get": {
+        "tags": [
+          "Blocklist"
+        ],
+        "operationId": "List Blocked fingerprints of a particular kind",
+        "parameters": [
+          {
+            "name": "data_kind",
+            "in": "query",
+            "description": "Kind of the fingerprint list requested",
+            "required": true,
+            "schema": {
+              "$ref": "#/components/schemas/BlocklistDataKind"
+            }
+          }
+        ],
+        "responses": {
+          "200": {
+            "description": "Blocked Fingerprints",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/BlocklistResponse"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "Invalid Data"
+          }
+        },
+        "security": [
+          {
+            "api_key": []
+          }
+        ]
+      },
+      "post": {
+        "tags": [
+          "Blocklist"
+        ],
+        "operationId": "Block a Fingerprint",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/BlocklistRequest"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "description": "Fingerprint Blocked",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/BlocklistResponse"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "Invalid Data"
+          }
+        },
+        "security": [
+          {
+            "api_key": []
+          }
+        ]
+      },
+      "delete": {
+        "tags": [
+          "Blocklist"
+        ],
+        "operationId": "Unblock a Fingerprint",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "$ref": "#/components/schemas/BlocklistRequest"
+              }
+            }
+          },
+          "required": true
+        },
+        "responses": {
+          "200": {
+            "description": "Fingerprint Unblocked",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/BlocklistResponse"
+                }
+              }
+            }
+          },
+          "400": {
+            "description": "Invalid Data"
+          }
+        },
+        "security": [
+          {
+            "api_key": []
+          }
+        ]
+      }
+    },
     "/customers": {
       "post": {
         "tags": [
@@ -4035,6 +4146,95 @@
           }
         ]
       },
+      "BlocklistDataKind": {
+        "type": "string",
+        "enum": [
+          "payment_method",
+          "card_bin",
+          "extended_card_bin"
+        ]
+      },
+      "BlocklistRequest": {
+        "oneOf": [
+          {
+            "type": "object",
+            "required": [
+              "type",
+              "data"
+            ],
+            "properties": {
+              "type": {
+                "type": "string",
+                "enum": [
+                  "card_bin"
+                ]
+              },
+              "data": {
+                "type": "string"
+              }
+            }
+          },
+          {
+            "type": "object",
+            "required": [
+              "type",
+              "data"
+            ],
+            "properties": {
+              "type": {
+                "type": "string",
+                "enum": [
+                  "fingerprint"
+                ]
+              },
+              "data": {
+                "type": "string"
+              }
+            }
+          },
+          {
+            "type": "object",
+            "required": [
+              "type",
+              "data"
+            ],
+            "properties": {
+              "type": {
+                "type": "string",
+                "enum": [
+                  "extended_card_bin"
+                ]
+              },
+              "data": {
+                "type": "string"
+              }
+            }
+          }
+        ],
+        "discriminator": {
+          "propertyName": "type"
+        }
+      },
+      "BlocklistResponse": {
+        "type": "object",
+        "required": [
+          "fingerprint_id",
+          "data_kind",
+          "created_at"
+        ],
+        "properties": {
+          "fingerprint_id": {
+            "type": "string"
+          },
+          "data_kind": {
+            "$ref": "#/components/schemas/BlocklistDataKind"
+          },
+          "created_at": {
+            "type": "string",
+            "format": "date-time"
+          }
+        }
+      },
       "BoletoVoucherData": {
         "type": "object",
         "properties": {
@@ -6576,6 +6776,27 @@
           }
         }
       },
+      "ListBlocklistQuery": {
+        "type": "object",
+        "required": [
+          "data_kind"
+        ],
+        "properties": {
+          "data_kind": {
+            "$ref": "#/components/schemas/BlocklistDataKind"
+          },
+          "limit": {
+            "type": "integer",
+            "format": "int32",
+            "minimum": 0
+          },
+          "offset": {
+            "type": "integer",
+            "format": "int32",
+            "minimum": 0
+          }
+        }
+      },
       "MandateAmountData": {
         "type": "object",
         "required": [