Skip to content

feat(connector): [FINIX] webhook + statement descriptor#10758

Merged
Gnanasundari24 merged 13 commits into
mainfrom
finix-fixxes
Dec 24, 2025
Merged

feat(connector): [FINIX] webhook + statement descriptor#10758
Gnanasundari24 merged 13 commits into
mainfrom
finix-fixxes

Conversation

@Nithin1506200

@Nithin1506200 Nithin1506200 commented Dec 22, 2025

Copy link
Copy Markdown
Contributor

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

  • Add statement descriptor
  • implement webhooks (dispute + refund) - Dispute cannot be triggered
  • Added card in pmlist

statement descriptor

Request

{
    "amount": 400,
    "customer_id":"hello_world",
    "currency": "USD",
    "confirm": true,
    "setup_future_usage": "off_session",
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_type": "credit",
    "authentication_type": "no_three_ds",
    "description": "hellow world",
        "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "127.0.0.1",
            "user_agent": "amet irure esse"
        }
    },
    "connector":["finix"],
    "billing": {
        "address": {
            "zip": "560095",
            "country": "IN",
            "first_name": "Sakil",
            "last_name": "Mostak",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "city": "Fasdf"
        }
    },
    "billing_descriptor":{
        "statement_descriptor" :"test"
    },
    "payment_method_data": {
        "card": {
            "card_number": "5200828282828210",
            "card_exp_month": "01",
            "card_exp_year": "2026",
            "card_holder_name": "John Smith",
            "card_cvc": "100"
        }
  
    }
}

Response

{
    "payment_id": "pay_kqBhRZNOmen1b49Yqifv",
    "merchant_id": "merchant_1766136784",
    "status": "succeeded",
    "amount": 400,
    "net_amount": 400,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 400,
    "connector": "finix",
    "client_secret": "pay_kqBhRZNOmen1b49Yqifv_secret_1kJD7s89xJB3JD54e3Yw",
    "created": "2025-12-22T05:19:03.437Z",
    "modified_at": "2025-12-22T05:19:06.279Z",
    "currency": "USD",
    "customer_id": "hello_world",
    "customer": {
        "id": "hello_world",
        "name": null,
        "email": null,
        "phone": null,
        "phone_country_code": null
    },
    "description": "hellow world",
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": "off_session",
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "card",
    "payment_method_data": {
        "card": {
            "last4": "8210",
            "card_type": null,
            "card_network": null,
            "card_issuer": null,
            "card_issuing_country": null,
            "card_isin": "520082",
            "card_extended_bin": null,
            "card_exp_month": "01",
            "card_exp_year": "2026",
            "card_holder_name": "John Smith",
            "payment_checks": null,
            "authentication_data": null
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "Fasdf",
            "country": "IN",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "line3": null,
            "zip": "560095",
            "state": null,
            "first_name": "Sakil",
            "last_name": "Mostak",
            "origin_zip": null
        },
        "phone": null,
        "email": null
    },
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "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,
    "manual_retry_allowed": null,
    "connector_transaction_id": "TRpebYFVqXQFidJ1M4p9P791",
    "frm_message": null,
    "metadata": null,
    "connector_metadata": null,
    "feature_metadata": {
        "redirect_response": null,
        "search_tags": null,
        "apple_pay_recurring_details": null,
        "gateway_system": "direct"
    },
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_EeH8kEuAArq7n3oJ7iX0",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_7F6uC4TvsgC7epx2S06Q",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-12-22T05:34:03.437Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_channel": null,
    "payment_method_id": "pm_qVbUZupn68KS2v7rcQxj",
    "network_transaction_id": null,
    "payment_method_status": "active",
    "updated": "2025-12-22T05:19:06.279Z",
    "split_payments": null,
    "frm_metadata": null,
    "extended_authorization_applied": null,
    "extended_authorization_last_applied_at": null,
    "request_extended_authorization": null,
    "capture_before": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": null,
    "connector_mandate_id": "PIe2SHAdwd8TE2CVv7NyPJsV",
    "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,
    "enable_partial_authorization": null,
    "enable_overcapture": null,
    "is_overcapture_enabled": null,
    "network_details": null,
    "is_stored_credential": null,
    "mit_category": null,
    "billing_descriptor": {
        "name": null,
        "city": null,
        "phone": null,
        "statement_descriptor": "test",
        "statement_descriptor_suffix": null,
        "reference": null
    },
    "tokenization": null,
    "partner_merchant_identifier_details": null,
    "payment_method_tokenization_details": {
        "payment_method_id": "pm_qVbUZupn68KS2v7rcQxj",
        "payment_method_status": "active",
        "psp_tokenization": false,
        "network_tokenization": false,
        "network_transaction_id": null,
        "is_eligible_for_mit_payment": false
    }
}

