feat(core): add webhook setup event handler (#9420)

This commit is contained in:
Sakil Mostak
2025-09-22 12:53:00 +05:30
committed by GitHub
parent 2553780051
commit 740f3af643
5 changed files with 39 additions and 1 deletions

View File

@ -66,6 +66,7 @@ pub enum IncomingWebhookEvent {
RecoveryPaymentPending, RecoveryPaymentPending,
#[cfg(all(feature = "revenue_recovery", feature = "v2"))] #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
RecoveryInvoiceCancel, RecoveryInvoiceCancel,
SetupWebhook,
} }
impl IncomingWebhookEvent { impl IncomingWebhookEvent {
@ -143,6 +144,7 @@ pub enum WebhookFlow {
FraudCheck, FraudCheck,
#[cfg(all(feature = "revenue_recovery", feature = "v2"))] #[cfg(all(feature = "revenue_recovery", feature = "v2"))]
Recovery, Recovery,
Setup,
} }
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
@ -297,6 +299,7 @@ impl From<IncomingWebhookEvent> for WebhookFlow {
| IncomingWebhookEvent::RecoveryPaymentFailure | IncomingWebhookEvent::RecoveryPaymentFailure
| IncomingWebhookEvent::RecoveryPaymentPending | IncomingWebhookEvent::RecoveryPaymentPending
| IncomingWebhookEvent::RecoveryPaymentSuccess => Self::Recovery, | IncomingWebhookEvent::RecoveryPaymentSuccess => Self::Recovery,
IncomingWebhookEvent::SetupWebhook => Self::Setup,
} }
} }
} }

View File

@ -756,6 +756,16 @@ impl ConnectorIntegration<Execute, RefundsData, RefundsResponseData> for Wise {}
impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Wise {} impl ConnectorIntegration<RSync, RefundsData, RefundsResponseData> for Wise {}
#[cfg(feature = "payouts")]
fn is_setup_webhook_event(request: &IncomingWebhookRequestDetails<'_>) -> bool {
let test_webhook_header = request
.headers
.get("X-Test-Notification")
.and_then(|header_value| String::from_utf8(header_value.as_bytes().to_vec()).ok());
test_webhook_header == Some("true".to_string())
}
#[async_trait::async_trait] #[async_trait::async_trait]
impl IncomingWebhook for Wise { impl IncomingWebhook for Wise {
fn get_webhook_source_verification_algorithm( fn get_webhook_source_verification_algorithm(
@ -833,6 +843,10 @@ impl IncomingWebhook for Wise {
) -> CustomResult<IncomingWebhookEvent, ConnectorError> { ) -> CustomResult<IncomingWebhookEvent, ConnectorError> {
#[cfg(feature = "payouts")] #[cfg(feature = "payouts")]
{ {
if is_setup_webhook_event(request) {
return Ok(IncomingWebhookEvent::SetupWebhook);
}
let payload: wise::WisePayoutsWebhookBody = request let payload: wise::WisePayoutsWebhookBody = request
.body .body
.parse_struct("WisePayoutsWebhookBody") .parse_struct("WisePayoutsWebhookBody")

View File

@ -271,6 +271,15 @@ async fn incoming_webhooks_core<W: types::OutgoingWebhookType>(
.await? .await?
}; };
// if it is a setup webhook event, return ok status
if webhook_processing_result.event_type == webhooks::IncomingWebhookEvent::SetupWebhook {
return Ok((
services::ApplicationResponse::StatusOk,
WebhookResponseTracker::NoEffect,
serde_json::Value::default(),
));
}
// Update request_details with the appropriate body (decoded for non-UCS, raw for UCS) // Update request_details with the appropriate body (decoded for non-UCS, raw for UCS)
let final_request_details = match &webhook_processing_result.decoded_body { let final_request_details = match &webhook_processing_result.decoded_body {
Some(decoded_body) => IncomingWebhookRequestDetails { Some(decoded_body) => IncomingWebhookRequestDetails {
@ -1443,6 +1452,7 @@ async fn relay_incoming_webhook_flow(
| webhooks::WebhookFlow::ReturnResponse | webhooks::WebhookFlow::ReturnResponse
| webhooks::WebhookFlow::BankTransfer | webhooks::WebhookFlow::BankTransfer
| webhooks::WebhookFlow::Mandate | webhooks::WebhookFlow::Mandate
| webhooks::WebhookFlow::Setup
| webhooks::WebhookFlow::ExternalAuthentication | webhooks::WebhookFlow::ExternalAuthentication
| webhooks::WebhookFlow::FraudCheck => Err(errors::ApiErrorResponse::NotSupported { | webhooks::WebhookFlow::FraudCheck => Err(errors::ApiErrorResponse::NotSupported {
message: "Relay webhook flow types not supported".to_string(), message: "Relay webhook flow types not supported".to_string(),

View File

@ -221,6 +221,15 @@ async fn incoming_webhooks_core<W: types::OutgoingWebhookType>(
}; };
logger::info!(event_type=?event_type); logger::info!(event_type=?event_type);
// if it is a setup webhook event, return ok status
if event_type == webhooks::IncomingWebhookEvent::SetupWebhook {
return Ok((
services::ApplicationResponse::StatusOk,
WebhookResponseTracker::NoEffect,
serde_json::Value::default(),
));
}
let is_webhook_event_supported = !matches!( let is_webhook_event_supported = !matches!(
event_type, event_type,
webhooks::IncomingWebhookEvent::EventNotSupported webhooks::IncomingWebhookEvent::EventNotSupported
@ -360,6 +369,7 @@ async fn incoming_webhooks_core<W: types::OutgoingWebhookType>(
api::WebhookFlow::ExternalAuthentication => todo!(), api::WebhookFlow::ExternalAuthentication => todo!(),
api::WebhookFlow::FraudCheck => todo!(), api::WebhookFlow::FraudCheck => todo!(),
api::WebhookFlow::Setup => WebhookResponseTracker::NoEffect,
#[cfg(feature = "payouts")] #[cfg(feature = "payouts")]
api::WebhookFlow::Payout => todo!(), api::WebhookFlow::Payout => todo!(),

View File

@ -1455,7 +1455,8 @@ impl RecoveryAction {
| webhooks::IncomingWebhookEvent::PayoutCancelled | webhooks::IncomingWebhookEvent::PayoutCancelled
| webhooks::IncomingWebhookEvent::PayoutCreated | webhooks::IncomingWebhookEvent::PayoutCreated
| webhooks::IncomingWebhookEvent::PayoutExpired | webhooks::IncomingWebhookEvent::PayoutExpired
| webhooks::IncomingWebhookEvent::PayoutReversed => { | webhooks::IncomingWebhookEvent::PayoutReversed
| webhooks::IncomingWebhookEvent::SetupWebhook => {
common_types::payments::RecoveryAction::InvalidAction common_types::payments::RecoveryAction::InvalidAction
} }
webhooks::IncomingWebhookEvent::RecoveryPaymentFailure => match attempt_triggered_by { webhooks::IncomingWebhookEvent::RecoveryPaymentFailure => match attempt_triggered_by {