-
Notifications
You must be signed in to change notification settings - Fork 3.9k
feat(core): Adding integration for webhooks through UCS #8814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Changed Files
|
…-webhook-integration
…-webhook-integration
}; | ||
|
||
// Make UCS call | ||
if let Some(ucs_client) = &state.grpc_client.unified_connector_service_client { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the function start itself have this check
} else { | ||
// UCS client not available but UCS is configured | ||
// We don't fall back to direct connector processing when UCS is configured | ||
router_env::logger::error!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attach printable already server the logging purpose, so this log will be redundant one
Err(err) => { | ||
// When UCS is configured, we don't fall back to direct connector processing | ||
// since the goal is to remove direct connector code in the future | ||
router_env::logger::error!( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attach printable already server the logging purpose, so this log will be redundant one
|
||
/// Decide whether to use UCS for webhook processing based on configuration | ||
/// This mirrors the pattern used in payment flows for UCS decision making | ||
pub async fn decide_webhook_ucs_processing( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is function really required it is just a wrapper on top should_call_unified_connector_service_for_webhooks this, we can simply call should_call_unified_connector_service_for_webhooks
this itself where decide_webhook_ucs_processing
is called
connector_id: &str, | ||
) -> Result< | ||
PaymentServiceTransformRequest, | ||
error_stack::Report<crate::core::errors::ApiErrorResponse>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error_stack::Report<crate::core::errors::ApiErrorResponse>, | |
error_stack::Report<errors::ApiErrorResponse>, |
error_stack::Report<crate::core::errors::ApiErrorResponse>, | ||
> { | ||
let request_details_grpc = payments_grpc::RequestDetails::foreign_try_from(request_details) | ||
.change_context(crate::core::errors::ApiErrorResponse::InternalServerError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.change_context(crate::core::errors::ApiErrorResponse::InternalServerError) | |
.change_context(errors::ApiErrorResponse::InternalServerError) |
let mut event_object: Box<dyn masking::ErasedMaskSerialize> = Box::new(serde_json::Value::Null); | ||
|
||
let webhook_effect = | ||
if process_webhook_further && !matches!(flow_type, api::WebhookFlow::ReturnResponse) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the matches can move to where process_webhook_further is constructed
response | ||
} | ||
Err(error) => { | ||
return handle_incoming_webhook_error( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid early return here, only for validation at top return can be there, that also using Result with ? operator can be avoid, don't follow return pattern based code, other places also change this pattern
{ | ||
Ok(response) => { | ||
// Extract event object for serialization | ||
event_object = if let Some(transform_data) = webhook_transform_data { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid deep nested if else structure, have handler function to handle response handling, and for option use match and avoid using if let some syntax, chaining and writing in idiomatic way follow those.
89f5c41
to
2730989
Compare
…-webhook-integration
2730989
to
24d1beb
Compare
|
||
/// High-level abstraction for transforming webhooks via UCS | ||
/// This function encapsulates all UCS communication and request building logic | ||
pub async fn transform_webhook_via_ucs( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this function called? I cannot see it being referenced anywhere.
…-webhook-integration
246213b
to
eb6031a
Compare
@AmitsinghTanwar007 Can you please add testing information in the PR description? |
…-webhook-integration
…-webhook-integration
…-webhook-integration
a0b9bd4
…-webhook-integration
…-webhook-integration
…-webhook-integration
…-webhook-integration
…ordea-sepa * 'main' of github.com:juspay/hyperswitch: feat(core): Adding integration for webhooks through UCS (#8814) refactor(euclid): refactor logs for evaluation of equality for dynamic routing evaluate response (#8834) feat(connector): [SIFT] add Connector Template Code (#8488) feat(router): Add tokenization support for proxy and update the route for proxy (#8530) fix(ci): Fix Spell Check For CI Pull Request (#8857) feat(checkbook_io): connector integrate ACH (#8730) fix(connector): Change Refund Reason Type in Adyen (#8849)
Type of Change
Description
Added webhooks integration support in hyperswitch so that for webhooks hyperswitch can call UCS and get the response.
Closes #8880
Additional Changes
Motivation and Context
How did you test it?
Checklist
cargo +nightly fmt --all
cargo clippy
img of hyperswitch

img of UCS

Steps to test webhooks
✅ 1. Create a Sandbox Account on Authorize.Net
Go to: https://developer.authorize.net/hello_world/sandbox/
Sign up for a sandbox account.
After registration, note your:
API Login ID
Transaction Key
(Optional: Public Client Key if needed)
✅ 2. Generate the Signature Key
Log in to the Authorize.Net Sandbox
Navigate to:
Account → Settings → API Credentials & Keys
Under Signature Key, click New Signature Key → click Submit
Copy and save the Signature Key safely — you’ll use it to verify webhooks.
✅ 3. Enable Webhooks in Authorize.Net
In your sandbox account, go to:
Account → Settings → Webhooks
Click Add Endpoint
Endpoint URL:
https://f9475498739857e.ngrok-free.app/webhooks/merchant_id/mca_of_merchant
Event Types: Select the events you want (e.g., net.authorize.payment.authcapture.created)
Save the webhook.
✅ 4. Configure Hyperswitch Merchant with Signature & Credentials
While creating a merchant in Hyperswitch, add the following:
authentication creds
BodyKey
api_key = API Login ID (from step 1)
key1 = Transaction Key
and below you file find a field named merchant secret where you will put the signature
Signature Key (from step 2)
This allows Hyperswitch to authenticate with Authorize.Net and validate incoming webhooks.
✅ 5. Trigger a Payment to Receive Webhooks
Use Hyperswitch to make a test payment through the merchant you configured.
If everything is set up:
Authorize.Net will send a webhook to your endpoint (ngrok URL).
Your backend should receive and verify the webhook using the signature key.
✅ Optional: Use ngrok to Test Webhooks Locally
If running locally:
ngrok http 8080
Use the https://xxxx.ngrok-free.app URL as the webhook URL in step 3.