connector

INFO hyperswitch_interfaces::api_client: raw_connector_request: Object {"amount": Number(400), "currency": String("USD"), "source": String("*** alloc::string::String ***"), "merchant": String("*** alloc::string::String ***"), "tags": Null, "three_d_secure": Null, "idempotency_id": String("pay_oWSIJXJelUeZZPg5T8Dn_1"), "statement_descriptor": String("testdescription")}

Webhook

Create a refund for above payment only and check webhook source verification

curl --location 'localhost:8080/refunds' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_u5fv4daBqwucc4TcH9nSrXWrlhDK3daunVrbo46ywVIqpK9XLP1Qgqc5YSASvfXP' \
--data '{
    "payment_id": "pay_oWSIJXJelUeZZPg5T8Dn",
    "amount":400,
    "metadata":{"store":"ST3298F22322955NDWVDWCWG6"}
}'
{
    "refund_id": "ref_pOLKsxTeUuCzbXGkWEPX",
    "payment_id": "pay_oWSIJXJelUeZZPg5T8Dn",
    "amount": 400,
    "currency": "USD",
    "status": "pending",
    "reason": null,
    "metadata": {
        "store": "ST3298F22322955NDWVDWCWG6"
    },
    "error_message": null,
    "error_code": null,
    "unified_code": null,
    "unified_message": null,
    "created_at": "2025-12-22T05:28:06.079Z",
    "updated_at": "2025-12-22T05:28:07.432Z",
    "connector": "finix",
    "profile_id": "pro_EeH8kEuAArq7n3oJ7iX0",
    "merchant_connector_id": "mca_7F6uC4TvsgC7epx2S06Q",
    "split_refunds": null,
    "issuer_error_code": null,
    "issuer_error_message": null,
    "raw_connector_response": null
}
{
    "id": "event_dcxXgvYhwkMcxXKKWAoNG3",
    "system_generated_idempotency_id": "dcxXgvYhwkMcxXKKWAoNG3",
    "type": "updated",
    "entity": "transfer",
    "occurred_at": "2025-12-22T05:29:04.937754326",
    "_embedded": {
        "transfers": [
            {
                "id": "TRjSEcM56yzdC6fX9Z2vNa9c",
                "created_at": "2025-12-22T05:28:07.25Z",
                "updated_at": "2025-12-22T05:29:03.71Z",
                "additional_buyer_charges": null,
                "additional_healthcare_data": null,
                "additional_purchase_data": null,
                "address_verification": null,
                "amount": 400,
                "amount_requested": 400,
                "application": "APsadfUVzGM6gWeoGCeXSCJs",
                "currency": "USD",
                "destination": "PIf8GRSdpdue3ZTFzBHdkyW5",
                "externally_funded": "UNKNOWN",
                "failure_code": null,
                "failure_message": null,
                "fee": 0,
                "fee_profile": "FPmtT4MYmiAs1qjLjneQmk4d",
                "idempotency_id": null,
                "ip_address_details": null,
                "merchant": "MU3YACSJUhFGMGSbfMPL5xd7",
                "merchant_identity": "ID5WZSCWbsyoBW22x9MrrPn8",
                "messages": [],
                "network_details": null,
                "operation_key": "CARD_NOT_PRESENT_REFUND",
                "parent_transfer": "TRprodxPo31w4yd549zXzjTZ",
                "parent_transfer_trace_id": "f0a246bd-3576-402b-b0d7-136e4eaaaaf4",
                "raw": null,
                "ready_to_settle_at": "2025-12-23T05:29:03.75Z",
                "receipt_last_printed_at": null,
                "security_code_verification": null,
                "source": null,
                "split_transfers": [],
                "state": "SUCCEEDED",
                "statement_descriptor": "FLX*TESTDESCRIPTION",
                "subtype": "API",
                "supplemental_fee": null,
                "tags": {},
                "third_party_details": null,
                "tip_amount": null,
                "trace_id": "c16697c8-95ad-4bfb-ac3b-16ada22ac692",
                "type": "REVERSAL"
            }
        ]
    }
}

without doing psync check status

Screenshot 2025-12-22 at 11 00 04 AM Screenshot 2025-12-19 at 6 13 38 PM Screenshot 2025-12-24 at 2 31 41 PM

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

Motivation and Context

How did you test it?

Checklist

  • 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

@Nithin1506200 Nithin1506200 requested review from a team as code owners December 22, 2025 05:30
@semanticdiff-com

semanticdiff-com Bot commented Dec 22, 2025

