Skip to content

refactor(core): introduce new field cardFundingSource to GooglePayPaymentMethodData#9571

Merged
Gnanasundari24 merged 8 commits intomainfrom
core/googlepay-new-field
Oct 1, 2025
Merged

refactor(core): introduce new field cardFundingSource to GooglePayPaymentMethodData#9571
Gnanasundari24 merged 8 commits intomainfrom
core/googlepay-new-field

Conversation

@pixincreate
Copy link
Member

@pixincreate pixincreate commented Sep 25, 2025

Type of Change

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

Description

google recently introduced new field called cardFundingSource. It is an upcoming gpay api change

it takes an enum:

  • UNKNOWN
  • CREDIT
  • DEBIT
  • PREPAID

google has mentioned it on their api reference that this info will be none on production until q4 of 2025.

Additional Changes

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

Motivation and Context

this new information will enable us to implement more sophisticated business logic such as routing, analytics, fraud management etc, tailored to different card types.

closes #9570

How did you test it?

curl --location 'http://localhost:8080/payments/pay_P9LfwQUR2raIVIvvY1pb/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_uDP0kqyLTXnlN5jYassJphQYXWAJEywH4BSkKQXtJoOYLCs71FGNCifuORqq9w2q' \
--data '{
	"confirm": true,
	"payment_method": "wallet",
	"payment_method_type": "google_pay",
	"payment_method_data": {
	    "wallet": {
	        "google_pay": {
	            "description": "Visa •••• 1111",
	            "tokenization_data": {
	                "type": "PAYMENT_GATEWAY",
	                "token": "{\"signature\":\"MEUCIAT1vH7oE0bc1FR..."
	            },
	            "type": "CARD",
	            "info": {
	                "card_network": "VISA",
	                "card_details": "1111"
	            }
	        }
	    }
	},
	"browser_info": {
		"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
		"accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
		"language": "nl-NL",
		"color_depth": 24,
		"screen_height": 723,
		"screen_width": 1536,
		"time_zone": 0,
		"java_enabled": true,
		"java_script_enabled": true,
		"ip_address": "127.0.0.1"
	},
	"billing": {
		"address": {
			"line1": "1467",
			"line2": "Harrison Street",
			"line3": "Harrison Street",
			"city": "San Fransico",
			"state": "California",
			"zip": "94122",
			"country": "US",
			"first_name": "John",
			"last_name": "Doe"
		}
	},
	"shipping": {
		"address": {
			"line1": "1467",
			"line2": "Harrison Street",
			"line3": "Harrison Street",
			"city": "San Fransico",
			"state": "California",
			"zip": "94122",
			"country": "US",
			"first_name": "John",
			"last_name": "Doe"
		}
	}
}'
{
	"payment_id": "pay_P9LfwQUR2raIVIvvY1pb",
	"merchant_id": "postman_merchant_GHAction_1758879946",
	"status": "succeeded",
	"amount": 1000,
	"net_amount": 1000,
	"shipping_cost": null,
	"amount_capturable": 0,
	"amount_received": 1000,
	"connector": "cybersource",
	"client_secret": "pay_P9LfwQUR2raIVIvvY1pb_secret_NWAWTxJGdQ0z1OAj5wAZ",
	"created": "2025-09-26T09:45:52.604Z",
	"currency": "USD",
	"customer_id": "StripeCustomer",
	"customer": {
		"id": "StripeCustomer",
		"name": "John Doe",
		"email": "likhin.bopanna@gmail.com",
		"phone": "999999999",
		"phone_country_code": "+65"
	},
	"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": "wallet",
	"payment_method_data": {
		"wallet": {
			"google_pay": {
				"last4": "1111",
				"card_network": "VISA",
				"type": "CARD"
			}
		},
		"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": "John",
			"last_name": "Doe",
			"origin_zip": 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": "John",
			"last_name": "Doe",
			"origin_zip": null
		},
		"phone": null,
		"email": null
	},
	"order_details": null,
	"email": "likhin.bopanna@gmail.com",
	"name": "John Doe",
	"phone": "999999999",
	"return_url": "https://google.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": "google_pay",
	"connector_label": "cybersource_US_default_default",
	"business_country": "US",
	"business_label": "default",
	"business_sub_label": null,
	"allowed_payment_method_types": null,
	"ephemeral_key": null,
	"manual_retry_allowed": null,
	"connector_transaction_id": "7588799552276876103812",
	"frm_message": null,
	"metadata": {
		"udf1": "value1",
		"login_date": "2019-09-10T10:11:12Z",
		"new_customer": "true"
	},
	"connector_metadata": null,
	"feature_metadata": {
		"redirect_response": null,
		"search_tags": null,
		"apple_pay_recurring_details": null,
		"gateway_system": "direct"
	},
	"reference_id": "pay_P9LfwQUR2raIVIvvY1pb_1",
	"payment_link": null,
	"profile_id": "pro_QHOqYvAjzpmM3wQpjd2E",
	"surcharge_details": null,
	"attempt_count": 1,
	"merchant_decision": null,
	"merchant_connector_id": "mca_N8JtdITxcIuQ0D1tM1Uh",
	"incremental_authorization_allowed": false,
	"authorization_count": null,
	"incremental_authorizations": null,
	"external_authentication_details": null,
	"external_3ds_authentication_attempted": false,
	"expires_on": "2025-09-26T10:00:52.604Z",
	"fingerprint": null,
	"browser_info": {
		"os_type": null,
		"referer": null,
		"language": "nl-NL",
		"time_zone": 0,
		"ip_address": "127.0.0.1",
		"os_version": null,
		"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
		"color_depth": 24,
		"device_model": null,
		"java_enabled": true,
		"screen_width": 1536,
		"accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
		"screen_height": 723,
		"accept_language": "en",
		"java_script_enabled": true
	},
	"payment_channel": null,
	"payment_method_id": null,
	"network_transaction_id": "016153570198200",
	"payment_method_status": null,
	"updated": "2025-09-26T09:45:56.234Z",
	"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": null,
	"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
}

