Bug: [FEATURE] [CONNECTOR: PAYLOAD] Add Webhook support



connector does not support signature verification.

- https://docs.payload.com/apis/webhooks/
- https://docs.payload.com/apis/webhooks/triggers/
- https://docs.payload.com/apis/webhooks/oauth/
- https://docs.payload.com/apis/object-reference/webhook/
- https://docs.payload.com/apis/object-reference/webhook-logs/
- https://docs.payload.com/apis/authentication/
- https://docs.payload.com/apis/api-design/
diff --git a/crates/api_models/src/webhooks.rs b/crates/api_models/src/webhooks.rs
index 177310de18f..75af0b19cf2 100644
--- a/crates/api_models/src/webhooks.rs
+++ b/crates/api_models/src/webhooks.rs
@@ -10,9 +10,9 @@ use crate::{disputes, enums as api_enums, mandates, payments, refunds};
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Copy)]
 #[serde(rename_all = "snake_case")]
 pub enum IncomingWebhookEvent {
-    /// Authorization + Capture success
-    PaymentIntentFailure,
     /// Authorization + Capture failure
+    PaymentIntentFailure,
+    /// Authorization + Capture success
     PaymentIntentSuccess,
     PaymentIntentProcessing,
     PaymentIntentPartiallyFunded,
diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml
index a8a0baa2661..cdf94d6e439 100644
--- a/crates/connector_configs/toml/development.toml
+++ b/crates/connector_configs/toml/development.toml
@@ -6328,8 +6328,7 @@ type="Text"
   payment_method_type = "Visa"
 [payload.connector_auth.HeaderKey]
 api_key="API Key"
-[payload.connector_webhook_details]
-merchant_secret="Source verification key"
+
 [silverflow]
 [silverflow.connector_auth.BodyKey]
 api_key="API Key"
diff --git a/crates/connector_configs/toml/production.toml b/crates/connector_configs/toml/production.toml
index a22b50a9b4f..b9a98f5aedd 100644
--- a/crates/connector_configs/toml/production.toml
+++ b/crates/connector_configs/toml/production.toml
@@ -4935,10 +4935,8 @@ type="Text"
   payment_method_type = "Visa"
 [payload.connector_auth.HeaderKey]
 api_key="API Key"
-[payload.connector_webhook_details]
-merchant_secret="Source verification key"
 
 [silverflow]
 [silverflow.connector_auth.BodyKey]
 api_key="API Key"
-key1="Secret Key"
\ No newline at end of file
+key1="Secret Key"
diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml
index d7026129699..21801d380b5 100644
--- a/crates/connector_configs/toml/sandbox.toml
+++ b/crates/connector_configs/toml/sandbox.toml
@@ -6302,8 +6302,7 @@ type="Text"
   payment_method_type = "Visa"
 [payload.connector_auth.HeaderKey]
 api_key="API Key"
-[payload.connector_webhook_details]
-merchant_secret="Source verification key"
+
 [silverflow]
 [silverflow.connector_auth.BodyKey]
 api_key="API Key"
diff --git a/crates/hyperswitch_connectors/src/connectors/payload.rs b/crates/hyperswitch_connectors/src/connectors/payload.rs
index c1f1516e63b..03c41d367aa 100644
--- a/crates/hyperswitch_connectors/src/connectors/payload.rs
+++ b/crates/hyperswitch_connectors/src/connectors/payload.rs
@@ -8,12 +8,12 @@ use base64::Engine;
 use common_enums::enums;
 use common_utils::{
     consts::BASE64_ENGINE,
-    errors::CustomResult,
-    ext_traits::BytesExt,
+    errors::{CustomResult, ReportSwitchExt},
+    ext_traits::{ByteSliceExt, BytesExt},
     request::{Method, Request, RequestBuilder, RequestContent},
     types::{AmountConvertor, StringMajorUnit, StringMajorUnitForConnector},
 };
-use error_stack::{report, ResultExt};
+use error_stack::ResultExt;
 use hyperswitch_domain_models::{
     payment_method_data::PaymentMethodData,
     router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData},
@@ -47,7 +47,7 @@ use hyperswitch_interfaces::{
     types::{self, PaymentsVoidType, Response},
     webhooks,
 };
-use masking::{ExposeInterface, Mask};
+use masking::{ExposeInterface, Mask, Secret};
 use transformers as payload;
 
 use crate::{constants::headers, types::ResponseRouterData, utils};
@@ -195,7 +195,18 @@ impl ConnectorIntegration<Session, PaymentsSessionData, PaymentsResponseData> fo
 
 impl ConnectorIntegration<AccessTokenAuth, AccessTokenRequestData, AccessToken> for Payload {}
 
-impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Payload {}
+impl ConnectorIntegration<SetupMandate, SetupMandateRequestData, PaymentsResponseData> for Payload {
+    fn build_request(
+        &self,
+        _req: &RouterData<SetupMandate, SetupMandateRequestData, PaymentsResponseData>,
+        _connectors: &Connectors,
+    ) -> CustomResult<Option<Request>, errors::ConnectorError> {
+        Err(
+            errors::ConnectorError::NotImplemented("Setup Mandate flow for Payload".to_string())
+                .into(),
+        )
+    }
+}
 
 impl ConnectorIntegration<Authorize, PaymentsAuthorizeData, PaymentsResponseData> for Payload {
     fn get_headers(
@@ -701,25 +712,95 @@ impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Payload {
 
 #[async_trait::async_trait]
 impl webhooks::IncomingWebhook for Payload {
-    fn get_webhook_object_reference_id(
+    async fn verify_webhook_source(
         &self,
         _request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        _merchant_id: &common_utils::id_type::MerchantId,
+        _connector_webhook_details: Option<common_utils::pii::SecretSerdeValue>,
+        _connector_account_details: common_utils::crypto::Encryptable<Secret<serde_json::Value>>,
+        _connector_label: &str,
+    ) -> CustomResult<bool, errors::ConnectorError> {
+        // Payload does not support source verification
+        // It does, but the client id and client secret generation is not possible at present
+        // It requires OAuth connect which falls under Access Token flow and it also requires multiple calls to be made
+        // We return false just so that a PSync call is triggered internally
+        Ok(false)
+    }
+
+    fn get_webhook_object_reference_id(
+        &self,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
-        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
+        let webhook_body: responses::PayloadWebhookEvent = request
+            .body
+            .parse_struct("PayloadWebhookEvent")
+            .change_context(errors::ConnectorError::WebhookBodyDecodingFailed)?;
+
+        let reference_id = match webhook_body.trigger {
+            responses::PayloadWebhooksTrigger::Payment
+            | responses::PayloadWebhooksTrigger::Processed
+            | responses::PayloadWebhooksTrigger::Authorized
+            | responses::PayloadWebhooksTrigger::Credit
+            | responses::PayloadWebhooksTrigger::Reversal
+            | responses::PayloadWebhooksTrigger::Void
+            | responses::PayloadWebhooksTrigger::AutomaticPayment
+            | responses::PayloadWebhooksTrigger::Decline
+            | responses::PayloadWebhooksTrigger::Deposit
+            | responses::PayloadWebhooksTrigger::Reject
+            | responses::PayloadWebhooksTrigger::PaymentActivationStatus
+            | responses::PayloadWebhooksTrigger::PaymentLinkStatus
+            | responses::PayloadWebhooksTrigger::ProcessingStatus
+            | responses::PayloadWebhooksTrigger::BankAccountReject
+            | responses::PayloadWebhooksTrigger::Chargeback
+            | responses::PayloadWebhooksTrigger::ChargebackReversal
+            | responses::PayloadWebhooksTrigger::TransactionOperation
+            | responses::PayloadWebhooksTrigger::TransactionOperationClear => {
+                api_models::webhooks::ObjectReferenceId::PaymentId(
+                    api_models::payments::PaymentIdType::ConnectorTransactionId(
+                        webhook_body
+                            .triggered_on
+                            .transaction_id
+                            .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
+                    ),
+                )
+            }
+
+            responses::PayloadWebhooksTrigger::Refund => {
+                api_models::webhooks::ObjectReferenceId::RefundId(
+                    api_models::webhooks::RefundIdType::ConnectorRefundId(
+                        webhook_body
+                            .triggered_on
+                            .transaction_id
+                            .ok_or(errors::ConnectorError::WebhookReferenceIdNotFound)?,
+                    ),
+                )
+            }
+        };
+
+        Ok(reference_id)
     }
 
     fn get_webhook_event_type(
         &self,
-        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
-        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
+        let webhook_body: responses::PayloadWebhookEvent =
+            request.body.parse_struct("PayloadWebhookEvent").switch()?;
+
+        Ok(api_models::webhooks::IncomingWebhookEvent::from(
+            webhook_body.trigger,
+        ))
     }
 
     fn get_webhook_resource_object(
         &self,
-        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
+        request: &webhooks::IncomingWebhookRequestDetails<'_>,
     ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
-        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
+        let webhook_body: responses::PayloadWebhookEvent = request
+            .body
+            .parse_struct("PayloadWebhookEvent")
+            .change_context(errors::ConnectorError::WebhookReferenceIdNotFound)?;
+        Ok(Box::new(webhook_body))
     }
 }
 
@@ -782,7 +863,11 @@ static PAYLOAD_CONNECTOR_INFO: ConnectorInfo = ConnectorInfo {
     connector_type: enums::PaymentConnectorCategory::PaymentGateway,
 };
 
-static PAYLOAD_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 0] = [];
+static PAYLOAD_SUPPORTED_WEBHOOK_FLOWS: [enums::EventClass; 3] = [
+    enums::EventClass::Disputes,
+    enums::EventClass::Payments,
+    enums::EventClass::Refunds,
+];
 
 impl ConnectorSpecifications for Payload {
     fn get_connector_about(&self) -> Option<&'static ConnectorInfo> {
diff --git a/crates/hyperswitch_connectors/src/connectors/payload/responses.rs b/crates/hyperswitch_connectors/src/connectors/payload/responses.rs
index 63699d09810..444e794e6bd 100644
--- a/crates/hyperswitch_connectors/src/connectors/payload/responses.rs
+++ b/crates/hyperswitch_connectors/src/connectors/payload/responses.rs
@@ -38,6 +38,7 @@ pub struct PayloadCardsResponseData {
     #[serde(rename = "id")]
     pub transaction_id: String,
     pub payment_method_id: Option<Secret<String>>,
+    // Connector customer id
     pub processing_id: Option<String>,
     pub processing_method_id: Option<String>,
     pub ref_number: Option<String>,
@@ -84,6 +85,7 @@ pub struct PayloadRefundResponse {
     pub transaction_id: String,
     pub ledger: Vec<RefundsLedger>,
     pub payment_method_id: Option<Secret<String>>,
+    // Connector customer id
     pub processing_id: Option<String>,
     pub ref_number: Option<String>,
     pub status: RefundStatus,
@@ -99,3 +101,51 @@ pub struct PayloadErrorResponse {
     /// Payload returns arbitrary details in JSON format
     pub details: Option<serde_json::Value>,
 }
+
+#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum PayloadWebhooksTrigger {
+    Payment,
+    Processed,
+    Authorized,
+    Credit,
+    Refund,
+    Reversal,
+    Void,
+    AutomaticPayment,
+    Decline,
+    Deposit,
+    Reject,
+    #[serde(rename = "payment_activation:status")]
+    PaymentActivationStatus,
+    #[serde(rename = "payment_link:status")]
+    PaymentLinkStatus,
+    ProcessingStatus,
+    BankAccountReject,
+    Chargeback,
+    ChargebackReversal,
+    #[serde(rename = "transaction:operation")]
+    TransactionOperation,
+    #[serde(rename = "transaction:operation:clear")]
+    TransactionOperationClear,
+}
+
+// Webhook response structures
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PayloadWebhookEvent {
+    pub object: String, // Added to match actual webhook structure
+    pub trigger: PayloadWebhooksTrigger,
+    pub webhook_id: String,
+    pub triggered_at: String, // Added to match actual webhook structure
+    // Webhooks Payload
+    pub triggered_on: PayloadEventDetails,
+    pub url: String,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct PayloadEventDetails {
+    #[serde(rename = "id")]
+    pub transaction_id: Option<String>,
+    pub object: String,
+    pub value: Option<serde_json::Value>, // Changed to handle any value type including null
+}
diff --git a/crates/hyperswitch_connectors/src/connectors/payload/transformers.rs b/crates/hyperswitch_connectors/src/connectors/payload/transformers.rs
index 994b4a7cfce..707a8db9366 100644
--- a/crates/hyperswitch_connectors/src/connectors/payload/transformers.rs
+++ b/crates/hyperswitch_connectors/src/connectors/payload/transformers.rs
@@ -1,20 +1,24 @@
+use api_models::webhooks::IncomingWebhookEvent;
 use common_enums::enums;
 use common_utils::types::StringMajorUnit;
 use hyperswitch_domain_models::{
     payment_method_data::PaymentMethodData,
-    router_data::{ConnectorAuthType, RouterData},
+    router_data::{ConnectorAuthType, ErrorResponse, RouterData},
     router_flow_types::refunds::{Execute, RSync},
     router_request_types::ResponseId,
     router_response_types::{PaymentsResponseData, RefundsResponseData},
     types::{PaymentsAuthorizeRouterData, PaymentsCaptureRouterData, RefundsRouterData},
 };
-use hyperswitch_interfaces::errors;
+use hyperswitch_interfaces::{
+    consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE},
+    errors,
+};
 use masking::Secret;
 
 use super::{requests, responses};
 use crate::{
     types::{RefundsResponseRouterData, ResponseRouterData},
-    utils::{is_manual_capture, CardData, RouterData as OtherRouterData},
+    utils::{is_manual_capture, AddressDetailsData, CardData, RouterData as OtherRouterData},
 };
 
 //TODO: Fill the struct with respective fields
@@ -56,12 +60,20 @@ impl TryFrom<&PayloadRouterData<&PaymentsAuthorizeRouterData>>
                     cvc: req_card.card_cvc,
                 };
                 let address = item.router_data.get_billing_address()?;
+
+                // Check for required fields and fail if they're missing
+                let city = address.get_city()?.to_owned();
+                let country = address.get_country()?.to_owned();
+                let postal_code = address.get_zip()?.to_owned();
+                let state_province = address.get_state()?.to_owned();
+                let street_address = address.get_line1()?.to_owned();
+
                 let billing_address = requests::BillingAddress {
-                    city: address.city.clone().unwrap_or_default(),
-                    country: address.country.unwrap_or_default(),
-                    postal_code: address.zip.clone().unwrap_or_default(),
-                    state_province: address.state.clone().unwrap_or_default(),
-                    street_address: address.line1.clone().unwrap_or_default(),
+                    city,
+                    country,
+                    postal_code,
+                    state_province,
+                    street_address,
                 };
 
                 // For manual capture, set status to "authorized"
@@ -127,13 +139,29 @@ impl<F, T>
     ) -> Result<Self, Self::Error> {
         match item.response.clone() {
             responses::PayloadPaymentsResponse::PayloadCardsResponse(response) => {
-                let payment_status = response.status;
-                let transaction_id = response.transaction_id;
-
-                Ok(Self {
-                    status: common_enums::AttemptStatus::from(payment_status),
-                    response: Ok(PaymentsResponseData::TransactionResponse {
-                        resource_id: ResponseId::ConnectorTransactionId(transaction_id),
+                let status = enums::AttemptStatus::from(response.status);
+                let connector_customer = response.processing_id.clone();
+                let response_result = if status == enums::AttemptStatus::Failure {
+                    Err(ErrorResponse {
+                        attempt_status: None,
+                        code: response
+                            .status_code
+                            .clone()
+                            .unwrap_or_else(|| NO_ERROR_CODE.to_string()),
+                        message: response
+                            .status_message
+                            .clone()
+                            .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()),
+                        reason: response.status_message,
+                        status_code: item.http_code,
+                        connector_transaction_id: Some(response.transaction_id.clone()),
+                        network_decline_code: None,
+                        network_advice_code: None,
+                        network_error_message: None,
+                    })
+                } else {
+                    Ok(PaymentsResponseData::TransactionResponse {
+                        resource_id: ResponseId::ConnectorTransactionId(response.transaction_id),
                         redirection_data: Box::new(None),
                         mandate_reference: Box::new(None),
                         connector_metadata: None,
@@ -141,7 +169,12 @@ impl<F, T>
                         connector_response_reference_id: response.ref_number,
                         incremental_authorization_allowed: None,
                         charges: None,
-                    }),
+                    })
+                };
+                Ok(Self {
+                    status,
+                    response: response_result,
+                    connector_customer,
                     ..item.data
                 })
             }
@@ -225,3 +258,41 @@ impl TryFrom<RefundsResponseRouterData<RSync, responses::PayloadRefundResponse>>
         })
     }
 }
+
+// Webhook transformations
+impl From<responses::PayloadWebhooksTrigger> for IncomingWebhookEvent {
+    fn from(trigger: responses::PayloadWebhooksTrigger) -> Self {
+        match trigger {
+            // Payment Success Events
+            responses::PayloadWebhooksTrigger::Processed => Self::PaymentIntentSuccess,
+            responses::PayloadWebhooksTrigger::Authorized => {
+                Self::PaymentIntentAuthorizationSuccess
+            }
+            // Payment Processing Events
+            responses::PayloadWebhooksTrigger::Payment
+            | responses::PayloadWebhooksTrigger::AutomaticPayment => Self::PaymentIntentProcessing,
+            // Payment Failure Events
+            responses::PayloadWebhooksTrigger::Decline
+            | responses::PayloadWebhooksTrigger::Reject
+            | responses::PayloadWebhooksTrigger::BankAccountReject => Self::PaymentIntentFailure,
+            responses::PayloadWebhooksTrigger::Void
+            | responses::PayloadWebhooksTrigger::Reversal => Self::PaymentIntentCancelled,
+            // Refund Events
+            responses::PayloadWebhooksTrigger::Refund => Self::RefundSuccess,
+            // Dispute Events
+            responses::PayloadWebhooksTrigger::Chargeback => Self::DisputeOpened,
+            responses::PayloadWebhooksTrigger::ChargebackReversal => Self::DisputeWon,
+            // Other payment-related events
+            // Events not supported by our standard flows
+            responses::PayloadWebhooksTrigger::PaymentActivationStatus
+            | responses::PayloadWebhooksTrigger::Credit
+            | responses::PayloadWebhooksTrigger::Deposit
+            | responses::PayloadWebhooksTrigger::PaymentLinkStatus
+            | responses::PayloadWebhooksTrigger::ProcessingStatus
+            | responses::PayloadWebhooksTrigger::TransactionOperation
+            | responses::PayloadWebhooksTrigger::TransactionOperationClear => {
+                Self::EventNotSupported
+            }
+        }
+    }
+}

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

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

## Description
<!-- Describe your changes in detail -->

This PR:
- Adds support for webhooks to Payload connector. The connector does not support source verification. 
- Address Cypress comments that was asked in #8545.
- Fixes setup mandate not throwing `501`

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [x] 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`
-->

1. crates/connector_configs/toml/development.toml
2. crates/connector_configs/toml/production.toml
3. crates/connector_configs/toml/sandbox.toml

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

Closes #8557

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

<details>

<summary>Setup Webhooks in Merchant Account</summary>

```curl
curl --location 'https://pix-mbp.orthrus-monster.ts.net/accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: test_admin' \
--data-raw '{
    "merchant_id": "postman_merchant_GHAction_1751796781",
    "locker_id": "m0010",
    "merchant_name": "NewAge Retailer",
    "merchant_details": {
        "primary_contact_person": "John Test",
        "primary_email": "JohnTest@test.com",
        "primary_phone": "sunt laborum",
        "secondary_contact_person": "John Test2",
        "secondary_email": "JohnTest2@test.com",
        "secondary_phone": "cillum do dolor id",
        "website": "www.example.com",
        "about_business": "Online Retail with a wide selection of organic products for North America"
        ,
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US"
        }
    },
    "return_url": "https://duck.com",
    "webhook_details": {
        "webhook_url": "https://webhook.site/02225e46-1016-4c2c-a492-efaaa5d41cf3",
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123"
    },
    "sub_merchants_enabled": false,
    "metadata": {
        "city": "NY",
        "unit": "245"
    },
    "primary_business_details": [
        {
            "country": "US",
            "business": "default"
        }
    ]
}'
```
```json
{
    "merchant_id": "postman_merchant_GHAction_1751738744",
    "merchant_name": "NewAge Retailer",
    "return_url": "https://duck.com/",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "wsJ8BLD1TuNdKjCCMpoonWCJduaS9CT1EperKUJVLOQftECdAK7d4a7otMdv2EMq",
    "redirect_to_merchant_with_http_post": false,
    "merchant_details": {
        "primary_contact_person": "John Test",
        "primary_phone": "sunt laborum",
        "primary_email": "JohnTest@test.com",
        "secondary_contact_person": "John Test2",
        "secondary_phone": "cillum do dolor id",
        "secondary_email": "JohnTest2@test.com",
        "website": "www.example.com",
        "about_business": "Online Retail with a wide selection of organic products for North America",
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": null,
            "last_name": null
        }
    },
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site/02225e46-1016-4c2c-a492-efaaa5d41cf3",
        "payment_created_enabled": null,
        "payment_succeeded_enabled": null,
        "payment_failed_enabled": null,
        "payment_statuses_enabled": null,
        "refund_statuses_enabled": null,
        "payout_statuses_enabled": null
    },
    "payout_routing_algorithm": null,
    "sub_merchants_enabled": false,
    "parent_merchant_id": null,
    "publishable_key": "pk_dev_4ab91f8e35424d11acdd8c639a974f0c",
    "metadata": {
        "city": "NY",
        "unit": "245",
        "compatible_connector": null
    },
    "locker_id": "m0010",
    "primary_business_details": [
        {
            "country": "US",
            "business": "default"
        }
    ],
    "frm_routing_algorithm": null,
    "organization_id": "org_oZUZY7YEM9gts3EC4kbC",
    "is_recon_enabled": false,
    "default_profile": "pro_ZVgp4CWyKZKnx99AD7BL",
    "recon_status": "not_requested",
    "pm_collect_link_config": null,
    "product_type": "orchestration",
    "merchant_account_type": "standard"
}
```

</details>

<details>

<summary>Setup Webhooks at Connector's end below commands by referring to the [trigger docs](https://docs.payload.com/apis/webhooks/triggers/)</summary>

```curl
curl --location 'https://api.payload.com/webhooks/' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: api_key' \
--data-urlencode 'trigger=processed' \
--data-urlencode 'url=<base_url>/webhooks/<merchant_id>/<mca_id/connector_name>'
```
```json
{
    "attrs": null,
    "created_at": "Sun, 06 Jul 2025 07:24:29 GMT",
    "id": "<webhook_id>",
    "modified_at": "Sun, 06 Jul 2025 07:24:29 GMT",
    "oauth_params": null,
    "object": "webhook",
    "retries": 0,
    "trigger": "processed",
    "url": "<base_url>/webhooks/<merchant_id>/<mca_id/connector_name>"
}
```

</details>

<details>

<summary>Make Payment</summary>

```curl
curl --location 'https://pix-mbp.orthrus-monster.ts.net/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Accept-Language: ja' \
--header 'api-key: dev_PCJYsjpYCN6C9ECuYT5g9LR1epAx5Jeqc7WpsXzoxpTbCcHqSqJ5CdUPnxdEh29y' \
--data-raw '{
    "amount": 40,
    "currency": "USD",
    "confirm": true,
    "capture_method": "automatic",
    "capture_on": "2022-09-10T10:11:12Z",
    "amount_to_capture": 40,
    "customer_id": "customer",
    "email": "guesjhvghht@example.com",
    "phone": "999999999",
    "phone_country_code": "+1",
    "description": "Its my first payment request",
    "authentication_type": "no_three_ds",
    "return_url": "https://duck.com",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "Joseph Doe",
            "card_cvc": "123"
        }
    },
    "billing": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US"
            ,
            "first_name": "PiX"
            ,
            "last_name": "THE"
        }
    },
    "shipping": {
        "address": {
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US",
            "first_name": "PiX"
        }
    },
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "browser_info": {
        "color_depth": 24,
        "java_enabled": true,
        "java_script_enabled": true,
        "language": "en-GB",
        "screen_height": 720,
        "screen_width": 1280,
        "time_zone": -330,
        "ip_address": "208.127.127.193",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0"
    }
}'
```
```json
{
    "payment_id": "pay_IMknbnvAK8MSCd1WXmrI",
    "merchant_id": "postman_merchant_GHAction_1751797139",
    "status": "succeeded",
    "amount": 40,
    "net_amount": 40,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 40,
    "connector": "payload",
    "client_secret": "pay_IMknbnvAK8MSCd1WXmrI_secret_Gj1Vtt77ai6KPzJ5AGHC",
    "created": "2025-07-06T10:20:56.697Z",
    "currency": "USD",
    "customer_id": "customer",
    "customer": {
        "id": "customer",
        "name": null,
        "email": "guesjhvghht@example.com",
        "phone": "999999999",
        "phone_country_code": "+1"
    },
    "description": "Its my first payment request",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "1111",
            "card_type": "CREDIT",
            "card_network": "Visa",
            "card_issuer": "JP Morgan",
            "card_issuing_country": "INDIA",
            "card_isin": "411111",
            "card_extended_bin": null,
            "card_exp_month": "10",
            "card_exp_year": "25",
            "card_holder_name": "Joseph Doe",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": null
        },
        "phone": null,
        "email": null
    },
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "PiX",
            "last_name": "THE"
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": "guesjhvghht@example.com",
    "name": null,
    "phone": "999999999",
    "return_url": "https://duck.com/",
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": "joseph",
    "statement_descriptor_suffix": "JS",
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": "credit",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "customer",
        "created_at": 1751797256,
        "expires": 1751800856,
        "secret": "epk_d97417b2937b49a98be4f3bab68e34b1"
    },
    "manual_retry_allowed": false,
    "connector_transaction_id": "txn_3ephQ2TpDLsQSnekEK1a8",
    "frm_message": null,
    "metadata": {
        "udf1": "value1",
        "login_date": "2019-09-10T10:11:12Z",
        "new_customer": "true"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": "PL-M3P-9HY-9T7",
    "payment_link": null,
    "profile_id": "pro_VaPL7y7qI4IY0F9cvRU2",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_KOpDieOFRmWvh26OJ9OH",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-07-06T10:35:56.697Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-GB",
        "time_zone": -330,
        "ip_address": "208.127.127.193",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0",
        "color_depth": 24,
        "java_enabled": true,
        "screen_width": 1280,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "screen_height": 720,
        "java_script_enabled": true
    },
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-07-06T10:20:57.632Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": null,
    "card_discovery": "manual",
    "force_3ds_challenge": false,
    "force_3ds_challenge_trigger": false,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "is_iframe_redirection_enabled": null,
    "whole_connector_response": null
}
```

</details>

<details>

<summary>Check website for outgoing webhooks</summary>

<img width="1695" alt="image" src="https://github.com/user-attachments/assets/5a6890aa-85de-4b31-9337-d001e61b5236" />

</details>

<details>

<summary>Check logs for incoming webhooks</summary>

<img width="1286" alt="image" src="https://github.com/user-attachments/assets/0963fdfc-d21f-4acf-b795-b9d829409a75" />
<img width="1291" alt="image" src="https://github.com/user-attachments/assets/b12582e5-b732-427b-abf3-f31582fa1b92" />

</details>


<details>

<summary>Cypress</summary>

`19` failures is because the connector marked them as duplicate even with 15 seconds timeout.

<img width="553" alt="image" src="https://github.com/user-attachments/assets/b217d420-a5ce-4a68-b0cc-89cd920049ba" />


</details>

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

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

<!-- @coderabbitai ignore -->