Copy link
Copy Markdown

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds webhook support for the FINIX connector, implementing dispute and refund webhooks along with statement descriptor functionality. The implementation includes webhook signature verification using HMAC-SHA256 and proper event type mapping.

  • Webhook implementation for payment, refund, and dispute events with signature verification
  • Statement descriptor support in payment requests
  • Error handling improvements for unsupported flow scenarios

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
crates/hyperswitch_connectors/src/connectors/finix.rs Added webhook handlers including signature verification, event type detection, and dispute details extraction; removed old placeholder webhook implementation; removed ApplePay from supported payment methods
crates/hyperswitch_connectors/src/connectors/finix/transformers.rs Added webhook body parsing, event type mapping, dispute details extraction, and object reference ID resolution for webhooks
crates/hyperswitch_connectors/src/connectors/finix/transformers/request.rs Added statement_descriptor field to payment request structure
crates/hyperswitch_connectors/src/connectors/finix/transformers/response.rs Added webhook-related structs (FinixWebhookBody, FinixEmbedded, FinixDisputes, etc.) and combined payment/webhook response handling
crates/router/src/core/refunds.rs Added error handling for FlowNotSupported connector error with appropriate refund update
crates/router/src/core/refunds_v2.rs Added error handling for FlowNotSupported connector error with appropriate refund update
crates/payment_methods/src/configs/payment_connector_required_fields.rs Added FINIX connector to required fields configuration with basic card fields

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/hyperswitch_connectors/src/connectors/finix/transformers.rs
Comment thread crates/hyperswitch_connectors/src/connectors/finix/transformers.rs
Comment thread crates/hyperswitch_connectors/src/connectors/finix.rs
Comment thread crates/hyperswitch_connectors/src/connectors/finix/transformers/response.rs Outdated
Comment thread crates/hyperswitch_connectors/src/connectors/finix.rs
Comment thread crates/hyperswitch_connectors/src/connectors/finix.rs
Comment thread crates/hyperswitch_connectors/src/connectors/finix/transformers.rs Outdated
Comment thread crates/hyperswitch_connectors/src/connectors/finix/transformers.rs Outdated
Comment thread crates/hyperswitch_connectors/src/connectors/finix.rs
Nithin1506200 and others added 4 commits December 22, 2025 11:09
…s.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@codecov

codecov Bot commented Dec 22, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 221 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@a54dce9). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...tes/hyperswitch_connectors/src/connectors/finix.rs 0.00% 118 Missing ⚠️
...ch_connectors/src/connectors/finix/transformers.rs 0.00% 88 Missing ⚠️
...tors/src/connectors/finix/transformers/response.rs 0.00% 15 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #10758   +/-   ##
=======================================
  Coverage        ?    6.38%           
=======================================
  Files           ?     1264           
  Lines           ?   317865           
  Branches        ?        0           
=======================================
  Hits            ?    20305           
  Misses          ?   297560           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

))
}
FinixEmbedded::Transfers { transfers } => {
let transfer = transfers.get_first_event()?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First event is always the latest event ?

FinixState::FAILED | FinixState::CANCELED | FinixState::UNKNOWN => {
Ok(IncomingWebhookEvent::PaymentIntentCancelFailure)
}
FinixState::PENDING => Ok(IncomingWebhookEvent::PaymentIntentCancelled),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is pending mapped to PaymentIntentCancelled

match transfers.state {
FinixState::PENDING => Ok(IncomingWebhookEvent::PaymentIntentProcessing),
FinixState::SUCCEEDED => Ok(IncomingWebhookEvent::PaymentIntentSuccess),
FinixState::FAILED | FinixState::CANCELED | FinixState::UNKNOWN => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does UNKNOWN FinixState always mean payment intent failure ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Comment thread crates/hyperswitch_connectors/src/connectors/finix.rs
@Nithin1506200 Nithin1506200 requested review from jagan-jaya and removed request for a team December 23, 2025 04:00
Comment on lines +195 to +200
let statement_descriptor = item
.router_data
.request
.billing_descriptor
.clone()
.and_then(|billing_descriptor| billing_descriptor.statement_descriptor);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move this to utils

Ok(format!(
"{}:{}",
&security_header_kvs.timestamp,
String::from_utf8_lossy(request.body)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it ok to use lossy in verification? if failure occurs due to invalid character it won't be visible.

@Nithin1506200 Nithin1506200 linked an issue Dec 23, 2025 that may be closed by this pull request
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Dec 24, 2025
Merged via the queue into main with commit 761183b Dec 24, 2025
44 of 47 checks passed
@Gnanasundari24 Gnanasundari24 deleted the finix-fixxes branch December 24, 2025 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(connector): [FINIX] webhook + statement descriptor

8 participants