nuvei:

{
    "amount": 1,
    "currency": "EUR",
    "confirm": true,
    "customer_id": "nithxxinn",
    "return_url": "https://www.google.com",
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_type": "google_pay",
    "authentication_type": "no_three_ds",
    "description": "hellow world",
    "billing": {
        "address": {
            "zip": "560095",
            "country": "UA",
            "first_name": "Sakil",
            "last_name": "Mostak",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "city": "Fasdf"
        },
        "email": "nithin@test.com"
    },
    "browser_info": {
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "ip_address": "192.168.1.1",
        "java_enabled": false,
        "java_script_enabled": true,
        "language": "en-US",
        "color_depth": 24,
        "screen_height": 1080,
        "screen_width": 1920,
        "time_zone": 330,
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
    },
    "email": "hello@gmail.com",
    "payment_method_data": {
        "wallet": {
            "google_pay": {
                "description": "SG Visa Success: Visa •••• 1390",
                "info": {
                    "assurance_details": {
                        "account_verified": true,
                        "card_holder_authenticated": false
                    },
                    "card_details": "1390",
                    "card_funding_source": "CREDIT",
                    "card_network": "VISA"
                },
                "tokenization_data": {
                    "token": "{...}",
                    "type": "PAYMENT_GATEWAY"
                },
                "type": "CARD"
            }
        }
    }
	}
{
    "payment_id": "pay_BHX5HsGxx8GWTqhtxv55",
    "merchant_id": "merchant_1758885759",
    "status": "succeeded",
    "amount": 1,
    "net_amount": 1,
    "shipping_cost": null,
    "amount_capturable": 0,
    "amount_received": 1,
    "connector": "nuvei",
    "client_secret": "pay_BHX5HsGxx8GWTqhtxv55_secret_9ZgxOEN1NokJgukDDUKe",
    "created": "2025-09-26T11:24:42.509Z",
    "currency": "EUR",
    "customer_id": "nithxxinn",
    "customer": {
        "id": "nithxxinn",
        "name": null,
        "email": "hello@gmail.com",
        "phone": null,
        "phone_country_code": null
    },
    "description": "hellow world",
    "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": "wallet",
    "payment_method_data": {
        "wallet": {
            "google_pay": {
                "last4": "1390",
                "card_network": "VISA",
                "type": "CARD"
            }
        },
        "billing": null
    },
    "payment_token": null,
    "shipping": null,
    "billing": {
        "address": {
            "city": "Fasdf",
            "country": "UA",
            "line1": "Fasdf",
            "line2": "Fasdf",
            "line3": null,
            "zip": "560095",
            "state": null,
            "first_name": "Sakil",
            "last_name": "Mostak",
            "origin_zip": null
        },
        "phone": null,
        "email": "nithin@test.com"
    },
    "order_details": null,
    "email": "hello@gmail.com",
    "name": null,
    "phone": null,
    "return_url": "https://www.google.com/",
    "authentication_type": "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": "google_pay",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": {
        "customer_id": "nithxxinn",
        "created_at": 1758885882,
        "expires": 1758889482,
        "secret": "epk_31a09b5d224f4aea8bf6a114c6b7acd9"
    },
    "manual_retry_allowed": null,
    "connector_transaction_id": "7110000000017459005",
    "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": "9201058111",
    "payment_link": null,
    "profile_id": "pro_IOIVxznj4AqQbMy44z1p",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_MDGr4n22wQXL1OQXay79",
    "incremental_authorization_allowed": false,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-09-26T11:39:42.509Z",
    "fingerprint": null,
    "browser_info": {
        "language": "en-US",
        "time_zone": 330,
        "ip_address": "192.168.1.1",
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
        "color_depth": 24,
        "java_enabled": false,
        "screen_width": 1920,
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "screen_height": 1080,
        "java_script_enabled": true
    },
    "payment_channel": null,
    "payment_method_id": null,
    "network_transaction_id": "483297487231504",
    "payment_method_status": null,
    "updated": "2025-09-26T11:24:44.551Z",
    "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": null,
    "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
}
image

