diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index af1186ac9e..f0be48afec 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -857,6 +857,55 @@ "propertyName": "type" } }, + "AchBankDebitAdditionalData": { + "type": "object", + "required": [ + "account_number", + "routing_number" + ], + "properties": { + "account_number": { + "type": "string", + "description": "Partially masked account number for ach bank debit payment", + "example": "0001****3456" + }, + "routing_number": { + "type": "string", + "description": "Partially masked routing number for ach bank debit payment", + "example": "110***000" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + }, + "bank_name": { + "allOf": [ + { + "$ref": "#/components/schemas/BankNames" + } + ], + "nullable": true + }, + "bank_type": { + "allOf": [ + { + "$ref": "#/components/schemas/BankType" + } + ], + "nullable": true + }, + "bank_holder_type": { + "allOf": [ + { + "$ref": "#/components/schemas/BankHolderType" + } + ], + "nullable": true + } + } + }, "AchBankTransfer": { "type": "object", "required": [ @@ -1435,6 +1484,31 @@ "unresolved" ] }, + "BacsBankDebitAdditionalData": { + "type": "object", + "required": [ + "account_number", + "sort_code" + ], + "properties": { + "account_number": { + "type": "string", + "description": "Partially masked account number for Bacs payment method", + "example": "0001****3456" + }, + "sort_code": { + "type": "string", + "description": "Partially masked sort code for Bacs payment method", + "example": "108800" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + } + } + }, "BacsBankTransfer": { "type": "object", "required": [ @@ -1496,6 +1570,35 @@ } } }, + "BancontactBankRedirectAdditionalData": { + "type": "object", + "properties": { + "last4": { + "type": "string", + "description": "Last 4 digits of the card number", + "example": "4242", + "nullable": true + }, + "card_exp_month": { + "type": "string", + "description": "The card's expiry month", + "example": "12", + "nullable": true + }, + "card_exp_year": { + "type": "string", + "description": "The card's expiry year", + "example": "24", + "nullable": true + }, + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Test", + "nullable": true + } + } + }, "Bank": { "oneOf": [ { @@ -1512,6 +1615,54 @@ } ] }, + "BankDebitAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "ach" + ], + "properties": { + "ach": { + "$ref": "#/components/schemas/AchBankDebitAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "bacs" + ], + "properties": { + "bacs": { + "$ref": "#/components/schemas/BacsBankDebitAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "becs" + ], + "properties": { + "becs": { + "$ref": "#/components/schemas/BecsBankDebitAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "sepa" + ], + "properties": { + "sepa": { + "$ref": "#/components/schemas/SepaBankDebitAdditionalData" + } + } + } + ] + }, "BankDebitBilling": { "type": "object", "properties": { @@ -1719,6 +1870,13 @@ } ] }, + "BankHolderType": { + "type": "string", + "enum": [ + "personal", + "business" + ] + }, "BankNames": { "type": "string", "description": "Name of banks supported by Hyperswitch", @@ -1870,6 +2028,31 @@ "nationale_nederlanden" ] }, + "BankRedirectAdditionalData": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankRedirectDetails" + } + ], + "nullable": true + }, + { + "type": "object", + "properties": { + "bank_name": { + "allOf": [ + { + "$ref": "#/components/schemas/BankNames" + } + ], + "nullable": true + } + } + } + ] + }, "BankRedirectBilling": { "type": "object", "required": [ @@ -2320,6 +2503,201 @@ } ] }, + "BankRedirectDetails": { + "oneOf": [ + { + "type": "object", + "required": [ + "BancontactCard" + ], + "properties": { + "BancontactCard": { + "$ref": "#/components/schemas/BancontactBankRedirectAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "Blik" + ], + "properties": { + "Blik": { + "$ref": "#/components/schemas/BlikBankRedirectAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "Giropay" + ], + "properties": { + "Giropay": { + "$ref": "#/components/schemas/GiropayBankRedirectAdditionalData" + } + } + } + ] + }, + "BankTransferAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "ach" + ], + "properties": { + "ach": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "sepa" + ], + "properties": { + "sepa": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bacs" + ], + "properties": { + "bacs": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "multibanco" + ], + "properties": { + "multibanco": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "permata" + ], + "properties": { + "permata": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bca" + ], + "properties": { + "bca": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bni_va" + ], + "properties": { + "bni_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bri_va" + ], + "properties": { + "bri_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "cimb_va" + ], + "properties": { + "cimb_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "danamon_va" + ], + "properties": { + "danamon_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "mandiri_va" + ], + "properties": { + "mandiri_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "pix" + ], + "properties": { + "pix": { + "$ref": "#/components/schemas/PixBankTransferAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "pse" + ], + "properties": { + "pse": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "local_bank_transfer" + ], + "properties": { + "local_bank_transfer": { + "$ref": "#/components/schemas/LocalBankTransferAdditionalData" + } + } + } + ] + }, "BankTransferData": { "oneOf": [ { @@ -2699,6 +3077,48 @@ } ] }, + "BankType": { + "type": "string", + "enum": [ + "checking", + "savings" + ] + }, + "BecsBankDebitAdditionalData": { + "type": "object", + "required": [ + "account_number", + "bsb_number" + ], + "properties": { + "account_number": { + "type": "string", + "description": "Partially masked account number for Becs payment method", + "example": "0001****3456" + }, + "bsb_number": { + "type": "string", + "description": "Bank-State-Branch (bsb) number", + "example": "000000" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + } + } + }, + "BlikBankRedirectAdditionalData": { + "type": "object", + "properties": { + "blik_code": { + "type": "string", + "example": "3GD9MO", + "nullable": true + } + } + }, "BlocklistDataKind": { "type": "string", "enum": [ @@ -3789,6 +4209,19 @@ } } }, + "CardTokenAdditionalData": { + "type": "object", + "required": [ + "card_holder_name" + ], + "properties": { + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Test" + } + } + }, "CashappQr": { "type": "object" }, @@ -6148,6 +6581,32 @@ } } }, + "GiftCardAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "givex" + ], + "properties": { + "givex": { + "$ref": "#/components/schemas/GivexGiftCardAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "pay_safe_card" + ], + "properties": { + "pay_safe_card": { + "type": "object" + } + } + } + ] + }, "GiftCardData": { "oneOf": [ { @@ -6191,6 +6650,42 @@ } } }, + "GiropayBankRedirectAdditionalData": { + "type": "object", + "properties": { + "bic": { + "type": "string", + "description": "Masked bank account bic code", + "nullable": true + }, + "iban": { + "type": "string", + "description": "Partially masked international bank account number (iban) for SEPA", + "nullable": true + }, + "country": { + "allOf": [ + { + "$ref": "#/components/schemas/CountryAlpha2" + } + ], + "nullable": true + } + } + }, + "GivexGiftCardAdditionalData": { + "type": "object", + "required": [ + "last4" + ], + "properties": { + "last4": { + "type": "string", + "description": "Last 4 digits of the gift card number", + "example": "4242" + } + } + }, "GoPayRedirection": { "type": "object" }, @@ -7034,6 +7529,17 @@ } } }, + "LocalBankTransferAdditionalData": { + "type": "object", + "properties": { + "bank_code": { + "type": "string", + "description": "Partially masked bank code", + "example": "**** OA2312", + "nullable": true + } + } + }, "MandateAmountData": { "type": "object", "required": [ @@ -10276,7 +10782,7 @@ ], "properties": { "bank_transfer": { - "type": "object" + "$ref": "#/components/schemas/BankTransferAdditionalData" } } }, @@ -10309,7 +10815,7 @@ ], "properties": { "bank_redirect": { - "type": "object" + "$ref": "#/components/schemas/BankRedirectAdditionalData" } } }, @@ -10320,7 +10826,7 @@ ], "properties": { "crypto": { - "type": "object" + "$ref": "#/components/schemas/CryptoData" } } }, @@ -10331,7 +10837,7 @@ ], "properties": { "bank_debit": { - "type": "object" + "$ref": "#/components/schemas/BankDebitAdditionalData" } } }, @@ -10364,7 +10870,7 @@ ], "properties": { "real_time_payment": { - "type": "object" + "$ref": "#/components/schemas/RealTimePaymentData" } } }, @@ -10375,7 +10881,7 @@ ], "properties": { "upi": { - "type": "object" + "$ref": "#/components/schemas/UpiAdditionalData" } } }, @@ -10386,7 +10892,7 @@ ], "properties": { "voucher": { - "type": "object" + "$ref": "#/components/schemas/VoucherData" } } }, @@ -10397,7 +10903,7 @@ ], "properties": { "gift_card": { - "type": "object" + "$ref": "#/components/schemas/GiftCardAdditionalData" } } }, @@ -10408,7 +10914,7 @@ ], "properties": { "card_redirect": { - "type": "object" + "$ref": "#/components/schemas/CardRedirectData" } } }, @@ -10419,7 +10925,7 @@ ], "properties": { "card_token": { - "type": "object" + "$ref": "#/components/schemas/CardTokenAdditionalData" } } }, @@ -10430,7 +10936,7 @@ ], "properties": { "open_banking": { - "type": "object" + "$ref": "#/components/schemas/OpenBankingData" } } } @@ -14865,6 +15371,29 @@ } } }, + "PixBankTransferAdditionalData": { + "type": "object", + "properties": { + "pix_key": { + "type": "string", + "description": "Partially masked unique key for pix transfer", + "example": "a1f4102e ****** 6fa48899c1d1", + "nullable": true + }, + "cpf": { + "type": "string", + "description": "Partially masked CPF - CPF is a Brazilian tax identification number", + "example": "**** 124689", + "nullable": true + }, + "cnpj": { + "type": "string", + "description": "Partially masked CNPJ - CNPJ is a Brazilian company tax identification number", + "example": "**** 417312", + "nullable": true + } + } + }, "PollConfigResponse": { "type": "object", "required": [ @@ -16208,6 +16737,25 @@ } } }, + "SepaBankDebitAdditionalData": { + "type": "object", + "required": [ + "iban" + ], + "properties": { + "iban": { + "type": "string", + "description": "Partially masked international bank account number (iban) for SEPA", + "example": "DE8937******013000" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + } + } + }, "SepaBankTransfer": { "type": "object", "required": [ @@ -16834,6 +17382,42 @@ }, "additionalProperties": false }, + "UpiAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "upi_collect" + ], + "properties": { + "upi_collect": { + "$ref": "#/components/schemas/UpiCollectAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "upi_intent" + ], + "properties": { + "upi_intent": { + "$ref": "#/components/schemas/UpiIntentData" + } + } + } + ] + }, + "UpiCollectAdditionalData": { + "type": "object", + "properties": { + "vpa_id": { + "type": "string", + "description": "Masked VPA ID", + "nullable": true + } + } + }, "UpiCollectData": { "type": "object", "properties": { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index 83a505746e..682814f08d 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -5078,6 +5078,55 @@ "propertyName": "type" } }, + "AchBankDebitAdditionalData": { + "type": "object", + "required": [ + "account_number", + "routing_number" + ], + "properties": { + "account_number": { + "type": "string", + "description": "Partially masked account number for ach bank debit payment", + "example": "0001****3456" + }, + "routing_number": { + "type": "string", + "description": "Partially masked routing number for ach bank debit payment", + "example": "110***000" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + }, + "bank_name": { + "allOf": [ + { + "$ref": "#/components/schemas/BankNames" + } + ], + "nullable": true + }, + "bank_type": { + "allOf": [ + { + "$ref": "#/components/schemas/BankType" + } + ], + "nullable": true + }, + "bank_holder_type": { + "allOf": [ + { + "$ref": "#/components/schemas/BankHolderType" + } + ], + "nullable": true + } + } + }, "AchBankTransfer": { "type": "object", "required": [ @@ -5656,6 +5705,31 @@ "unresolved" ] }, + "BacsBankDebitAdditionalData": { + "type": "object", + "required": [ + "account_number", + "sort_code" + ], + "properties": { + "account_number": { + "type": "string", + "description": "Partially masked account number for Bacs payment method", + "example": "0001****3456" + }, + "sort_code": { + "type": "string", + "description": "Partially masked sort code for Bacs payment method", + "example": "108800" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + } + } + }, "BacsBankTransfer": { "type": "object", "required": [ @@ -5717,6 +5791,35 @@ } } }, + "BancontactBankRedirectAdditionalData": { + "type": "object", + "properties": { + "last4": { + "type": "string", + "description": "Last 4 digits of the card number", + "example": "4242", + "nullable": true + }, + "card_exp_month": { + "type": "string", + "description": "The card's expiry month", + "example": "12", + "nullable": true + }, + "card_exp_year": { + "type": "string", + "description": "The card's expiry year", + "example": "24", + "nullable": true + }, + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Test", + "nullable": true + } + } + }, "Bank": { "oneOf": [ { @@ -5733,6 +5836,54 @@ } ] }, + "BankDebitAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "ach" + ], + "properties": { + "ach": { + "$ref": "#/components/schemas/AchBankDebitAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "bacs" + ], + "properties": { + "bacs": { + "$ref": "#/components/schemas/BacsBankDebitAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "becs" + ], + "properties": { + "becs": { + "$ref": "#/components/schemas/BecsBankDebitAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "sepa" + ], + "properties": { + "sepa": { + "$ref": "#/components/schemas/SepaBankDebitAdditionalData" + } + } + } + ] + }, "BankDebitBilling": { "type": "object", "properties": { @@ -5940,6 +6091,13 @@ } ] }, + "BankHolderType": { + "type": "string", + "enum": [ + "personal", + "business" + ] + }, "BankNames": { "type": "string", "description": "Name of banks supported by Hyperswitch", @@ -6091,6 +6249,31 @@ "nationale_nederlanden" ] }, + "BankRedirectAdditionalData": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankRedirectDetails" + } + ], + "nullable": true + }, + { + "type": "object", + "properties": { + "bank_name": { + "allOf": [ + { + "$ref": "#/components/schemas/BankNames" + } + ], + "nullable": true + } + } + } + ] + }, "BankRedirectBilling": { "type": "object", "required": [ @@ -6541,6 +6724,201 @@ } ] }, + "BankRedirectDetails": { + "oneOf": [ + { + "type": "object", + "required": [ + "BancontactCard" + ], + "properties": { + "BancontactCard": { + "$ref": "#/components/schemas/BancontactBankRedirectAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "Blik" + ], + "properties": { + "Blik": { + "$ref": "#/components/schemas/BlikBankRedirectAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "Giropay" + ], + "properties": { + "Giropay": { + "$ref": "#/components/schemas/GiropayBankRedirectAdditionalData" + } + } + } + ] + }, + "BankTransferAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "ach" + ], + "properties": { + "ach": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "sepa" + ], + "properties": { + "sepa": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bacs" + ], + "properties": { + "bacs": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "multibanco" + ], + "properties": { + "multibanco": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "permata" + ], + "properties": { + "permata": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bca" + ], + "properties": { + "bca": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bni_va" + ], + "properties": { + "bni_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "bri_va" + ], + "properties": { + "bri_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "cimb_va" + ], + "properties": { + "cimb_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "danamon_va" + ], + "properties": { + "danamon_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "mandiri_va" + ], + "properties": { + "mandiri_va": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "pix" + ], + "properties": { + "pix": { + "$ref": "#/components/schemas/PixBankTransferAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "pse" + ], + "properties": { + "pse": { + "type": "object" + } + } + }, + { + "type": "object", + "required": [ + "local_bank_transfer" + ], + "properties": { + "local_bank_transfer": { + "$ref": "#/components/schemas/LocalBankTransferAdditionalData" + } + } + } + ] + }, "BankTransferData": { "oneOf": [ { @@ -6920,6 +7298,48 @@ } ] }, + "BankType": { + "type": "string", + "enum": [ + "checking", + "savings" + ] + }, + "BecsBankDebitAdditionalData": { + "type": "object", + "required": [ + "account_number", + "bsb_number" + ], + "properties": { + "account_number": { + "type": "string", + "description": "Partially masked account number for Becs payment method", + "example": "0001****3456" + }, + "bsb_number": { + "type": "string", + "description": "Bank-State-Branch (bsb) number", + "example": "000000" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + } + } + }, + "BlikBankRedirectAdditionalData": { + "type": "object", + "properties": { + "blik_code": { + "type": "string", + "example": "3GD9MO", + "nullable": true + } + } + }, "BlocklistDataKind": { "type": "string", "enum": [ @@ -8027,6 +8447,19 @@ } } }, + "CardTokenAdditionalData": { + "type": "object", + "required": [ + "card_holder_name" + ], + "properties": { + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Test" + } + } + }, "CashappQr": { "type": "object" }, @@ -10363,6 +10796,32 @@ } } }, + "GiftCardAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "givex" + ], + "properties": { + "givex": { + "$ref": "#/components/schemas/GivexGiftCardAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "pay_safe_card" + ], + "properties": { + "pay_safe_card": { + "type": "object" + } + } + } + ] + }, "GiftCardData": { "oneOf": [ { @@ -10406,6 +10865,42 @@ } } }, + "GiropayBankRedirectAdditionalData": { + "type": "object", + "properties": { + "bic": { + "type": "string", + "description": "Masked bank account bic code", + "nullable": true + }, + "iban": { + "type": "string", + "description": "Partially masked international bank account number (iban) for SEPA", + "nullable": true + }, + "country": { + "allOf": [ + { + "$ref": "#/components/schemas/CountryAlpha2" + } + ], + "nullable": true + } + } + }, + "GivexGiftCardAdditionalData": { + "type": "object", + "required": [ + "last4" + ], + "properties": { + "last4": { + "type": "string", + "description": "Last 4 digits of the gift card number", + "example": "4242" + } + } + }, "GoPayRedirection": { "type": "object" }, @@ -11249,6 +11744,17 @@ } } }, + "LocalBankTransferAdditionalData": { + "type": "object", + "properties": { + "bank_code": { + "type": "string", + "description": "Partially masked bank code", + "example": "**** OA2312", + "nullable": true + } + } + }, "MandateAmountData": { "type": "object", "required": [ @@ -14856,7 +15362,7 @@ ], "properties": { "bank_transfer": { - "type": "object" + "$ref": "#/components/schemas/BankTransferAdditionalData" } } }, @@ -14889,7 +15395,7 @@ ], "properties": { "bank_redirect": { - "type": "object" + "$ref": "#/components/schemas/BankRedirectAdditionalData" } } }, @@ -14900,7 +15406,7 @@ ], "properties": { "crypto": { - "type": "object" + "$ref": "#/components/schemas/CryptoData" } } }, @@ -14911,7 +15417,7 @@ ], "properties": { "bank_debit": { - "type": "object" + "$ref": "#/components/schemas/BankDebitAdditionalData" } } }, @@ -14944,7 +15450,7 @@ ], "properties": { "real_time_payment": { - "type": "object" + "$ref": "#/components/schemas/RealTimePaymentData" } } }, @@ -14955,7 +15461,7 @@ ], "properties": { "upi": { - "type": "object" + "$ref": "#/components/schemas/UpiAdditionalData" } } }, @@ -14966,7 +15472,7 @@ ], "properties": { "voucher": { - "type": "object" + "$ref": "#/components/schemas/VoucherData" } } }, @@ -14977,7 +15483,7 @@ ], "properties": { "gift_card": { - "type": "object" + "$ref": "#/components/schemas/GiftCardAdditionalData" } } }, @@ -14988,7 +15494,7 @@ ], "properties": { "card_redirect": { - "type": "object" + "$ref": "#/components/schemas/CardRedirectData" } } }, @@ -14999,7 +15505,7 @@ ], "properties": { "card_token": { - "type": "object" + "$ref": "#/components/schemas/CardTokenAdditionalData" } } }, @@ -15010,7 +15516,7 @@ ], "properties": { "open_banking": { - "type": "object" + "$ref": "#/components/schemas/OpenBankingData" } } } @@ -19885,6 +20391,29 @@ } } }, + "PixBankTransferAdditionalData": { + "type": "object", + "properties": { + "pix_key": { + "type": "string", + "description": "Partially masked unique key for pix transfer", + "example": "a1f4102e ****** 6fa48899c1d1", + "nullable": true + }, + "cpf": { + "type": "string", + "description": "Partially masked CPF - CPF is a Brazilian tax identification number", + "example": "**** 124689", + "nullable": true + }, + "cnpj": { + "type": "string", + "description": "Partially masked CNPJ - CNPJ is a Brazilian company tax identification number", + "example": "**** 417312", + "nullable": true + } + } + }, "PollConfigResponse": { "type": "object", "required": [ @@ -21230,6 +21759,25 @@ } } }, + "SepaBankDebitAdditionalData": { + "type": "object", + "required": [ + "iban" + ], + "properties": { + "iban": { + "type": "string", + "description": "Partially masked international bank account number (iban) for SEPA", + "example": "DE8937******013000" + }, + "bank_account_holder_name": { + "type": "string", + "description": "Bank account's owner name", + "example": "John Doe", + "nullable": true + } + } + }, "SepaBankTransfer": { "type": "object", "required": [ @@ -21856,6 +22404,42 @@ }, "additionalProperties": false }, + "UpiAdditionalData": { + "oneOf": [ + { + "type": "object", + "required": [ + "upi_collect" + ], + "properties": { + "upi_collect": { + "$ref": "#/components/schemas/UpiCollectAdditionalData" + } + } + }, + { + "type": "object", + "required": [ + "upi_intent" + ], + "properties": { + "upi_intent": { + "$ref": "#/components/schemas/UpiIntentData" + } + } + } + ] + }, + "UpiCollectAdditionalData": { + "type": "object", + "properties": { + "vpa_id": { + "type": "string", + "description": "Masked VPA ID", + "nullable": true + } + } + }, "UpiCollectData": { "type": "object", "properties": { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 5ccde3e6d7..99735f5792 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -3,7 +3,7 @@ use std::{ fmt, num::NonZeroI64, }; - +pub mod additional_info; use cards::CardNumber; use common_utils::{ consts::default_payments_list_limit, @@ -1991,6 +1991,8 @@ pub enum AdditionalPaymentData { Card(Box), BankRedirect { bank_name: Option, + #[serde(flatten)] + additional_details: Option, }, Wallet { apple_pay: Option, @@ -1998,18 +2000,18 @@ pub enum AdditionalPaymentData { PayLater { klarna_sdk: Option, }, - BankTransfer {}, - Crypto {}, - BankDebit {}, + BankTransfer(additional_info::BankTransferAdditionalData), + Crypto(CryptoData), + BankDebit(additional_info::BankDebitAdditionalData), MandatePayment {}, Reward {}, - RealTimePayment {}, - Upi {}, - GiftCard {}, - Voucher {}, - CardRedirect {}, - CardToken {}, - OpenBanking {}, + RealTimePayment(RealTimePaymentData), + Upi(additional_info::UpiAdditionalData), + GiftCard(additional_info::GiftCardAdditionalData), + Voucher(VoucherData), + CardRedirect(CardRedirectData), + CardToken(additional_info::CardTokenAdditionalData), + OpenBanking(OpenBankingData), } #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] @@ -2976,21 +2978,21 @@ where { match payment_method_data { PaymentMethodDataResponse::Reward {} => serializer.serialize_str("reward"), - PaymentMethodDataResponse::BankDebit {} - | PaymentMethodDataResponse::BankRedirect {} + PaymentMethodDataResponse::BankDebit(_) + | PaymentMethodDataResponse::BankRedirect(_) | PaymentMethodDataResponse::Card(_) - | PaymentMethodDataResponse::CardRedirect {} - | PaymentMethodDataResponse::CardToken {} - | PaymentMethodDataResponse::Crypto {} + | PaymentMethodDataResponse::CardRedirect(_) + | PaymentMethodDataResponse::CardToken(_) + | PaymentMethodDataResponse::Crypto(_) | PaymentMethodDataResponse::MandatePayment {} - | PaymentMethodDataResponse::GiftCard {} + | PaymentMethodDataResponse::GiftCard(_) | PaymentMethodDataResponse::PayLater(_) - | PaymentMethodDataResponse::RealTimePayment {} - | PaymentMethodDataResponse::Upi {} + | PaymentMethodDataResponse::RealTimePayment(_) + | PaymentMethodDataResponse::Upi(_) | PaymentMethodDataResponse::Wallet {} - | PaymentMethodDataResponse::BankTransfer {} - | PaymentMethodDataResponse::OpenBanking {} - | PaymentMethodDataResponse::Voucher {} => { + | PaymentMethodDataResponse::BankTransfer(_) + | PaymentMethodDataResponse::OpenBanking(_) + | PaymentMethodDataResponse::Voucher(_) => { payment_method_data_response.serialize(serializer) } } @@ -3006,23 +3008,28 @@ where #[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, serde::Deserialize, ToSchema)] #[serde(rename_all = "snake_case")] pub enum PaymentMethodDataResponse { - #[serde(rename = "card")] Card(Box), - BankTransfer {}, + #[schema(value_type = BankTransferAdditionalData)] + BankTransfer(additional_info::BankTransferAdditionalData), Wallet {}, PayLater(Box), - BankRedirect {}, - Crypto {}, - BankDebit {}, + #[schema(value_type = BankRedirectAdditionalData)] + BankRedirect(additional_info::BankRedirectAdditionalData), + Crypto(CryptoData), + #[schema(value_type = BankDebitAdditionalData)] + BankDebit(additional_info::BankDebitAdditionalData), MandatePayment {}, Reward {}, - RealTimePayment {}, - Upi {}, - Voucher {}, - GiftCard {}, - CardRedirect {}, - CardToken {}, - OpenBanking {}, + RealTimePayment(RealTimePaymentData), + #[schema(value_type = UpiAdditionalData)] + Upi(additional_info::UpiAdditionalData), + Voucher(VoucherData), + #[schema(value_type = GiftCardAdditionalData)] + GiftCard(additional_info::GiftCardAdditionalData), + CardRedirect(CardRedirectData), + #[schema(value_type = CardTokenAdditionalData)] + CardToken(additional_info::CardTokenAdditionalData), + OpenBanking(OpenBankingData), } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] @@ -4271,19 +4278,27 @@ impl From for PaymentMethodDataResponse { None => Self::PayLater(Box::new(PaylaterResponse { klarna_sdk: None })), }, AdditionalPaymentData::Wallet { .. } => Self::Wallet {}, - AdditionalPaymentData::BankRedirect { .. } => Self::BankRedirect {}, - AdditionalPaymentData::Crypto {} => Self::Crypto {}, - AdditionalPaymentData::BankDebit {} => Self::BankDebit {}, + AdditionalPaymentData::BankRedirect { + bank_name, + additional_details, + } => Self::BankRedirect(additional_info::BankRedirectAdditionalData { + bank_name, + additional_details, + }), + AdditionalPaymentData::Crypto(crypto) => Self::Crypto(crypto), + AdditionalPaymentData::BankDebit(bank_debit) => Self::BankDebit(bank_debit), AdditionalPaymentData::MandatePayment {} => Self::MandatePayment {}, AdditionalPaymentData::Reward {} => Self::Reward {}, - AdditionalPaymentData::RealTimePayment {} => Self::RealTimePayment {}, - AdditionalPaymentData::Upi {} => Self::Upi {}, - AdditionalPaymentData::BankTransfer {} => Self::BankTransfer {}, - AdditionalPaymentData::Voucher {} => Self::Voucher {}, - AdditionalPaymentData::GiftCard {} => Self::GiftCard {}, - AdditionalPaymentData::CardRedirect {} => Self::CardRedirect {}, - AdditionalPaymentData::CardToken {} => Self::CardToken {}, - AdditionalPaymentData::OpenBanking {} => Self::OpenBanking {}, + AdditionalPaymentData::RealTimePayment(realtime_payment) => { + Self::RealTimePayment(realtime_payment) + } + AdditionalPaymentData::Upi(upi) => Self::Upi(upi), + AdditionalPaymentData::BankTransfer(bank_transfer) => Self::BankTransfer(bank_transfer), + AdditionalPaymentData::Voucher(voucher) => Self::Voucher(voucher), + AdditionalPaymentData::GiftCard(gift_card) => Self::GiftCard(gift_card), + AdditionalPaymentData::CardRedirect(card_redirect) => Self::CardRedirect(card_redirect), + AdditionalPaymentData::CardToken(card_token) => Self::CardToken(card_token), + AdditionalPaymentData::OpenBanking(open_banking) => Self::OpenBanking(open_banking), } } } diff --git a/crates/api_models/src/payments/additional_info.rs b/crates/api_models/src/payments/additional_info.rs new file mode 100644 index 0000000000..4d5b144f78 --- /dev/null +++ b/crates/api_models/src/payments/additional_info.rs @@ -0,0 +1,220 @@ +use common_utils::pii::{self}; +use masking::{ + masked_string::{MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode}, + Secret, +}; +use utoipa::ToSchema; + +use crate::enums as api_enums; + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum BankDebitAdditionalData { + Ach(Box), + Bacs(Box), + Becs(Box), + Sepa(Box), +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct AchBankDebitAdditionalData { + /// Partially masked account number for ach bank debit payment + #[schema(value_type = String, example = "0001****3456")] + pub account_number: Secret, + + /// Partially masked routing number for ach bank debit payment + #[schema(value_type = String, example = "110***000")] + pub routing_number: Secret, + + /// Bank account's owner name + #[schema(value_type = Option, example = "John Doe")] + pub bank_account_holder_name: Option>, + + /// Name of the bank + #[schema(value_type = Option, example = "ach")] + pub bank_name: Option, + + /// Bank account type + #[schema(value_type = Option, example = "checking")] + pub bank_type: Option, + + /// Bank holder entity type + #[schema(value_type = Option, example = "personal")] + pub bank_holder_type: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct BacsBankDebitAdditionalData { + /// Partially masked account number for Bacs payment method + #[schema(value_type = String, example = "0001****3456")] + pub account_number: Secret, + + /// Partially masked sort code for Bacs payment method + #[schema(value_type = String, example = "108800")] + pub sort_code: Secret, + + /// Bank account's owner name + #[schema(value_type = Option, example = "John Doe")] + pub bank_account_holder_name: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct BecsBankDebitAdditionalData { + /// Partially masked account number for Becs payment method + #[schema(value_type = String, example = "0001****3456")] + pub account_number: Secret, + + /// Bank-State-Branch (bsb) number + #[schema(value_type = String, example = "000000")] + pub bsb_number: Secret, + + /// Bank account's owner name + #[schema(value_type = Option, example = "John Doe")] + pub bank_account_holder_name: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct SepaBankDebitAdditionalData { + /// Partially masked international bank account number (iban) for SEPA + #[schema(value_type = String, example = "DE8937******013000")] + pub iban: Secret, + + /// Bank account's owner name + #[schema(value_type = Option, example = "John Doe")] + pub bank_account_holder_name: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case", tag = "type")] +pub struct BankRedirectAdditionalData { + /// Name of the bank + #[schema(value_type = Option)] + pub bank_name: Option, + #[serde(flatten)] + pub additional_details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub enum BankRedirectDetails { + BancontactCard(Box), + Blik(Box), + Giropay(Box), +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct BancontactBankRedirectAdditionalData { + /// Last 4 digits of the card number + #[schema(value_type = Option, example = "4242")] + pub last4: Option, + + /// The card's expiry month + #[schema(value_type = Option, example = "12")] + pub card_exp_month: Option>, + + /// The card's expiry year + #[schema(value_type = Option, example = "24")] + pub card_exp_year: Option>, + + /// The card holder's name + #[schema(value_type = Option, example = "John Test")] + pub card_holder_name: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct BlikBankRedirectAdditionalData { + #[schema(value_type = Option, example = "3GD9MO")] + pub blik_code: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct GiropayBankRedirectAdditionalData { + #[schema(value_type = Option)] + /// Masked bank account bic code + pub bic: Option>, + + /// Partially masked international bank account number (iban) for SEPA + #[schema(value_type = Option)] + pub iban: Option>, + + /// Country for bank payment + #[schema(value_type = Option, example = "US")] + pub country: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum BankTransferAdditionalData { + Ach {}, + Sepa {}, + Bacs {}, + Multibanco {}, + Permata {}, + Bca {}, + BniVa {}, + BriVa {}, + CimbVa {}, + DanamonVa {}, + MandiriVa {}, + Pix(Box), + Pse {}, + LocalBankTransfer(Box), +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct PixBankTransferAdditionalData { + /// Partially masked unique key for pix transfer + #[schema(value_type = Option, example = "a1f4102e ****** 6fa48899c1d1")] + pub pix_key: Option>, + + /// Partially masked CPF - CPF is a Brazilian tax identification number + #[schema(value_type = Option, example = "**** 124689")] + pub cpf: Option>, + + /// Partially masked CNPJ - CNPJ is a Brazilian company tax identification number + #[schema(value_type = Option, example = "**** 417312")] + pub cnpj: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct LocalBankTransferAdditionalData { + /// Partially masked bank code + #[schema(value_type = Option, example = "**** OA2312")] + pub bank_code: Option>, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum GiftCardAdditionalData { + Givex(Box), + PaySafeCard {}, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct GivexGiftCardAdditionalData { + /// Last 4 digits of the gift card number + #[schema(value_type = String, example = "4242")] + pub last4: Secret, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct CardTokenAdditionalData { + /// The card holder's name + #[schema(value_type = String, example = "John Test")] + pub card_holder_name: Option>, +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub enum UpiAdditionalData { + UpiCollect(Box), + #[schema(value_type = UpiIntentData)] + UpiIntent(Box), +} + +#[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case")] +pub struct UpiCollectAdditionalData { + /// Masked VPA ID + #[schema(value_type = Option)] + pub vpa_id: Option>, +} diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 5bff7b489c..64c3278e6c 100644 --- a/crates/hyperswitch_domain_models/src/payment_method_data.rs +++ b/crates/hyperswitch_domain_models/src/payment_method_data.rs @@ -1,10 +1,13 @@ -use api_models::payments::ExtendedCardInfo; +use api_models::payments::{additional_info as payment_additional_types, ExtendedCardInfo}; use common_enums::enums as api_enums; use common_utils::{ id_type, pii::{self, Email}, }; -use masking::Secret; +use masking::{ + masked_string::{MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode}, + PeekInterface, Secret, +}; use serde::{Deserialize, Serialize}; use time::Date; @@ -581,6 +584,17 @@ impl From for CardRedirectData { } } +impl From for api_models::payments::CardRedirectData { + fn from(value: CardRedirectData) -> Self { + match value { + CardRedirectData::Knet {} => Self::Knet {}, + CardRedirectData::Benefit {} => Self::Benefit {}, + CardRedirectData::MomoAtm {} => Self::MomoAtm {}, + CardRedirectData::CardRedirect {} => Self::CardRedirect {}, + } + } +} + impl From for WalletData { fn from(value: api_models::payments::WalletData) -> Self { match value { @@ -800,6 +814,19 @@ impl From for CryptoData { } } +impl From for api_models::payments::CryptoData { + fn from(value: CryptoData) -> Self { + let CryptoData { + pay_currency, + network, + } = value; + Self { + pay_currency, + network, + } + } +} + impl From for UpiData { fn from(value: api_models::payments::UpiData) -> Self { match value { @@ -811,6 +838,19 @@ impl From for UpiData { } } +impl From for api_models::payments::additional_info::UpiAdditionalData { + fn from(value: UpiData) -> Self { + match value { + UpiData::UpiCollect(upi) => Self::UpiCollect(Box::new( + payment_additional_types::UpiCollectAdditionalData { vpa_id: upi.vpa_id }, + )), + UpiData::UpiIntent(_) => { + Self::UpiIntent(Box::new(api_models::payments::UpiIntentData {})) + } + } + } +} + impl From for VoucherData { fn from(value: api_models::payments::VoucherData) -> Self { match value { @@ -842,6 +882,66 @@ impl From for VoucherData { } } +impl From> for Box { + fn from(value: Box) -> Self { + Self::new(api_models::payments::BoletoVoucherData { + social_security_number: value.social_security_number, + }) + } +} + +impl From> for Box { + fn from(_value: Box) -> Self { + Self::new(api_models::payments::AlfamartVoucherData { + first_name: None, + last_name: None, + email: None, + }) + } +} + +impl From> for Box { + fn from(_value: Box) -> Self { + Self::new(api_models::payments::IndomaretVoucherData { + first_name: None, + last_name: None, + email: None, + }) + } +} + +impl From> for Box { + fn from(_value: Box) -> Self { + Self::new(api_models::payments::JCSVoucherData { + first_name: None, + last_name: None, + email: None, + phone_number: None, + }) + } +} + +impl From for api_models::payments::VoucherData { + fn from(value: VoucherData) -> Self { + match value { + VoucherData::Boleto(boleto_data) => Self::Boleto(boleto_data.into()), + VoucherData::Alfamart(alfa_mart) => Self::Alfamart(alfa_mart.into()), + VoucherData::Indomaret(info_maret) => Self::Indomaret(info_maret.into()), + VoucherData::SevenEleven(jcs_data) + | VoucherData::Lawson(jcs_data) + | VoucherData::MiniStop(jcs_data) + | VoucherData::FamilyMart(jcs_data) + | VoucherData::Seicomart(jcs_data) + | VoucherData::PayEasy(jcs_data) => Self::SevenEleven(jcs_data.into()), + VoucherData::Efecty => Self::Efecty, + VoucherData::PagoEfectivo => Self::PagoEfectivo, + VoucherData::RedCompra => Self::RedCompra, + VoucherData::RedPagos => Self::RedPagos, + VoucherData::Oxxo => Self::Oxxo, + } + } +} + impl From for GiftCardData { fn from(value: api_models::payments::GiftCardData) -> Self { match value { @@ -854,6 +954,29 @@ impl From for GiftCardData { } } +impl From for payment_additional_types::GiftCardAdditionalData { + fn from(value: GiftCardData) -> Self { + match value { + GiftCardData::Givex(details) => Self::Givex(Box::new( + payment_additional_types::GivexGiftCardAdditionalData { + last4: details + .number + .peek() + .chars() + .rev() + .take(4) + .collect::() + .chars() + .rev() + .collect::() + .into(), + }, + )), + GiftCardData::PaySafeCard {} => Self::PaySafeCard {}, + } + } +} + impl From for CardToken { fn from(value: api_models::payments::CardToken) -> Self { let api_models::payments::CardToken { @@ -867,6 +990,15 @@ impl From for CardToken { } } +impl From for payment_additional_types::CardTokenAdditionalData { + fn from(value: CardToken) -> Self { + let CardToken { + card_holder_name, .. + } = value; + Self { card_holder_name } + } +} + impl From for BankDebitData { fn from(value: api_models::payments::BankDebitData) -> Self { match value { @@ -907,6 +1039,65 @@ impl From for BankDebitData { } } +impl From for api_models::payments::additional_info::BankDebitAdditionalData { + fn from(value: BankDebitData) -> Self { + match value { + BankDebitData::AchBankDebit { + account_number, + routing_number, + bank_name, + bank_type, + bank_holder_type, + } => Self::Ach(Box::new( + payment_additional_types::AchBankDebitAdditionalData { + account_number: Secret::from(MaskedBankAccount::from( + account_number.peek().to_owned(), + )), + routing_number: Secret::from(MaskedRoutingNumber::from( + routing_number.peek().to_owned(), + )), + bank_name, + bank_type, + bank_holder_type, + bank_account_holder_name: None, + }, + )), + BankDebitData::SepaBankDebit { iban, .. } => Self::Sepa(Box::new( + payment_additional_types::SepaBankDebitAdditionalData { + iban: Secret::from(MaskedIban::from(iban.peek().to_owned())), + bank_account_holder_name: None, + }, + )), + BankDebitData::BecsBankDebit { + account_number, + bsb_number, + .. + } => Self::Becs(Box::new( + payment_additional_types::BecsBankDebitAdditionalData { + account_number: Secret::from(MaskedBankAccount::from( + account_number.peek().to_owned(), + )), + bsb_number, + bank_account_holder_name: None, + }, + )), + BankDebitData::BacsBankDebit { + account_number, + sort_code, + .. + } => Self::Bacs(Box::new( + payment_additional_types::BacsBankDebitAdditionalData { + account_number: Secret::from(MaskedBankAccount::from( + account_number.peek().to_owned(), + )), + sort_code: Secret::from(MaskedSortCode::from(sort_code.peek().to_owned())), + bank_account_holder_name: None, + }, + )), + } + } +} + impl From for BankTransferData { fn from(value: api_models::payments::BankTransferData) -> Self { match value { @@ -954,6 +1145,42 @@ impl From for BankTransferData { } } +impl From for api_models::payments::additional_info::BankTransferAdditionalData { + fn from(value: BankTransferData) -> Self { + match value { + BankTransferData::AchBankTransfer {} => Self::Ach {}, + BankTransferData::SepaBankTransfer {} => Self::Sepa {}, + BankTransferData::BacsBankTransfer {} => Self::Bacs {}, + BankTransferData::MultibancoBankTransfer {} => Self::Multibanco {}, + BankTransferData::PermataBankTransfer {} => Self::Permata {}, + BankTransferData::BcaBankTransfer {} => Self::Bca {}, + BankTransferData::BniVaBankTransfer {} => Self::BniVa {}, + BankTransferData::BriVaBankTransfer {} => Self::BriVa {}, + BankTransferData::CimbVaBankTransfer {} => Self::CimbVa {}, + BankTransferData::DanamonVaBankTransfer {} => Self::DanamonVa {}, + BankTransferData::MandiriVaBankTransfer {} => Self::MandiriVa {}, + BankTransferData::Pix { pix_key, cpf, cnpj } => Self::Pix(Box::new( + api_models::payments::additional_info::PixBankTransferAdditionalData { + pix_key: pix_key.map(|pix_key| { + Secret::from(MaskedBankAccount::from(pix_key.peek().to_owned())) + }), + cpf: cpf + .map(|cpf| Secret::from(MaskedBankAccount::from(cpf.peek().to_owned()))), + cnpj: cnpj + .map(|cnpj| Secret::from(MaskedBankAccount::from(cnpj.peek().to_owned()))), + }, + )), + BankTransferData::Pse {} => Self::Pse {}, + BankTransferData::LocalBankTransfer { bank_code } => Self::LocalBankTransfer(Box::new( + api_models::payments::additional_info::LocalBankTransferAdditionalData { + bank_code: bank_code + .map(|bank_code| Secret::from(MaskedBankAccount::from(bank_code))), + }, + )), + } + } +} + impl From for RealTimePaymentData { fn from(value: api_models::payments::RealTimePaymentData) -> Self { match value { @@ -965,6 +1192,17 @@ impl From for RealTimePaymentData { } } +impl From for api_models::payments::RealTimePaymentData { + fn from(value: RealTimePaymentData) -> Self { + match value { + RealTimePaymentData::Fps {} => Self::Fps {}, + RealTimePaymentData::DuitNow {} => Self::DuitNow {}, + RealTimePaymentData::PromptPay {} => Self::PromptPay {}, + RealTimePaymentData::VietQr {} => Self::VietQr {}, + } + } +} + impl From for OpenBankingData { fn from(value: api_models::payments::OpenBankingData) -> Self { match value { @@ -973,6 +1211,14 @@ impl From for OpenBankingData { } } +impl From for api_models::payments::OpenBankingData { + fn from(value: OpenBankingData) -> Self { + match value { + OpenBankingData::OpenBankingPIS {} => Self::OpenBankingPIS {}, + } + } +} + #[derive(Debug, serde::Serialize, serde::Deserialize)] #[serde(rename_all = "camelCase")] pub struct TokenizedCardValue1 { diff --git a/crates/masking/src/lib.rs b/crates/masking/src/lib.rs index 5393438a87..d4b31e2bb0 100644 --- a/crates/masking/src/lib.rs +++ b/crates/masking/src/lib.rs @@ -33,8 +33,12 @@ mod bytes; #[cfg(feature = "bytes")] pub use self::bytes::SecretBytesMut; +#[cfg(all(feature = "alloc", feature = "serde"))] +pub mod masked_string; + #[cfg(feature = "alloc")] mod string; + #[cfg(feature = "alloc")] mod vec; diff --git a/crates/masking/src/masked_string.rs b/crates/masking/src/masked_string.rs new file mode 100644 index 0000000000..9a0f4c70c4 --- /dev/null +++ b/crates/masking/src/masked_string.rs @@ -0,0 +1,100 @@ +//! +//! Secret truncated strings +//! +//! Using type aliases for truncating and masking different types of string values. + +use alloc::string::{String, ToString}; + +use super::SerializableSecret; + +/// Function for masking alphanumeric characters in a string +/// examples +/// Sort Code +/// (12-34-56, 2, 2) -> 12-**-56 +/// Routing number +/// (026009593, 3, 3) -> 026***593 +/// CNPJ +/// (12345678901, 4, 4) -> 1234***8901 +/// Pix key +/// (123e-a452-1243-1244-000, 4, 4) -> 123e-****-****-****-000 +/// IBAN +/// (AL35202111090000000001234567, 5, 5) -> AL352******************34567 +fn apply_mask(val: &str, unmasked_char_count: usize, min_masked_char_count: usize) -> String { + let len = val.len(); + if len <= unmasked_char_count { + return val.to_string(); + } + + let mask_start_index = + // For showing only last `unmasked_char_count` characters + if len < (unmasked_char_count * 2 + min_masked_char_count) { + 0 + // For showing first and last `unmasked_char_count` characters + } else { + unmasked_char_count + }; + let mask_end_index = len - unmasked_char_count - 1; + + val.chars() + .enumerate() + .fold(String::new(), |mut acc, (index, ch)| { + if ch.is_alphanumeric() && (mask_start_index..=mask_end_index).contains(&index) { + acc.push('*'); + } else { + acc.push(ch); + } + acc + }) +} + +/// Masked sort code + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedSortCode(pub String); + +impl SerializableSecret for MaskedSortCode {} +impl From for MaskedSortCode { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 2, 2); + Self(masked_value) + } +} + +/// Masked Routing number + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedRoutingNumber(pub String); + +impl SerializableSecret for MaskedRoutingNumber {} +impl From for MaskedRoutingNumber { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 3, 3); + Self(masked_value) + } +} + +/// Masked bank account + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedBankAccount(pub String); + +impl SerializableSecret for MaskedBankAccount {} +impl From for MaskedBankAccount { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 4, 4); + Self(masked_value) + } +} + +/// Masked IBAN + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedIban(pub String); + +impl SerializableSecret for MaskedIban {} +impl From for MaskedIban { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 5, 5); + Self(masked_value) + } +} diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 676debffa2..0db9c9a775 100644 --- a/crates/openapi/src/openapi.rs +++ b/crates/openapi/src/openapi.rs @@ -250,6 +250,8 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::MandateStatus, api_models::enums::PaymentExperience, api_models::enums::BankNames, + api_models::enums::BankType, + api_models::enums::BankHolderType, api_models::enums::CardNetwork, api_models::enums::DisputeStage, api_models::enums::DisputeStatus, @@ -572,6 +574,24 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CustomerDetailsResponse, api_models::payments::OpenBankingData, api_models::payments::OpenBankingSessionToken, + api_models::payments::additional_info::CardTokenAdditionalData, + api_models::payments::additional_info::BankDebitAdditionalData, + api_models::payments::additional_info::AchBankDebitAdditionalData, + api_models::payments::additional_info::BacsBankDebitAdditionalData, + api_models::payments::additional_info::BecsBankDebitAdditionalData, + api_models::payments::additional_info::SepaBankDebitAdditionalData, + api_models::payments::additional_info::BankRedirectAdditionalData, + api_models::payments::additional_info::BankRedirectDetails, + api_models::payments::additional_info::BancontactBankRedirectAdditionalData, + api_models::payments::additional_info::BlikBankRedirectAdditionalData, + api_models::payments::additional_info::GiropayBankRedirectAdditionalData, + api_models::payments::additional_info::BankTransferAdditionalData, + api_models::payments::additional_info::PixBankTransferAdditionalData, + api_models::payments::additional_info::LocalBankTransferAdditionalData, + api_models::payments::additional_info::GiftCardAdditionalData, + api_models::payments::additional_info::GivexGiftCardAdditionalData, + api_models::payments::additional_info::UpiAdditionalData, + api_models::payments::additional_info::UpiCollectAdditionalData, )), modifiers(&SecurityAddon) )] diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 465f00df03..f516839950 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -150,6 +150,8 @@ Never share your secret api keys. Keep them guarded and secure. api_models::enums::MandateStatus, api_models::enums::PaymentExperience, api_models::enums::BankNames, + api_models::enums::BankType, + api_models::enums::BankHolderType, api_models::enums::CardNetwork, api_models::enums::DisputeStage, api_models::enums::DisputeStatus, @@ -470,6 +472,24 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CustomerDetailsResponse, api_models::payments::OpenBankingData, api_models::payments::OpenBankingSessionToken, + api_models::payments::additional_info::CardTokenAdditionalData, + api_models::payments::additional_info::BankDebitAdditionalData, + api_models::payments::additional_info::AchBankDebitAdditionalData, + api_models::payments::additional_info::BacsBankDebitAdditionalData, + api_models::payments::additional_info::BecsBankDebitAdditionalData, + api_models::payments::additional_info::SepaBankDebitAdditionalData, + api_models::payments::additional_info::BankRedirectAdditionalData, + api_models::payments::additional_info::BankRedirectDetails, + api_models::payments::additional_info::BancontactBankRedirectAdditionalData, + api_models::payments::additional_info::BlikBankRedirectAdditionalData, + api_models::payments::additional_info::GiropayBankRedirectAdditionalData, + api_models::payments::additional_info::BankTransferAdditionalData, + api_models::payments::additional_info::PixBankTransferAdditionalData, + api_models::payments::additional_info::LocalBankTransferAdditionalData, + api_models::payments::additional_info::GiftCardAdditionalData, + api_models::payments::additional_info::GivexGiftCardAdditionalData, + api_models::payments::additional_info::UpiAdditionalData, + api_models::payments::additional_info::UpiCollectAdditionalData, )), modifiers(&SecurityAddon) )] diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index a1b65fa268..068a66a248 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -4,7 +4,10 @@ use std::{borrow::Cow, str::FromStr}; use api_models::customers::CustomerRequestWithEmail; use api_models::{ mandates::RecurringDetails, - payments::{AddressDetailsWithPhone, RequestSurchargeDetails}, + payments::{ + additional_info as payment_additional_types, AddressDetailsWithPhone, + RequestSurchargeDetails, + }, }; use base64::Engine; use common_enums::ConnectorType; @@ -31,7 +34,10 @@ use hyperswitch_domain_models::{ }; use hyperswitch_interfaces::integrity::{CheckIntegrity, FlowIntegrity, GetIntegrityObject}; use josekit::jwe; -use masking::{ExposeInterface, PeekInterface}; +use masking::{ + masked_string::{MaskedIban, MaskedSortCode}, + ExposeInterface, PeekInterface, +}; use openssl::{ derive::Deriver, pkey::PKey, @@ -3932,16 +3938,67 @@ pub async fn get_additional_payment_data( domain::BankRedirectData::Eps { bank_name, .. } => { Some(api_models::payments::AdditionalPaymentData::BankRedirect { bank_name: bank_name.to_owned(), + additional_details: None, }) } domain::BankRedirectData::Ideal { bank_name, .. } => { Some(api_models::payments::AdditionalPaymentData::BankRedirect { bank_name: bank_name.to_owned(), + additional_details: None, }) } - _ => { - Some(api_models::payments::AdditionalPaymentData::BankRedirect { bank_name: None }) + domain::BankRedirectData::BancontactCard { + card_number, + card_exp_month, + card_exp_year, + } => Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + additional_details: Some( + payment_additional_types::BankRedirectDetails::BancontactCard(Box::new( + payment_additional_types::BancontactBankRedirectAdditionalData { + last4: card_number.as_ref().map(|c| c.get_last4()), + card_exp_month: card_exp_month.clone(), + card_exp_year: card_exp_year.clone(), + card_holder_name: None, + }, + )), + ), + }), + domain::BankRedirectData::Blik { blik_code } => { + Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + additional_details: blik_code.as_ref().map(|blik_code| { + payment_additional_types::BankRedirectDetails::Blik(Box::new( + payment_additional_types::BlikBankRedirectAdditionalData { + blik_code: Some(blik_code.to_owned()), + }, + )) + }), + }) } + domain::BankRedirectData::Giropay { + bank_account_bic, + bank_account_iban, + } => Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + additional_details: Some(payment_additional_types::BankRedirectDetails::Giropay( + Box::new( + payment_additional_types::GiropayBankRedirectAdditionalData { + bic: bank_account_bic.as_ref().map(|bic| { + masking::Secret::from(MaskedSortCode::from(bic.peek().to_owned())) + }), + iban: bank_account_iban.as_ref().map(|iban| { + masking::Secret::from(MaskedIban::from(iban.peek().to_owned())) + }), + country: None, + }, + ), + )), + }), + _ => Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + additional_details: None, + }), }, domain::PaymentMethodData::Wallet(wallet) => match wallet { domain::WalletData::ApplePay(apple_pay_wallet_data) => { @@ -3958,41 +4015,49 @@ pub async fn get_additional_payment_data( domain::PaymentMethodData::PayLater(_) => { Some(api_models::payments::AdditionalPaymentData::PayLater { klarna_sdk: None }) } - domain::PaymentMethodData::BankTransfer(_) => { - Some(api_models::payments::AdditionalPaymentData::BankTransfer {}) - } - domain::PaymentMethodData::Crypto(_) => { - Some(api_models::payments::AdditionalPaymentData::Crypto {}) - } - domain::PaymentMethodData::BankDebit(_) => { - Some(api_models::payments::AdditionalPaymentData::BankDebit {}) + domain::PaymentMethodData::BankTransfer(bank_transfer) => { + Some(api_models::payments::AdditionalPaymentData::BankTransfer( + (*(bank_transfer.to_owned())).into(), + )) } + domain::PaymentMethodData::Crypto(crypto) => Some( + api_models::payments::AdditionalPaymentData::Crypto(crypto.to_owned().into()), + ), + domain::PaymentMethodData::BankDebit(bank_debit) => Some( + api_models::payments::AdditionalPaymentData::BankDebit(bank_debit.to_owned().into()), + ), domain::PaymentMethodData::MandatePayment => { Some(api_models::payments::AdditionalPaymentData::MandatePayment {}) } domain::PaymentMethodData::Reward => { Some(api_models::payments::AdditionalPaymentData::Reward {}) } - domain::PaymentMethodData::RealTimePayment(_) => { - Some(api_models::payments::AdditionalPaymentData::RealTimePayment {}) + domain::PaymentMethodData::RealTimePayment(realtime_payment) => Some( + api_models::payments::AdditionalPaymentData::RealTimePayment( + (*(realtime_payment.to_owned())).into(), + ), + ), + domain::PaymentMethodData::Upi(upi) => Some( + api_models::payments::AdditionalPaymentData::Upi(upi.to_owned().into()), + ), + domain::PaymentMethodData::CardRedirect(card_redirect) => { + Some(api_models::payments::AdditionalPaymentData::CardRedirect( + card_redirect.to_owned().into(), + )) } - domain::PaymentMethodData::Upi(_) => { - Some(api_models::payments::AdditionalPaymentData::Upi {}) - } - domain::PaymentMethodData::CardRedirect(_) => { - Some(api_models::payments::AdditionalPaymentData::CardRedirect {}) - } - domain::PaymentMethodData::Voucher(_) => { - Some(api_models::payments::AdditionalPaymentData::Voucher {}) - } - domain::PaymentMethodData::GiftCard(_) => { - Some(api_models::payments::AdditionalPaymentData::GiftCard {}) - } - domain::PaymentMethodData::CardToken(_) => { - Some(api_models::payments::AdditionalPaymentData::CardToken {}) - } - domain::PaymentMethodData::OpenBanking(_) => { - Some(api_models::payments::AdditionalPaymentData::OpenBanking {}) + domain::PaymentMethodData::Voucher(voucher) => Some( + api_models::payments::AdditionalPaymentData::Voucher(voucher.to_owned().into()), + ), + domain::PaymentMethodData::GiftCard(gift_card) => Some( + api_models::payments::AdditionalPaymentData::GiftCard((*(gift_card.to_owned())).into()), + ), + domain::PaymentMethodData::CardToken(card_token) => Some( + api_models::payments::AdditionalPaymentData::CardToken(card_token.to_owned().into()), + ), + domain::PaymentMethodData::OpenBanking(open_banking) => { + Some(api_models::payments::AdditionalPaymentData::OpenBanking( + open_banking.to_owned().into(), + )) } domain::PaymentMethodData::NetworkToken(_) => None, }