diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index ac4f3fe7b4..31aa84e64a 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -1436,6 +1436,61 @@ "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" + }, + "card_holder_name": { + "type": "string", + "description": "Card holder's name", + "example": "John Doe", + "nullable": true + }, + "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": [ @@ -2014,6 +2069,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": [ @@ -2075,6 +2155,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": [ { @@ -2091,6 +2200,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": { @@ -2298,6 +2455,28 @@ } ] }, + "BankDebitResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankDebitAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, + "BankHolderType": { + "type": "string", + "enum": [ + "personal", + "business" + ] + }, "BankNames": { "type": "string", "description": "Name of banks supported by Hyperswitch", @@ -2899,6 +3078,226 @@ } ] }, + "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" + } + } + } + ] + }, + "BankRedirectResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankRedirectDetails" + } + ], + "nullable": true + }, + { + "type": "object", + "properties": { + "bank_name": { + "allOf": [ + { + "$ref": "#/components/schemas/BankNames" + } + ], + "nullable": true + } + } + } + ] + }, + "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": [ { @@ -3278,6 +3677,63 @@ } ] }, + "BankTransferResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankTransferAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, + "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": [ @@ -4311,6 +4767,21 @@ } ] }, + "CardRedirectResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/CardRedirectData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "CardResponse": { "type": "object", "properties": { @@ -4384,6 +4855,34 @@ } } }, + "CardTokenAdditionalData": { + "type": "object", + "required": [ + "card_holder_name" + ], + "properties": { + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Test" + } + } + }, + "CardTokenResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/CardTokenAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "CashappQr": { "type": "object" }, @@ -4999,6 +5498,21 @@ } } }, + "CryptoResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/CryptoData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "Currency": { "type": "string", "description": "The three letter ISO currency code in uppercase. Eg: 'USD' for the United States Dollar.", @@ -6758,6 +7272,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": [ { @@ -6801,6 +7341,57 @@ } } }, + "GiftCardResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/GiftCardAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, + "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" }, @@ -7644,6 +8235,17 @@ } } }, + "LocalBankTransferAdditionalData": { + "type": "object", + "properties": { + "bank_code": { + "type": "string", + "description": "Partially masked bank code", + "example": "**** OA2312", + "nullable": true + } + } + }, "MandateAmountData": { "type": "object", "required": [ @@ -9289,6 +9891,21 @@ } ] }, + "OpenBankingResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/OpenBankingData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "OpenBankingSessionToken": { "type": "object", "required": [ @@ -10839,7 +11456,7 @@ ], "properties": { "bank_transfer": { - "type": "object" + "$ref": "#/components/schemas/BankTransferResponse" } } }, @@ -10872,7 +11489,7 @@ ], "properties": { "bank_redirect": { - "type": "object" + "$ref": "#/components/schemas/BankRedirectResponse" } } }, @@ -10883,7 +11500,7 @@ ], "properties": { "crypto": { - "type": "object" + "$ref": "#/components/schemas/CryptoResponse" } } }, @@ -10894,7 +11511,7 @@ ], "properties": { "bank_debit": { - "type": "object" + "$ref": "#/components/schemas/BankDebitResponse" } } }, @@ -10927,7 +11544,7 @@ ], "properties": { "real_time_payment": { - "type": "object" + "$ref": "#/components/schemas/RealTimePaymentDataResponse" } } }, @@ -10938,7 +11555,7 @@ ], "properties": { "upi": { - "type": "object" + "$ref": "#/components/schemas/UpiResponse" } } }, @@ -10949,7 +11566,7 @@ ], "properties": { "voucher": { - "type": "object" + "$ref": "#/components/schemas/VoucherResponse" } } }, @@ -10960,7 +11577,7 @@ ], "properties": { "gift_card": { - "type": "object" + "$ref": "#/components/schemas/GiftCardResponse" } } }, @@ -10971,7 +11588,7 @@ ], "properties": { "card_redirect": { - "type": "object" + "$ref": "#/components/schemas/CardRedirectResponse" } } }, @@ -10982,7 +11599,7 @@ ], "properties": { "card_token": { - "type": "object" + "$ref": "#/components/schemas/CardTokenResponse" } } }, @@ -10993,7 +11610,7 @@ ], "properties": { "open_banking": { - "type": "object" + "$ref": "#/components/schemas/OpenBankingResponse" } } } @@ -15477,6 +16094,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": [ @@ -15656,6 +16296,21 @@ } ] }, + "RealTimePaymentDataResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/RealTimePaymentData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "ReceiverDetails": { "type": "object", "required": [ @@ -16829,6 +17484,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": [ @@ -17462,6 +18136,43 @@ }, "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", + "example": "ab********@okhdfcbank", + "nullable": true + } + } + }, "UpiCollectData": { "type": "object", "properties": { @@ -17501,6 +18212,21 @@ "UpiIntentData": { "type": "object" }, + "UpiResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/UpiAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "ValueType": { "oneOf": [ { @@ -17795,6 +18521,21 @@ } ] }, + "VoucherResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/VoucherData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "Wallet": { "oneOf": [ { diff --git a/api-reference/openapi_spec.json b/api-reference/openapi_spec.json index f40b298308..689b39cb4c 100644 --- a/api-reference/openapi_spec.json +++ b/api-reference/openapi_spec.json @@ -5066,6 +5066,61 @@ "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" + }, + "card_holder_name": { + "type": "string", + "description": "Card holder's name", + "example": "John Doe", + "nullable": true + }, + "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": [ @@ -5644,6 +5699,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": [ @@ -5705,6 +5785,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": [ { @@ -5721,6 +5830,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": { @@ -5928,6 +6085,28 @@ } ] }, + "BankDebitResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankDebitAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, + "BankHolderType": { + "type": "string", + "enum": [ + "personal", + "business" + ] + }, "BankNames": { "type": "string", "description": "Name of banks supported by Hyperswitch", @@ -6529,6 +6708,226 @@ } ] }, + "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" + } + } + } + ] + }, + "BankRedirectResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankRedirectDetails" + } + ], + "nullable": true + }, + { + "type": "object", + "properties": { + "bank_name": { + "allOf": [ + { + "$ref": "#/components/schemas/BankNames" + } + ], + "nullable": true + } + } + } + ] + }, + "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": [ { @@ -6908,6 +7307,63 @@ } ] }, + "BankTransferResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/BankTransferAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, + "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": [ @@ -7958,6 +8414,21 @@ } ] }, + "CardRedirectResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/CardRedirectData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "CardResponse": { "type": "object", "properties": { @@ -8031,6 +8502,34 @@ } } }, + "CardTokenAdditionalData": { + "type": "object", + "required": [ + "card_holder_name" + ], + "properties": { + "card_holder_name": { + "type": "string", + "description": "The card holder's name", + "example": "John Test" + } + } + }, + "CardTokenResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/CardTokenAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "CashappQr": { "type": "object" }, @@ -8646,6 +9145,21 @@ } } }, + "CryptoResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/CryptoData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "Currency": { "type": "string", "description": "The three letter ISO currency code in uppercase. Eg: 'USD' for the United States Dollar.", @@ -10377,6 +10891,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": [ { @@ -10420,6 +10960,57 @@ } } }, + "GiftCardResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/GiftCardAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, + "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" }, @@ -11263,6 +11854,17 @@ } } }, + "LocalBankTransferAdditionalData": { + "type": "object", + "properties": { + "bank_code": { + "type": "string", + "description": "Partially masked bank code", + "example": "**** OA2312", + "nullable": true + } + } + }, "MandateAmountData": { "type": "object", "required": [ @@ -13294,6 +13896,21 @@ } ] }, + "OpenBankingResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/OpenBankingData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "OpenBankingSessionToken": { "type": "object", "required": [ @@ -14837,7 +15454,7 @@ ], "properties": { "bank_transfer": { - "type": "object" + "$ref": "#/components/schemas/BankTransferResponse" } } }, @@ -14870,7 +15487,7 @@ ], "properties": { "bank_redirect": { - "type": "object" + "$ref": "#/components/schemas/BankRedirectResponse" } } }, @@ -14881,7 +15498,7 @@ ], "properties": { "crypto": { - "type": "object" + "$ref": "#/components/schemas/CryptoResponse" } } }, @@ -14892,7 +15509,7 @@ ], "properties": { "bank_debit": { - "type": "object" + "$ref": "#/components/schemas/BankDebitResponse" } } }, @@ -14925,7 +15542,7 @@ ], "properties": { "real_time_payment": { - "type": "object" + "$ref": "#/components/schemas/RealTimePaymentDataResponse" } } }, @@ -14936,7 +15553,7 @@ ], "properties": { "upi": { - "type": "object" + "$ref": "#/components/schemas/UpiResponse" } } }, @@ -14947,7 +15564,7 @@ ], "properties": { "voucher": { - "type": "object" + "$ref": "#/components/schemas/VoucherResponse" } } }, @@ -14958,7 +15575,7 @@ ], "properties": { "gift_card": { - "type": "object" + "$ref": "#/components/schemas/GiftCardResponse" } } }, @@ -14969,7 +15586,7 @@ ], "properties": { "card_redirect": { - "type": "object" + "$ref": "#/components/schemas/CardRedirectResponse" } } }, @@ -14980,7 +15597,7 @@ ], "properties": { "card_token": { - "type": "object" + "$ref": "#/components/schemas/CardTokenResponse" } } }, @@ -14991,7 +15608,7 @@ ], "properties": { "open_banking": { - "type": "object" + "$ref": "#/components/schemas/OpenBankingResponse" } } } @@ -19935,6 +20552,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": [ @@ -20114,6 +20754,21 @@ } ] }, + "RealTimePaymentDataResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/RealTimePaymentData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "ReceiverDetails": { "type": "object", "required": [ @@ -21278,6 +21933,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": [ @@ -21911,6 +22585,43 @@ }, "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", + "example": "ab********@okhdfcbank", + "nullable": true + } + } + }, "UpiCollectData": { "type": "object", "properties": { @@ -21950,6 +22661,21 @@ "UpiIntentData": { "type": "object" }, + "UpiResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/UpiAdditionalData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "ValueType": { "oneOf": [ { @@ -22244,6 +22970,21 @@ } ] }, + "VoucherResponse": { + "allOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/VoucherData" + } + ], + "nullable": true + }, + { + "type": "object" + } + ] + }, "Wallet": { "oneOf": [ { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index cd32c045f1..be7b6ae456 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, @@ -2033,6 +2033,8 @@ pub enum AdditionalPaymentData { Card(Box), BankRedirect { bank_name: Option, + #[serde(flatten)] + details: Option, }, Wallet { apple_pay: Option, @@ -2040,18 +2042,48 @@ pub enum AdditionalPaymentData { PayLater { klarna_sdk: Option, }, - BankTransfer {}, - Crypto {}, - BankDebit {}, + BankTransfer { + #[serde(flatten)] + details: Option, + }, + Crypto { + #[serde(flatten)] + details: Option, + }, + BankDebit { + #[serde(flatten)] + details: Option, + }, MandatePayment {}, Reward {}, - RealTimePayment {}, - Upi {}, - GiftCard {}, - Voucher {}, - CardRedirect {}, - CardToken {}, - OpenBanking {}, + RealTimePayment { + #[serde(flatten)] + details: Option, + }, + Upi { + #[serde(flatten)] + details: Option, + }, + GiftCard { + #[serde(flatten)] + details: Option, + }, + Voucher { + #[serde(flatten)] + details: Option, + }, + CardRedirect { + #[serde(flatten)] + details: Option, + }, + CardToken { + #[serde(flatten)] + details: Option, + }, + OpenBanking { + #[serde(flatten)] + details: Option, + }, } #[derive(Debug, Clone, Eq, PartialEq, serde::Deserialize, serde::Serialize)] @@ -3018,21 +3050,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) } } @@ -3048,23 +3080,98 @@ 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 {}, + BankTransfer(Box), Wallet {}, PayLater(Box), - BankRedirect {}, - Crypto {}, - BankDebit {}, + BankRedirect(Box), + Crypto(Box), + BankDebit(Box), MandatePayment {}, Reward {}, - RealTimePayment {}, - Upi {}, - Voucher {}, - GiftCard {}, - CardRedirect {}, - CardToken {}, - OpenBanking {}, + RealTimePayment(Box), + Upi(Box), + Voucher(Box), + GiftCard(Box), + CardRedirect(Box), + CardToken(Box), + OpenBanking(Box), +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct BankDebitResponse { + #[serde(flatten)] + #[schema(value_type = Option)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)] +#[serde(rename_all = "snake_case", tag = "type")] +pub struct BankRedirectResponse { + /// Name of the bank + #[schema(value_type = Option)] + pub bank_name: Option, + #[serde(flatten)] + #[schema(value_type = Option)] + pub details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct BankTransferResponse { + #[serde(flatten)] + #[schema(value_type = Option)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct CardRedirectResponse { + #[serde(flatten)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct CardTokenResponse { + #[serde(flatten)] + #[schema(value_type = Option)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct CryptoResponse { + #[serde(flatten)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct GiftCardResponse { + #[serde(flatten)] + #[schema(value_type = Option)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct OpenBankingResponse { + #[serde(flatten)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct RealTimePaymentDataResponse { + #[serde(flatten)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct UpiResponse { + #[serde(flatten)] + #[schema(value_type = Option)] + details: Option, +} + +#[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] +pub struct VoucherResponse { + #[serde(flatten)] + details: Option, } #[derive(Eq, PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize, ToSchema)] @@ -4306,19 +4413,39 @@ 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, details } => { + Self::BankRedirect(Box::new(BankRedirectResponse { bank_name, details })) + } + AdditionalPaymentData::Crypto { details } => { + Self::Crypto(Box::new(CryptoResponse { details })) + } + AdditionalPaymentData::BankDebit { details } => { + Self::BankDebit(Box::new(BankDebitResponse { details })) + } 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 { details } => { + Self::RealTimePayment(Box::new(RealTimePaymentDataResponse { details })) + } + AdditionalPaymentData::Upi { details } => Self::Upi(Box::new(UpiResponse { details })), + AdditionalPaymentData::BankTransfer { details } => { + Self::BankTransfer(Box::new(BankTransferResponse { details })) + } + AdditionalPaymentData::Voucher { details } => { + Self::Voucher(Box::new(VoucherResponse { details })) + } + AdditionalPaymentData::GiftCard { details } => { + Self::GiftCard(Box::new(GiftCardResponse { details })) + } + AdditionalPaymentData::CardRedirect { details } => { + Self::CardRedirect(Box::new(CardRedirectResponse { details })) + } + AdditionalPaymentData::CardToken { details } => { + Self::CardToken(Box::new(CardTokenResponse { details })) + } + AdditionalPaymentData::OpenBanking { details } => { + Self::OpenBanking(Box::new(OpenBankingResponse { details })) + } } } } 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..77500b0edc --- /dev/null +++ b/crates/api_models/src/payments/additional_info.rs @@ -0,0 +1,213 @@ +use common_utils::new_type::{ + MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId, +}; +use masking::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: MaskedBankAccount, + + /// Partially masked routing number for ach bank debit payment + #[schema(value_type = String, example = "110***000")] + pub routing_number: MaskedRoutingNumber, + + /// Card holder's name + #[schema(value_type = Option, example = "John Doe")] + pub card_holder_name: Option>, + + /// 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: MaskedBankAccount, + + /// Partially masked sort code for Bacs payment method + #[schema(value_type = String, example = "108800")] + pub sort_code: MaskedSortCode, + + /// 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: MaskedBankAccount, + + /// 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: MaskedIban, + + /// 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 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, example = "ab********@okhdfcbank")] + pub vpa_id: Option, +} diff --git a/crates/common_utils/src/new_type.rs b/crates/common_utils/src/new_type.rs index 01d23448d2..9d05e0be27 100644 --- a/crates/common_utils/src/new_type.rs +++ b/crates/common_utils/src/new_type.rs @@ -1,5 +1,7 @@ //! Contains new types with restrictions -use crate::consts::MAX_ALLOWED_MERCHANT_NAME_LENGTH; +use masking::{ExposeInterface, Secret}; + +use crate::{consts::MAX_ALLOWED_MERCHANT_NAME_LENGTH, pii::UpiVpaMaskingStrategy}; #[nutype::nutype( derive(Clone, Serialize, Deserialize, Debug), @@ -8,3 +10,202 @@ use crate::consts::MAX_ALLOWED_MERCHANT_NAME_LENGTH; pub struct MerchantName(String); impl masking::SerializableSecret for MerchantName {} + +/// Function for masking alphanumeric characters in a string. +/// +/// # Arguments +/// `val` +/// - holds reference to the string to be masked. +/// `unmasked_char_count` +/// - minimum character count to remain unmasked for identification +/// - this number is for keeping the characters unmasked from +/// both beginning (if feasible) and ending of the string. +/// `min_masked_char_count` +/// - this ensures the minimum number of characters to be masked +/// +/// # Behaviour +/// - Returns the original string if its length is less than or equal to `unmasked_char_count`. +/// - If the string length allows, keeps `unmasked_char_count` characters unmasked at both start and end. +/// - Otherwise, keeps `unmasked_char_count` characters unmasked only at the end. +/// - Only alphanumeric characters are masked; other characters remain unchanged. +/// +/// # Examples +/// Sort Code +/// (12-34-56, 2, 2) -> 12-**-56 +/// Routing number +/// (026009593, 3, 3) -> 026***593 +/// CNPJ +/// (12345678901, 4, 4) -> *******8901 +/// CNPJ +/// (12345678901, 4, 3) -> 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; + let range = mask_start_index..=mask_end_index; + + val.chars() + .enumerate() + .fold(String::new(), |mut acc, (index, ch)| { + if ch.is_alphanumeric() && range.contains(&index) { + acc.push('*'); + } else { + acc.push(ch); + } + acc + }) +} + +/// Masked sort code +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedSortCode(Secret); +impl From for MaskedSortCode { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 2, 2); + Self(Secret::from(masked_value)) + } +} +impl From> for MaskedSortCode { + fn from(secret: Secret) -> Self { + Self::from(secret.expose()) + } +} + +/// Masked Routing number +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedRoutingNumber(Secret); +impl From for MaskedRoutingNumber { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 3, 3); + Self(Secret::from(masked_value)) + } +} +impl From> for MaskedRoutingNumber { + fn from(secret: Secret) -> Self { + Self::from(secret.expose()) + } +} + +/// Masked bank account +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedBankAccount(Secret); +impl From for MaskedBankAccount { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 4, 4); + Self(Secret::from(masked_value)) + } +} +impl From> for MaskedBankAccount { + fn from(secret: Secret) -> Self { + Self::from(secret.expose()) + } +} + +/// Masked IBAN +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedIban(Secret); +impl From for MaskedIban { + fn from(src: String) -> Self { + let masked_value = apply_mask(src.as_ref(), 5, 5); + Self(Secret::from(masked_value)) + } +} +impl From> for MaskedIban { + fn from(secret: Secret) -> Self { + Self::from(secret.expose()) + } +} + +/// Masked UPI ID +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct MaskedUpiVpaId(Secret); +impl From for MaskedUpiVpaId { + fn from(src: String) -> Self { + let unmasked_char_count = 2; + let masked_value = if let Some((user_identifier, bank_or_psp)) = src.split_once('@') { + let masked_user_identifier = user_identifier + .to_string() + .chars() + .take(unmasked_char_count) + .collect::() + + &"*".repeat(user_identifier.len() - unmasked_char_count); + format!("{}@{}", masked_user_identifier, bank_or_psp) + } else { + let masked_value = apply_mask(src.as_ref(), unmasked_char_count, 8); + masked_value + }; + + Self(Secret::from(masked_value)) + } +} +impl From> for MaskedUpiVpaId { + fn from(secret: Secret) -> Self { + Self::from(secret.expose()) + } +} + +#[cfg(test)] +mod apply_mask_fn_test { + use masking::PeekInterface; + + use crate::new_type::{ + apply_mask, MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, + MaskedUpiVpaId, + }; + #[test] + fn test_masked_types() { + let sort_code = MaskedSortCode::from("110011".to_string()); + let routing_number = MaskedRoutingNumber::from("056008849".to_string()); + let bank_account = MaskedBankAccount::from("12345678901234".to_string()); + let iban = MaskedIban::from("NL02ABNA0123456789".to_string()); + let upi_vpa = MaskedUpiVpaId::from("someusername@okhdfcbank".to_string()); + + // Standard masked data tests + assert_eq!(sort_code.0.peek().to_owned(), "11**11".to_string()); + assert_eq!(routing_number.0.peek().to_owned(), "056***849".to_string()); + assert_eq!( + bank_account.0.peek().to_owned(), + "1234******1234".to_string() + ); + assert_eq!(iban.0.peek().to_owned(), "NL02A********56789".to_string()); + assert_eq!( + upi_vpa.0.peek().to_owned(), + "so**********@okhdfcbank".to_string() + ); + } + + #[test] + fn test_apply_mask_fn() { + let value = "12345678901".to_string(); + + // Generic masked tests + assert_eq!(apply_mask(&value, 2, 2), "12*******01".to_string()); + assert_eq!(apply_mask(&value, 3, 2), "123*****901".to_string()); + assert_eq!(apply_mask(&value, 3, 3), "123*****901".to_string()); + assert_eq!(apply_mask(&value, 4, 3), "1234***8901".to_string()); + assert_eq!(apply_mask(&value, 4, 4), "*******8901".to_string()); + assert_eq!(apply_mask(&value, 5, 4), "******78901".to_string()); + assert_eq!(apply_mask(&value, 5, 5), "******78901".to_string()); + assert_eq!(apply_mask(&value, 6, 5), "*****678901".to_string()); + assert_eq!(apply_mask(&value, 6, 6), "*****678901".to_string()); + assert_eq!(apply_mask(&value, 7, 6), "****5678901".to_string()); + assert_eq!(apply_mask(&value, 7, 7), "****5678901".to_string()); + assert_eq!(apply_mask(&value, 8, 7), "***45678901".to_string()); + assert_eq!(apply_mask(&value, 8, 8), "***45678901".to_string()); + } +} diff --git a/crates/hyperswitch_domain_models/src/payment_method_data.rs b/crates/hyperswitch_domain_models/src/payment_method_data.rs index 5bff7b489c..f714dfac86 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, + new_type::{ + MaskedBankAccount, MaskedIban, MaskedRoutingNumber, MaskedSortCode, MaskedUpiVpaId, + }, pii::{self, Email}, }; -use masking::Secret; +use masking::{PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use time::Date; @@ -281,6 +284,7 @@ pub enum BankRedirectData { card_number: Option, card_exp_month: Option>, card_exp_year: Option>, + card_holder_name: Option>, }, Bizum {}, Blik { @@ -288,19 +292,26 @@ pub enum BankRedirectData { }, Eps { bank_name: Option, + country: Option, }, Giropay { bank_account_bic: Option>, bank_account_iban: Option>, + country: Option, }, Ideal { bank_name: Option, }, - Interac {}, + Interac { + country: Option, + email: Option, + }, OnlineBankingCzechRepublic { issuer: common_enums::BankNames, }, - OnlineBankingFinland {}, + OnlineBankingFinland { + email: Option, + }, OnlineBankingPoland { issuer: common_enums::BankNames, }, @@ -309,14 +320,18 @@ pub enum BankRedirectData { }, OpenBankingUk { issuer: Option, + country: Option, }, Przelewy24 { bank_name: Option, }, Sofort { + country: Option, preferred_language: Option, }, - Trustly {}, + Trustly { + country: Option, + }, OnlineBankingFpx { issuer: common_enums::BankNames, }, @@ -421,20 +436,25 @@ pub enum BankDebitData { AchBankDebit { account_number: Secret, routing_number: Secret, + card_holder_name: Option>, + bank_account_holder_name: Option>, bank_name: Option, bank_type: Option, bank_holder_type: Option, }, SepaBankDebit { iban: Secret, + bank_account_holder_name: Option>, }, BecsBankDebit { account_number: Secret, bsb_number: Secret, + bank_account_holder_name: Option>, }, BacsBankDebit { account_number: Secret, sort_code: Secret, + bank_account_holder_name: Option>, }, } @@ -581,6 +601,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 { @@ -729,34 +760,40 @@ impl From for BankRedirectData { card_number, card_exp_month, card_exp_year, + card_holder_name, .. } => Self::BancontactCard { card_number, card_exp_month, card_exp_year, + card_holder_name, }, api_models::payments::BankRedirectData::Bizum {} => Self::Bizum {}, api_models::payments::BankRedirectData::Blik { blik_code } => Self::Blik { blik_code }, - api_models::payments::BankRedirectData::Eps { bank_name, .. } => { - Self::Eps { bank_name } - } + api_models::payments::BankRedirectData::Eps { + bank_name, country, .. + } => Self::Eps { bank_name, country }, api_models::payments::BankRedirectData::Giropay { bank_account_bic, bank_account_iban, + country, .. } => Self::Giropay { bank_account_bic, bank_account_iban, + country, }, api_models::payments::BankRedirectData::Ideal { bank_name, .. } => { Self::Ideal { bank_name } } - api_models::payments::BankRedirectData::Interac { .. } => Self::Interac {}, + api_models::payments::BankRedirectData::Interac { country, email } => { + Self::Interac { country, email } + } api_models::payments::BankRedirectData::OnlineBankingCzechRepublic { issuer } => { Self::OnlineBankingCzechRepublic { issuer } } - api_models::payments::BankRedirectData::OnlineBankingFinland { .. } => { - Self::OnlineBankingFinland {} + api_models::payments::BankRedirectData::OnlineBankingFinland { email } => { + Self::OnlineBankingFinland { email } } api_models::payments::BankRedirectData::OnlineBankingPoland { issuer } => { Self::OnlineBankingPoland { issuer } @@ -764,16 +801,23 @@ impl From for BankRedirectData { api_models::payments::BankRedirectData::OnlineBankingSlovakia { issuer } => { Self::OnlineBankingSlovakia { issuer } } - api_models::payments::BankRedirectData::OpenBankingUk { issuer, .. } => { - Self::OpenBankingUk { issuer } - } + api_models::payments::BankRedirectData::OpenBankingUk { + country, issuer, .. + } => Self::OpenBankingUk { country, issuer }, api_models::payments::BankRedirectData::Przelewy24 { bank_name, .. } => { Self::Przelewy24 { bank_name } } api_models::payments::BankRedirectData::Sofort { - preferred_language, .. - } => Self::Sofort { preferred_language }, - api_models::payments::BankRedirectData::Trustly { .. } => Self::Trustly {}, + preferred_language, + country, + .. + } => Self::Sofort { + country, + preferred_language, + }, + api_models::payments::BankRedirectData::Trustly { country } => Self::Trustly { + country: Some(country), + }, api_models::payments::BankRedirectData::OnlineBankingFpx { issuer } => { Self::OnlineBankingFpx { issuer } } @@ -800,6 +844,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 +868,21 @@ 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.map(MaskedUpiVpaId::from), + }, + )), + 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 +914,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 +986,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,12 +1022,23 @@ 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 { api_models::payments::BankDebitData::AchBankDebit { account_number, routing_number, + card_holder_name, + bank_account_holder_name, bank_name, bank_type, bank_holder_type, @@ -880,33 +1046,101 @@ impl From for BankDebitData { } => Self::AchBankDebit { account_number, routing_number, + card_holder_name, + bank_account_holder_name, bank_name, bank_type, bank_holder_type, }, - api_models::payments::BankDebitData::SepaBankDebit { iban, .. } => { - Self::SepaBankDebit { iban } - } + api_models::payments::BankDebitData::SepaBankDebit { + iban, + bank_account_holder_name, + .. + } => Self::SepaBankDebit { + iban, + bank_account_holder_name, + }, api_models::payments::BankDebitData::BecsBankDebit { account_number, bsb_number, + bank_account_holder_name, .. } => Self::BecsBankDebit { account_number, bsb_number, + bank_account_holder_name, }, api_models::payments::BankDebitData::BacsBankDebit { account_number, sort_code, + bank_account_holder_name, .. } => Self::BacsBankDebit { account_number, sort_code, + bank_account_holder_name, }, } } } +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, + card_holder_name, + bank_account_holder_name, + } => Self::Ach(Box::new( + payment_additional_types::AchBankDebitAdditionalData { + account_number: MaskedBankAccount::from(account_number), + routing_number: MaskedRoutingNumber::from(routing_number), + bank_name, + bank_type, + bank_holder_type, + card_holder_name, + bank_account_holder_name, + }, + )), + BankDebitData::SepaBankDebit { + iban, + bank_account_holder_name, + } => Self::Sepa(Box::new( + payment_additional_types::SepaBankDebitAdditionalData { + iban: MaskedIban::from(iban), + bank_account_holder_name, + }, + )), + BankDebitData::BecsBankDebit { + account_number, + bsb_number, + bank_account_holder_name, + } => Self::Becs(Box::new( + payment_additional_types::BecsBankDebitAdditionalData { + account_number: MaskedBankAccount::from(account_number), + bsb_number, + bank_account_holder_name, + }, + )), + BankDebitData::BacsBankDebit { + account_number, + sort_code, + bank_account_holder_name, + } => Self::Bacs(Box::new( + payment_additional_types::BacsBankDebitAdditionalData { + account_number: MaskedBankAccount::from(account_number), + sort_code: MaskedSortCode::from(sort_code), + bank_account_holder_name, + }, + )), + } + } +} + impl From for BankTransferData { fn from(value: api_models::payments::BankTransferData) -> Self { match value { @@ -954,6 +1188,37 @@ 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(MaskedBankAccount::from), + cpf: cpf.map(MaskedBankAccount::from), + cnpj: cnpj.map(MaskedBankAccount::from), + }, + )), + BankTransferData::Pse {} => Self::Pse {}, + BankTransferData::LocalBankTransfer { bank_code } => Self::LocalBankTransfer(Box::new( + api_models::payments::additional_info::LocalBankTransferAdditionalData { + bank_code: bank_code.map(MaskedBankAccount::from), + }, + )), + } + } +} + impl From for RealTimePaymentData { fn from(value: api_models::payments::RealTimePaymentData) -> Self { match value { @@ -965,6 +1230,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 +1249,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..ca0da6b676 100644 --- a/crates/masking/src/lib.rs +++ b/crates/masking/src/lib.rs @@ -35,6 +35,7 @@ pub use self::bytes::SecretBytesMut; #[cfg(feature = "alloc")] mod string; + #[cfg(feature = "alloc")] mod vec; diff --git a/crates/openapi/src/openapi.rs b/crates/openapi/src/openapi.rs index 291b883561..2926f47af9 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, @@ -571,6 +573,34 @@ 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::BankDebitResponse, + api_models::payments::BankRedirectResponse, + api_models::payments::BankTransferResponse, + api_models::payments::CardRedirectResponse, + api_models::payments::CardTokenResponse, + api_models::payments::CryptoResponse, + api_models::payments::GiftCardResponse, + api_models::payments::OpenBankingResponse, + api_models::payments::RealTimePaymentDataResponse, + api_models::payments::UpiResponse, + api_models::payments::VoucherResponse, + 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::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, api_models::payments::PaymentsDynamicTaxCalculationRequest, )), modifiers(&SecurityAddon) diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 26765a29c3..25eab97d3e 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -167,6 +167,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, @@ -487,6 +489,34 @@ 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::BankDebitResponse, + api_models::payments::BankRedirectResponse, + api_models::payments::BankTransferResponse, + api_models::payments::CardRedirectResponse, + api_models::payments::CardTokenResponse, + api_models::payments::CryptoResponse, + api_models::payments::GiftCardResponse, + api_models::payments::OpenBankingResponse, + api_models::payments::RealTimePaymentDataResponse, + api_models::payments::UpiResponse, + api_models::payments::VoucherResponse, + 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::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/connector/aci/transformers.rs b/crates/router/src/connector/aci/transformers.rs index da31eae22a..5842143ad4 100644 --- a/crates/router/src/connector/aci/transformers.rs +++ b/crates/router/src/connector/aci/transformers.rs @@ -225,7 +225,7 @@ impl customer_email: Some(item.router_data.get_billing_email()?), })) } - domain::BankRedirectData::Interac {} => { + domain::BankRedirectData::Interac { .. } => { Self::BankRedirect(Box::new(BankRedirectionPMData { payment_brand: PaymentBrand::InteracOnline, bank_account_country: Some(item.router_data.get_billing_country()?), @@ -238,7 +238,7 @@ impl customer_email: Some(item.router_data.get_billing_email()?), })) } - domain::BankRedirectData::Trustly {} => { + domain::BankRedirectData::Trustly { .. } => { Self::BankRedirect(Box::new(BankRedirectionPMData { payment_brand: PaymentBrand::Trustly, bank_account_country: None, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index a9431d957e..9066d55604 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -2951,7 +2951,7 @@ fn get_redirect_extra_details( let country = item.get_optional_billing_country(); Ok((preferred_language.clone(), country)) } - domain::BankRedirectData::Trustly {} + domain::BankRedirectData::Trustly { .. } | domain::BankRedirectData::OpenBankingUk { .. } => { let country = item.get_optional_billing_country(); Ok((None, country)) diff --git a/crates/router/src/connector/gocardless/transformers.rs b/crates/router/src/connector/gocardless/transformers.rs index 572e4efa33..f3250602db 100644 --- a/crates/router/src/connector/gocardless/transformers.rs +++ b/crates/router/src/connector/gocardless/transformers.rs @@ -285,6 +285,7 @@ impl TryFrom<(&domain::BankDebitData, &types::TokenizationRouterData)> for Custo domain::BankDebitData::BecsBankDebit { account_number, bsb_number, + .. } => { let country_code = item.get_billing_country()?; let account_holder_name = item.get_billing_full_name()?; diff --git a/crates/router/src/connector/iatapay/transformers.rs b/crates/router/src/connector/iatapay/transformers.rs index f6b8c266ce..fde80abd25 100644 --- a/crates/router/src/connector/iatapay/transformers.rs +++ b/crates/router/src/connector/iatapay/transformers.rs @@ -160,7 +160,7 @@ impl | domain::BankRedirectData::Giropay { .. } | domain::BankRedirectData::Interac { .. } | domain::BankRedirectData::OnlineBankingCzechRepublic { .. } - | domain::BankRedirectData::OnlineBankingFinland {} + | domain::BankRedirectData::OnlineBankingFinland { .. } | domain::BankRedirectData::OnlineBankingPoland { .. } | domain::BankRedirectData::OnlineBankingSlovakia { .. } | domain::BankRedirectData::OpenBankingUk { .. } diff --git a/crates/router/src/connector/paypal/transformers.rs b/crates/router/src/connector/paypal/transformers.rs index fd2b262c7e..4f5ab13373 100644 --- a/crates/router/src/connector/paypal/transformers.rs +++ b/crates/router/src/connector/paypal/transformers.rs @@ -265,7 +265,7 @@ fn get_payment_source( bank_redirection_data: &domain::BankRedirectData, ) -> Result> { match bank_redirection_data { - domain::BankRedirectData::Eps { bank_name: _ } => { + domain::BankRedirectData::Eps { bank_name: _, .. } => { Ok(PaymentSourceItem::Eps(RedirectRequest { name: item.get_billing_full_name()?, country_code: item.get_billing_country()?, @@ -315,6 +315,7 @@ fn get_payment_source( } domain::BankRedirectData::Sofort { preferred_language: _, + .. } => Ok(PaymentSourceItem::Sofort(RedirectRequest { name: item.get_billing_full_name()?, country_code: item.get_billing_country()?, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index d9c5215546..f8a58158d0 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -4,14 +4,19 @@ 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; use common_utils::{ crypto::Encryptable, ext_traits::{AsyncExt, ByteSliceExt, Encode, ValueExt}, - fp_utils, generate_id, id_type, pii, type_name, + fp_utils, generate_id, id_type, + new_type::{MaskedIban, MaskedSortCode}, + pii, type_name, types::{ keymanager::{Identifier, KeyManagerState, ToEncryptable}, MinorUnit, @@ -3933,16 +3938,69 @@ pub async fn get_additional_payment_data( domain::BankRedirectData::Eps { bank_name, .. } => { Some(api_models::payments::AdditionalPaymentData::BankRedirect { bank_name: bank_name.to_owned(), + details: None, }) } domain::BankRedirectData::Ideal { bank_name, .. } => { Some(api_models::payments::AdditionalPaymentData::BankRedirect { bank_name: bank_name.to_owned(), + details: None, }) } - _ => { - Some(api_models::payments::AdditionalPaymentData::BankRedirect { bank_name: None }) + domain::BankRedirectData::BancontactCard { + card_number, + card_exp_month, + card_exp_year, + card_holder_name, + } => Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + 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: card_holder_name.clone(), + }, + )), + ), + }), + domain::BankRedirectData::Blik { blik_code } => { + Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + 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, + country, + } => Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + details: Some(payment_additional_types::BankRedirectDetails::Giropay( + Box::new( + payment_additional_types::GiropayBankRedirectAdditionalData { + bic: bank_account_bic + .as_ref() + .map(|bic| MaskedSortCode::from(bic.to_owned())), + iban: bank_account_iban + .as_ref() + .map(|iban| MaskedIban::from(iban.to_owned())), + country: *country, + }, + ), + )), + }), + _ => Some(api_models::payments::AdditionalPaymentData::BankRedirect { + bank_name: None, + details: None, + }), }, domain::PaymentMethodData::Wallet(wallet) => match wallet { domain::WalletData::ApplePay(apple_pay_wallet_data) => { @@ -3959,14 +4017,20 @@ 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::BankTransfer(bank_transfer) => { + Some(api_models::payments::AdditionalPaymentData::BankTransfer { + details: Some((*(bank_transfer.to_owned())).into()), + }) } - domain::PaymentMethodData::Crypto(_) => { - Some(api_models::payments::AdditionalPaymentData::Crypto {}) + domain::PaymentMethodData::Crypto(crypto) => { + Some(api_models::payments::AdditionalPaymentData::Crypto { + details: Some(crypto.to_owned().into()), + }) } - domain::PaymentMethodData::BankDebit(_) => { - Some(api_models::payments::AdditionalPaymentData::BankDebit {}) + domain::PaymentMethodData::BankDebit(bank_debit) => { + Some(api_models::payments::AdditionalPaymentData::BankDebit { + details: Some(bank_debit.to_owned().into()), + }) } domain::PaymentMethodData::MandatePayment => { Some(api_models::payments::AdditionalPaymentData::MandatePayment {}) @@ -3974,26 +4038,40 @@ pub async fn get_additional_payment_data( 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 { + details: Some((*(realtime_payment.to_owned())).into()), + }, + ), + domain::PaymentMethodData::Upi(upi) => { + Some(api_models::payments::AdditionalPaymentData::Upi { + details: Some(upi.to_owned().into()), + }) } - domain::PaymentMethodData::Upi(_) => { - Some(api_models::payments::AdditionalPaymentData::Upi {}) + domain::PaymentMethodData::CardRedirect(card_redirect) => { + Some(api_models::payments::AdditionalPaymentData::CardRedirect { + details: Some(card_redirect.to_owned().into()), + }) } - domain::PaymentMethodData::CardRedirect(_) => { - Some(api_models::payments::AdditionalPaymentData::CardRedirect {}) + domain::PaymentMethodData::Voucher(voucher) => { + Some(api_models::payments::AdditionalPaymentData::Voucher { + details: Some(voucher.to_owned().into()), + }) } - domain::PaymentMethodData::Voucher(_) => { - Some(api_models::payments::AdditionalPaymentData::Voucher {}) + domain::PaymentMethodData::GiftCard(gift_card) => { + Some(api_models::payments::AdditionalPaymentData::GiftCard { + details: Some((*(gift_card.to_owned())).into()), + }) } - domain::PaymentMethodData::GiftCard(_) => { - Some(api_models::payments::AdditionalPaymentData::GiftCard {}) + domain::PaymentMethodData::CardToken(card_token) => { + Some(api_models::payments::AdditionalPaymentData::CardToken { + details: Some(card_token.to_owned().into()), + }) } - domain::PaymentMethodData::CardToken(_) => { - Some(api_models::payments::AdditionalPaymentData::CardToken {}) - } - domain::PaymentMethodData::OpenBanking(_) => { - Some(api_models::payments::AdditionalPaymentData::OpenBanking {}) + domain::PaymentMethodData::OpenBanking(open_banking) => { + Some(api_models::payments::AdditionalPaymentData::OpenBanking { + details: Some(open_banking.to_owned().into()), + }) } domain::PaymentMethodData::NetworkToken(_) => None, } diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 4380d60955..b95d78c8a0 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -860,17 +860,21 @@ pub async fn retrieve_payment_method_from_auth_service( bank_name: None, bank_type, bank_holder_type: None, + card_holder_name: None, + bank_account_holder_name: None, }) } pm_auth_types::PaymentMethodTypeDetails::Bacs(bacs) => { domain::PaymentMethodData::BankDebit(domain::BankDebitData::BacsBankDebit { account_number: bacs.account_number.clone(), sort_code: bacs.sort_code.clone(), + bank_account_holder_name: None, }) } pm_auth_types::PaymentMethodTypeDetails::Sepa(sepa) => { domain::PaymentMethodData::BankDebit(domain::BankDebitData::SepaBankDebit { iban: sepa.iban.clone(), + bank_account_holder_name: None, }) } };