after unmasking, this data is being sent to the connector:

image

Checklist

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

@pixincreate pixincreate self-assigned this Sep 25, 2025
@pixincreate pixincreate added A-core Area: Core flows S-waiting-on-review Status: This PR has been implemented and needs to be reviewed C-refactor Category: Refactor A-payments Area: payments labels Sep 25, 2025
@semanticdiff-com
Copy link

semanticdiff-com bot commented Sep 25, 2025

@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Sep 25, 2025
@pixincreate pixincreate force-pushed the core/googlepay-new-field branch from b69b08f to 6b36ec0 Compare September 26, 2025 09:57
@pixincreate pixincreate marked this pull request as ready for review September 26, 2025 09:57
@pixincreate pixincreate requested review from a team as code owners September 26, 2025 09:57
//assurance_details of the card
pub assurance_details: Option<GooglePayAssuranceDetails>,
/// Card funding source for the selected payment method
pub card_funding_source: Option<GooglePayCardFundingSource>,
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that this field is just being consumed in the api response, but it is not being used anywhere in the code.

Why is this change required ?

Copy link
Member Author

Choose a reason for hiding this comment

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

  1. nuvei consumes this data since nuvei expects entire google pay payment method data to be passed in the request (confirmed by @Nithin1506200)
  2. this change is preparatory work for google pay's upcoming api changes. right now it's pass-through data, but having the field in our data models now means we won't need breaking changes when we implement the business logic later.

cc: @deepanshu-iiitu

Copy link
Contributor

@ShankarSinghC ShankarSinghC Sep 29, 2025

Choose a reason for hiding this comment

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

nuvei consumes this data since nuvei expects entire google pay payment method data to be passed in the request

Is card_funding_source a mandatory parameter for the connector ?

Copy link
Member Author

Choose a reason for hiding this comment

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

they haven't explicitly mentioned it, but the data we send during the payment request requires us to pass the entire payment info, and we never know when they'll need it. @Nithin1506200 suggested it's better for us to just pass it.

Copy link
Contributor

Choose a reason for hiding this comment

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

they haven't explicitly mentioned it, but the data we send during the payment request requires us to pass the entire payment info, and we never know when they'll need it. @Nithin1506200 suggested it's better for us to just pass it.

Without confirmation, it's not appropriate to add these fields. Also, since we're adding this as an enum variant, what happens if we receive a different enum variant? How are we handling enum parsing errors on our side?

Since this change affects API models, an unhandled enum variant (like card_funding_source) could cause a 5xx error even for connectors that don't require it.

Additionally, in the test case above, I don't see card_funding_source being passed in the /confirm call request. Is it possible to add a test that covers this change?

Copy link
Member Author

@pixincreate pixincreate Sep 29, 2025

Choose a reason for hiding this comment

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

@ShankarSinghC, you raise valid points. let me address them:

  • this is for google's upcoming api change (november 17, 2025 production rollout). google officially notified partners to prepare for the new cardFundingSource field in their response.

  • i added #[serde(other)] to Unknown variant and this handles unknown enum values gracefully and prevents 5xx errors.

  • the field is pass-through now but ensures forward compatibility when google rolls it out. i have already added a test case covering this field:

    image
  • while not explicitly documented as mandatory, nuvei expects the complete google pay payload to be forwarded. since google is making this field standard, it's better to include it proactively:

    image

    Convert the “entire” encrypted paymentMethod class into a string (“JSON to String”).

@pixincreate pixincreate added this to the July 2025 Release milestone Sep 29, 2025
ShankarSinghC
ShankarSinghC previously approved these changes Sep 30, 2025
…pay-new-field

* 'main' of github.com:juspay/hyperswitch: (21 commits)
  feat(payments): add tokenization action handling to payment flow for braintree (#9506)
  feat(connector): [Loonio] Add template code (#9586)
  fix(connector): [paysafe] make `eci_indicator` field optional (#9591)
  fix(core): add should_call_connector_customer function to connector specification (#9569)
  feat(ucs): Add profile ID to lineage tracking in Unified Connector Service (#9559)
  feat(core): Add support for partial auth in proxy payments [V2] (#9503)
  chore(version): 2025.09.30.0
  fix(authorizedotnet): refund via ucs missing connector_metadata (#9581)
  feat(auth): add new authentication to communicate between microservices (#9547)
  Fix: Ideal Giropay Country Currency Config (#9552)
  feat(connector): [ACI] cypress added (#9502)
  feat(connector): Add Peachpayments Cypress (#9573)
  chore(version): 2025.09.29.0
  feat(finix): template code (#9557)
  feat(cypress): add cypress test-cases for manual retry (#9505)
  feat(core): update additional payment method data in psync response (#9519)
  feat(connector): [Checkout] Add Google Pay Predecrypt Flow (#9130)
  feat(framework): Added smithy, smithy-core and smithy-generator crates (#9249)
  fix(core): add request_extended_authorization in the payment attempt and populate it in the payment response (#9492)
  chore(version): 2025.09.26.0
  ...
@Gnanasundari24 Gnanasundari24 added this pull request to the merge queue Oct 1, 2025
Merged via the queue into main with commit daad946 Oct 1, 2025
21 of 25 checks passed
@Gnanasundari24 Gnanasundari24 deleted the core/googlepay-new-field branch October 1, 2025 09:57
@pixincreate pixincreate removed the S-waiting-on-review Status: This PR has been implemented and needs to be reviewed label Oct 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-core Area: Core flows A-payments Area: payments C-refactor Category: Refactor M-api-contract-changes Metadata: This PR involves API contract changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] (GOOGLEPAY) Introduce cardsFundingSource in google pay payment method data

4 participants