--- title: "SCA for funds transfers" description: "Learn how to use our Authentication SDK to authenticate your users when they make transfers." url: "https://docs.adyen.com/business-accounts/sca-for-funds-transfers" source_url: "https://docs.adyen.com/business-accounts/sca-for-funds-transfers.md" canonical: "https://docs.adyen.com/business-accounts/sca-for-funds-transfers" last_modified: "2022-11-30T17:52:00+01:00" language: "en" --- # SCA for funds transfers Learn how to use our Authentication SDK to authenticate your users when they make transfers. Each time a user in the European Economic Area (EEA) wants to transfer funds, you must authenticate them using SCA. To do so: 1. [Check SCA eligibility](#initiate-authentication). 2. [Initiate the transfer](#initiate-transfer) using the `sdkOutput` that you got when you checked the device for SCA eligibility. 3. [Authenticate your user](#authenticate-user) with the Authentication SDK. 4. [Finalize the transfer](#finalize-transfer) using the `sdkOutput` from the authentication step. ## Requirements * Make sure that you have [installed the Authentication SDK](/business-accounts/install-auth-sdk).\ Make sure that you have [registered a device](/business-accounts/register-sca-devices) for your user. * Make sure that your [API credential](/business-accounts/manage-access#manage-api-credentials) has the following role: * **TransferService Webservice Initiate role** ## Check SCA eligibility Before initiating a transfer, you must check for SCA eligibility and initiate the process to authenticate your users. The following tabs explain how to check for SCA eligibility and initiate authentication using Kotlin, Swift, or JavaScript. ### Tab: Android (Kotlin) To check if the Android device is eligible for SCA: 1. Initiate the `AdyenAuthentication` class in your Activity or Fragment. **Initiate authentication** ```kotlin private lateinit var adyenAuthentication: AdyenAuthentication override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) adyenAuthentication = AdyenAuthentication(this) } ``` 2. Check if SCA is available on the device. **Check SCA eligibility** ```kotlin lifecycleScope.launch { val availabilityResult: AvailabilityResult = adyenAuthentication.checkAvailability() if (availabilityResult is AvailabilityResult.Available) { availabilityResult.sdkOutput } } ``` The function returns an `sdkOutput`. 3. Pass the `sdkOutput` to your server. ### Tab: iOS (Swift) To check if the iOS device is eligible for SCA: 1. Initialize the `AuthenticationService` class. **Initialize authentication service** ```swift let configuration = AuthenticationService.Configuration( localizedRegistrationReason: registrationReason, localizedAuthenticationReason: authenticationReason, appleTeamIdendtifier: appleTeamIdentifier ) let authenticationService = AuthenticationService(configuration: configuration) ``` 2. Check if SCA is available on the device. **Check SCA eligibility** ```swift let sdkOutput = try authenticationService.checkSupport() /// send the sdkOutput to your backend ``` The function returns an `sdkOutput`. 3. Pass the `sdkOutput` to your server. ### Tab: Web (JavaScript) To check if the web browser on your web-enabled device is eligible for SCA: 1. Import the node package in your application. `RelyingPartyName` is the name the user will be presented with when creating or validating a `WebAuthn` operation. We recommend that the value of the `RelyingPartyName` be the merchant name or the URL domain. **Import web sdk and initiate authentication** ```javascript import ScaWebauthn from '@adyen/bpscaweb'; const scaWebauthn = ScaWebauthn.create({ relyingPartyName: 'merchant', }); const sdkOutput = await scaWebauthn.checkAvailability().catch((error) => /* SCA_UNAVAILABLE error*/); ``` If the user's browser supports SCA, the function returns `sdkOutput` to exchange in requests to the server. If SCA is not supported, the method throws an `SCA_UNAVAILABLE` error. 2. Pass the `sdkOutput` to your server. You will use the `sdkOutput` when [initiating the transfer](#initiate-transfer). ## Initiate transfer The steps to initiate a transfer depend on whether you want to: * Authenticate the user when initiating a transfer request. * Authenticate the reviewer when approving a transfer request. Because a reviewer can approve multiple transfers at the same time, performing SCA during approval allows you to satisfy the authentication requirements for multiple transfers with a single SCA process. The following tabs explain both methods for initiating a transfer that requires SCA. ### Tab: Authenticate during initiation To initiate a funds transfer for your user and trigger SCA, do the following: 1. Make a POST [/transfers](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers) request, specifying the following parameters: | Parameter | Type | Required | Description | | -------------------------------------------------------------------------------------------------------------------------------- | ------ | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | [WWW-Authenticate](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#header-WWW_Authenticate) | Header | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | `SCA realm`: **Transfer**. `auth-param1`: Base64-encoded value of **sdkOutput** you get when you [initiate authentication](#initiate-authentication). | | [amount](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-amount) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | The amount of the transfer. | | [balanceAccountId](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-balanceAccountId) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | The unique identifier of the source balance account. | | [category](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-category) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Set to **bank**. | | [counterparty.bankAccount](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-counterparty-bankAccount) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Contains information about the target bank account. | | [description](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-description) | Body | | A human-readable description for the transfer. | | [reference](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-reference) | Body | | A reference of the transfer, only used internally within your balance platform. | | [referenceForBeneficiary](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-referenceForBeneficiary) | Body | | A reference that is sent to the recipient. | **Initiate funds transfer and trigger SCA** #### curl ```bash curl https://balanceplatform-api-test.adyen.com/btl/v4/transfers \ -H 'x-api-key: ADYEN_BALANCE_PLATFORM_API_KEY' \ -H 'content-type: application/json' \ -H 'WWW-Authenticate: SCA realm="Transfer" auth-param1="eyJjaGFsbGVuZ2UiOiJiVlV6ZW5wek0waFNl..."' \ -X POST \ -d '{ "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "bank", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } } }' ``` #### Java ```java // Adyen Java API Library v33.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.transfers.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.model.RequestOptions; import com.adyen.service.transfers.*; Client client = new Client("ADYEN_BALANCE_PLATFORM_API_KEY", Environment.TEST); // Create the request object(s) PartyIdentification partyIdentification3 = new PartyIdentification() .fullName("A. Klaassen"); IbanAccountIdentification ibanAccountIdentification = new IbanAccountIdentification() .iban("NL91ABNA0417164300") .type(IbanAccountIdentification.TypeEnum.IBAN); BankAccountV3 bankAccountV33 = new BankAccountV3() .accountHolder(partyIdentification3) .accountIdentification(new TransferInfoAccountIdentification(ibanAccountIdentification)); Amount amount = new Amount() .currency("EUR") .value(1000L); CounterpartyInfoV3 counterpartyInfoV3 = new CounterpartyInfoV3() .bankAccount(bankAccountV33); TransferInfo transferInfo = new TransferInfo() .balanceAccountId("BA00000000000000000000001") .reference("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER") .amount(amount) .referenceForBeneficiary("YOUR_REFERENCE_SENT_TO_BENEFICIARY") .description("YOUR_DESCRIPTION_FOR_THE_TRANSFER") .counterparty(counterpartyInfoV3) .category(TransferInfo.CategoryEnum.BANK); // Send the request TransfersApi service = new TransfersApi(client); Transfer response = service.transferFunds(transferInfo, new RequestOptions().idempotencyKey("UUID")); ``` #### PHP ```php setXApiKey("ADYEN_BALANCE_PLATFORM_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $partyIdentification3 = new PartyIdentification(); $partyIdentification3 ->setFullName("A. Klaassen"); $transferInfoAccountIdentification = new TransferInfoAccountIdentification(); $transferInfoAccountIdentification ->setIban("NL91ABNA0417164300") ->setType("iban"); $bankAccountV33 = new BankAccountV3(); $bankAccountV33 ->setAccountHolder($partyIdentification3) ->setAccountIdentification($transferInfoAccountIdentification); $amount = new Amount(); $amount ->setCurrency("EUR") ->setValue(1000); $counterpartyInfoV3 = new CounterpartyInfoV3(); $counterpartyInfoV3 ->setBankAccount($bankAccountV33); $transferInfo = new TransferInfo(); $transferInfo ->setBalanceAccountId("BA00000000000000000000001") ->setReference("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER") ->setAmount($amount) ->setReferenceForBeneficiary("YOUR_REFERENCE_SENT_TO_BENEFICIARY") ->setDescription("YOUR_DESCRIPTION_FOR_THE_TRANSFER") ->setCounterparty($counterpartyInfoV3) ->setCategory("bank"); $requestOptions['idempotencyKey'] = 'UUID'; // Send the request $service = new TransfersApi($client); $response = $service->transferFunds($transferInfo, $requestOptions); ``` #### C\# ```cs // Adyen .net API Library v28.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Transfers; using Adyen.Service.Transfers; var config = new Config() { XApiKey = "ADYEN_BALANCE_PLATFORM_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) PartyIdentification partyIdentification3 = new PartyIdentification { FullName = "A. Klaassen" }; IbanAccountIdentification ibanAccountIdentification = new IbanAccountIdentification { Iban = "NL91ABNA0417164300", Type = IbanAccountIdentification.TypeEnum.Iban }; BankAccountV3 bankAccountV33 = new BankAccountV3 { AccountHolder = partyIdentification3, AccountIdentification = new TransferInfoAccountIdentification(ibanAccountIdentification) }; Amount amount = new Amount { Currency = "EUR", Value = 1000 }; CounterpartyInfoV3 counterpartyInfoV3 = new CounterpartyInfoV3 { BankAccount = bankAccountV33 }; TransferInfo transferInfo = new TransferInfo { BalanceAccountId = "BA00000000000000000000001", Reference = "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", Amount = amount, ReferenceForBeneficiary = "YOUR_REFERENCE_SENT_TO_BENEFICIARY", Description = "YOUR_DESCRIPTION_FOR_THE_TRANSFER", Counterparty = counterpartyInfoV3, Category = TransferInfo.CategoryEnum.Bank }; // Send the request var service = new TransfersService(client); var response = service.TransferFunds(transferInfo, requestOptions: new RequestOptions { IdempotencyKey = "UUID"}); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v23.3.0 const { Client, TransfersAPI } = require('@adyen/api-library'); const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const transferInfo = { amount: { currency: "EUR", value: 1000 }, balanceAccountId: "BA00000000000000000000001", category: "bank", description: "YOUR_DESCRIPTION_FOR_THE_TRANSFER", reference: "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", referenceForBeneficiary: "YOUR_REFERENCE_SENT_TO_BENEFICIARY", counterparty: { bankAccount: { accountHolder: { fullName: "A. Klaassen" }, accountIdentification: { type: "iban", iban: "NL91ABNA0417164300" } } } } // Send the request const transfersAPI = new TransfersAPI(client); const response = transfersAPI.TransfersApi.transferFunds(transferInfo, { idempotencyKey: "UUID" }); ``` #### Go ```go // Adyen Go API Library v17.0.0 import ( "context" "github.com/adyen/adyen-go-api-library/v17/src/common" "github.com/adyen/adyen-go-api-library/v17/src/adyen" "github.com/adyen/adyen-go-api-library/v17/src/transfers" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) partyIdentification3 := transfers.PartyIdentification{ FullName: common.PtrString("A. Klaassen"), } ibanAccountIdentification := transfers.IbanAccountIdentification{ Iban: "NL91ABNA0417164300", Type: "iban", } bankAccountV33 := transfers.BankAccountV3{ AccountHolder: partyIdentification3, AccountIdentification: transfers.IbanAccountIdentificationAsTransferInfoAccountIdentification(&ibanAccountIdentification), } amount := transfers.Amount{ Currency: "EUR", Value: 1000, } counterpartyInfoV3 := transfers.CounterpartyInfoV3{ BankAccount: &bankAccountV33, } transferInfo := transfers.TransferInfo{ BalanceAccountId: common.PtrString("BA00000000000000000000001"), Reference: common.PtrString("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER"), Amount: amount, ReferenceForBeneficiary: common.PtrString("YOUR_REFERENCE_SENT_TO_BENEFICIARY"), Description: common.PtrString("YOUR_DESCRIPTION_FOR_THE_TRANSFER"), Counterparty: counterpartyInfoV3, Category: "bank", } // Send the request service := client.Transfers() req := service.TransfersApi.TransferFundsInput().IdempotencyKey("UUID").TransferInfo(transferInfo) res, httpRes, err := service.TransfersApi.TransferFunds(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v13.3.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_BALANCE_PLATFORM_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "bank", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } } } # Send the request result = adyen.transfers.transfers_api.transfer_funds(request=json_request, idempotency_key="UUID") ``` #### Ruby ```rb # Adyen Ruby API Library v10.1.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_BALANCE_PLATFORM_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :amount => { :currency => 'EUR', :value => 1000 }, :balanceAccountId => 'BA00000000000000000000001', :category => 'bank', :description => 'YOUR_DESCRIPTION_FOR_THE_TRANSFER', :reference => 'YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER', :referenceForBeneficiary => 'YOUR_REFERENCE_SENT_TO_BENEFICIARY', :counterparty => { :bankAccount => { :accountHolder => { :fullName => 'A. Klaassen' }, :accountIdentification => { :type => 'iban', :iban => 'NL91ABNA0417164300' } } } } # Send the request result = adyen.transfers.transfers_api.transfer_funds(request_body, headers: { 'Idempotency-Key' => 'UUID' }) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v23.3.0 import { Client, TransfersAPI, Types } from "@adyen/api-library"; const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const partyIdentification3: Types.transfers.PartyIdentification = { fullName: "A. Klaassen" }; const ibanAccountIdentification: Types.transfers.IbanAccountIdentification = { iban: "NL91ABNA0417164300", type: Types.transfers.IbanAccountIdentification.TypeEnum.Iban }; const bankAccountV33: Types.transfers.BankAccountV3 = { accountHolder: partyIdentification3, accountIdentification: ibanAccountIdentification }; const amount: Types.transfers.Amount = { currency: "EUR", value: 1000 }; const counterpartyInfoV3: Types.transfers.CounterpartyInfoV3 = { bankAccount: bankAccountV33 }; const transferInfo: Types.transfers.TransferInfo = { balanceAccountId: "BA00000000000000000000001", reference: "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", amount: amount, referenceForBeneficiary: "YOUR_REFERENCE_SENT_TO_BENEFICIARY", description: "YOUR_DESCRIPTION_FOR_THE_TRANSFER", counterparty: counterpartyInfoV3, category: Types.transfers.TransferInfo.CategoryEnum.Bank }; // Send the request const transfersAPI = new TransfersAPI(client); const response = transfersAPI.TransfersApi.transferFunds(transferInfo, { idempotencyKey: "UUID" }); ``` 2. Verify that the response header contains the following fields: * `status`: **401** * `auth-param1`: Base64-encoded blob of data. You will need `auth-param1` when you [authenticate your user](#authenticate-user). **Response header** ```json "WWW-Authenticate: SCA realm="Transfer" auth-param1="eyJjaGFsbGVuZ2UiOiJiVlV6ZW5wek0waFNl..."" ``` 3. Verify that the response body contains the following fields: * `amount`: An object containing the amount and currency of the funds that will be transferred. * `counterparty`: An object containing information about the counterparty that will receive the funds. You must show this data to your user when you [authenticate your user](#authenticate-user). **Response for initiating a fund transfer** ```json { "type": "https://docs.adyen.com/errors/unauthorized", "title": "Unauthorized", "status": 401, "response": { "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "bank", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } }, }, "errorCode": "00_401" } ``` 4. Pass `auth-param1` to the SDK as `sdkInput`. ### Tab: Authenticate during approval To initiate a funds transfer for your user and trigger SCA during approval, do the following: 1. Make a POST [/transfers](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers) request, specifying the following parameters: | Parameter | Type | Required | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | | [amount](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-amount) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | The amount of the transfer. | | [balanceAccountId](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-balanceAccountId) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | The unique identifier of the source balance account. | | [category](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-category) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Set to **bank**. | | [counterparty.bankAccount](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-counterparty-bankAccount) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Contains information about the target bank account. | | [description](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-description) | Body | | A human-readable description for the transfer. | | [reference](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-reference) | Body | | A reference of the transfer, only used internally within your balance platform. | | [referenceForBeneficiary](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-referenceForBeneficiary) | Body | | A reference that is sent to the recipient. | | [review.numberOfApprovalsRequired](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-review-numberOfApprovalsRequired) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Specifies the number of approvals required to process the transfer. | | [review.scaOnApproval](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-review-scaOnApproval) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | Set to **true**. | **Initiate funds transfer** #### curl ```bash curl https://balanceplatform-api-test.adyen.com/btl/v4/transfers \ -H 'x-api-key: YOUR_BALANCE_PLATFORM_API_KEY' \ -H 'content-type: application/json' \ -X POST \ -d '{ "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "bank", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } }, "review": { "numberOfApprovalsRequired": 1, "scaOnApproval": true } }' ``` #### Java ```java // Adyen Java API Library v33.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.transfers.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.model.RequestOptions; import com.adyen.service.transfers.*; Client client = new Client("YOUR_BALANCE_PLATFORM_API_KEY", Environment.TEST); // Create the request object(s) PartyIdentification partyIdentification3 = new PartyIdentification() .fullName("A. Klaassen"); IbanAccountIdentification ibanAccountIdentification = new IbanAccountIdentification() .iban("NL91ABNA0417164300") .type(IbanAccountIdentification.TypeEnum.IBAN); BankAccountV3 bankAccountV33 = new BankAccountV3() .accountHolder(partyIdentification3) .accountIdentification(new TransferInfoAccountIdentification(ibanAccountIdentification)); Amount amount = new Amount() .currency("EUR") .value(1000L); TransferRequestReview transferRequestReview = new TransferRequestReview() .numberOfApprovalsRequired(1) .scaOnApproval(true); CounterpartyInfoV3 counterpartyInfoV3 = new CounterpartyInfoV3() .bankAccount(bankAccountV33); TransferInfo transferInfo = new TransferInfo() .balanceAccountId("BA00000000000000000000001") .reference("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER") .amount(amount) .referenceForBeneficiary("YOUR_REFERENCE_SENT_TO_BENEFICIARY") .review(transferRequestReview) .description("YOUR_DESCRIPTION_FOR_THE_TRANSFER") .counterparty(counterpartyInfoV3) .category(TransferInfo.CategoryEnum.BANK); // Send the request TransfersApi service = new TransfersApi(client); Transfer response = service.transferFunds(transferInfo, new RequestOptions().idempotencyKey("UUID")); ``` #### PHP ```php setXApiKey("YOUR_BALANCE_PLATFORM_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $partyIdentification3 = new PartyIdentification(); $partyIdentification3 ->setFullName("A. Klaassen"); $transferInfoAccountIdentification = new TransferInfoAccountIdentification(); $transferInfoAccountIdentification ->setIban("NL91ABNA0417164300") ->setType("iban"); $bankAccountV33 = new BankAccountV3(); $bankAccountV33 ->setAccountHolder($partyIdentification3) ->setAccountIdentification($transferInfoAccountIdentification); $amount = new Amount(); $amount ->setCurrency("EUR") ->setValue(1000); $transferRequestReview = new TransferRequestReview(); $transferRequestReview ->setNumberOfApprovalsRequired(1) ->setScaOnApproval(true); $counterpartyInfoV3 = new CounterpartyInfoV3(); $counterpartyInfoV3 ->setBankAccount($bankAccountV33); $transferInfo = new TransferInfo(); $transferInfo ->setBalanceAccountId("BA00000000000000000000001") ->setReference("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER") ->setAmount($amount) ->setReferenceForBeneficiary("YOUR_REFERENCE_SENT_TO_BENEFICIARY") ->setReview($transferRequestReview) ->setDescription("YOUR_DESCRIPTION_FOR_THE_TRANSFER") ->setCounterparty($counterpartyInfoV3) ->setCategory("bank"); $requestOptions['idempotencyKey'] = 'UUID'; // Send the request $service = new TransfersApi($client); $response = $service->transferFunds($transferInfo, $requestOptions); ``` #### C\# ```cs // Adyen .net API Library v28.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Transfers; using Adyen.Service.Transfers; var config = new Config() { XApiKey = "YOUR_BALANCE_PLATFORM_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) PartyIdentification partyIdentification3 = new PartyIdentification { FullName = "A. Klaassen" }; IbanAccountIdentification ibanAccountIdentification = new IbanAccountIdentification { Iban = "NL91ABNA0417164300", Type = IbanAccountIdentification.TypeEnum.Iban }; BankAccountV3 bankAccountV33 = new BankAccountV3 { AccountHolder = partyIdentification3, AccountIdentification = new TransferInfoAccountIdentification(ibanAccountIdentification) }; Amount amount = new Amount { Currency = "EUR", Value = 1000 }; TransferRequestReview transferRequestReview = new TransferRequestReview { NumberOfApprovalsRequired = 1, ScaOnApproval = true }; CounterpartyInfoV3 counterpartyInfoV3 = new CounterpartyInfoV3 { BankAccount = bankAccountV33 }; TransferInfo transferInfo = new TransferInfo { BalanceAccountId = "BA00000000000000000000001", Reference = "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", Amount = amount, ReferenceForBeneficiary = "YOUR_REFERENCE_SENT_TO_BENEFICIARY", Review = transferRequestReview, Description = "YOUR_DESCRIPTION_FOR_THE_TRANSFER", Counterparty = counterpartyInfoV3, Category = TransferInfo.CategoryEnum.Bank }; // Send the request var service = new TransfersService(client); var response = service.TransferFunds(transferInfo, requestOptions: new RequestOptions { IdempotencyKey = "UUID"}); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v23.3.0 const { Client, TransfersAPI } = require('@adyen/api-library'); const client = new Client({ apiKey: "YOUR_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const transferInfo = { amount: { currency: "EUR", value: 1000 }, balanceAccountId: "BA00000000000000000000001", category: "bank", description: "YOUR_DESCRIPTION_FOR_THE_TRANSFER", reference: "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", referenceForBeneficiary: "YOUR_REFERENCE_SENT_TO_BENEFICIARY", counterparty: { bankAccount: { accountHolder: { fullName: "A. Klaassen" }, accountIdentification: { type: "iban", iban: "NL91ABNA0417164300" } } }, review: { numberOfApprovalsRequired: 1, scaOnApproval: true } } // Send the request const transfersAPI = new TransfersAPI(client); const response = transfersAPI.TransfersApi.transferFunds(transferInfo, { idempotencyKey: "UUID" }); ``` #### Go ```go // Adyen Go API Library v17.0.0 import ( "context" "github.com/adyen/adyen-go-api-library/v17/src/common" "github.com/adyen/adyen-go-api-library/v17/src/adyen" "github.com/adyen/adyen-go-api-library/v17/src/transfers" ) client := adyen.NewClient(&common.Config{ ApiKey: "YOUR_BALANCE_PLATFORM_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) partyIdentification3 := transfers.PartyIdentification{ FullName: common.PtrString("A. Klaassen"), } ibanAccountIdentification := transfers.IbanAccountIdentification{ Iban: "NL91ABNA0417164300", Type: "iban", } bankAccountV33 := transfers.BankAccountV3{ AccountHolder: partyIdentification3, AccountIdentification: transfers.IbanAccountIdentificationAsTransferInfoAccountIdentification(&ibanAccountIdentification), } amount := transfers.Amount{ Currency: "EUR", Value: 1000, } transferRequestReview := transfers.TransferRequestReview{ NumberOfApprovalsRequired: common.PtrInt32(1), ScaOnApproval: common.PtrBool(true), } counterpartyInfoV3 := transfers.CounterpartyInfoV3{ BankAccount: &bankAccountV33, } transferInfo := transfers.TransferInfo{ BalanceAccountId: common.PtrString("BA00000000000000000000001"), Reference: common.PtrString("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER"), Amount: amount, ReferenceForBeneficiary: common.PtrString("YOUR_REFERENCE_SENT_TO_BENEFICIARY"), Review: &transferRequestReview, Description: common.PtrString("YOUR_DESCRIPTION_FOR_THE_TRANSFER"), Counterparty: counterpartyInfoV3, Category: "bank", } // Send the request service := client.Transfers() req := service.TransfersApi.TransferFundsInput().IdempotencyKey("UUID").TransferInfo(transferInfo) res, httpRes, err := service.TransfersApi.TransferFunds(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v13.3.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "YOUR_BALANCE_PLATFORM_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "bank", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } }, "review": { "numberOfApprovalsRequired": 1, "scaOnApproval": True } } # Send the request result = adyen.transfers.transfers_api.transfer_funds(request=json_request, idempotency_key="UUID") ``` #### Ruby ```rb # Adyen Ruby API Library v10.1.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'YOUR_BALANCE_PLATFORM_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :amount => { :currency => 'EUR', :value => 1000 }, :balanceAccountId => 'BA00000000000000000000001', :category => 'bank', :description => 'YOUR_DESCRIPTION_FOR_THE_TRANSFER', :reference => 'YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER', :referenceForBeneficiary => 'YOUR_REFERENCE_SENT_TO_BENEFICIARY', :counterparty => { :bankAccount => { :accountHolder => { :fullName => 'A. Klaassen' }, :accountIdentification => { :type => 'iban', :iban => 'NL91ABNA0417164300' } } }, :review => { :numberOfApprovalsRequired => 1, :scaOnApproval => true } } # Send the request result = adyen.transfers.transfers_api.transfer_funds(request_body, headers: { 'Idempotency-Key' => 'UUID' }) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v23.3.0 import { Client, TransfersAPI, Types } from "@adyen/api-library"; const client = new Client({ apiKey: "YOUR_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const partyIdentification3: Types.transfers.PartyIdentification = { fullName: "A. Klaassen" }; const ibanAccountIdentification: Types.transfers.IbanAccountIdentification = { iban: "NL91ABNA0417164300", type: Types.transfers.IbanAccountIdentification.TypeEnum.Iban }; const bankAccountV33: Types.transfers.BankAccountV3 = { accountHolder: partyIdentification3, accountIdentification: ibanAccountIdentification }; const amount: Types.transfers.Amount = { currency: "EUR", value: 1000 }; const transferRequestReview: Types.transfers.TransferRequestReview = { numberOfApprovalsRequired: 1, scaOnApproval: true }; const counterpartyInfoV3: Types.transfers.CounterpartyInfoV3 = { bankAccount: bankAccountV33 }; const transferInfo: Types.transfers.TransferInfo = { balanceAccountId: "BA00000000000000000000001", reference: "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", amount: amount, referenceForBeneficiary: "YOUR_REFERENCE_SENT_TO_BENEFICIARY", review: transferRequestReview, description: "YOUR_DESCRIPTION_FOR_THE_TRANSFER", counterparty: counterpartyInfoV3, category: Types.transfers.TransferInfo.CategoryEnum.Bank }; // Send the request const transfersAPI = new TransfersAPI(client); const response = transfersAPI.TransfersApi.transferFunds(transferInfo, { idempotencyKey: "UUID" }); ``` 2. Verify that you receive an **HTTP 202** response that includes the following parameters: * `amount`: You must show this data to your user during [authentication](#authenticate-user). * `counterparty`: You must show this data to your user during authentication. * `id`: You must include the transfer ID in the POST `/transfers/approve` request. 3. Make a POST [/transfers/approve](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers/approve) request, specifying the following parameters: | **Parameter name** | **Type** | **Required** | **Description** | | ----------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [WWW-Authenticate](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers/approve#header-WWW_Authenticate) | Header | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | `SCA realm`: **ApproveTransfers**. `auth-param1`: Base64-encoded value of **sdkOutput** you get when you [initiate the SCA authentication process](#initiate-authentication). | | [transferIds](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers/approve#request-transferIds) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | An array containing the unique identifiers of the transfers that you decide to approve. You can include the IDs of all transfers that have: — `status`: **received** — `reason`: **pendingApproval** | **Approve funds transfer and trigger SCA** #### curl ```bash curl https://balanceplatform-api-test.adyen.com/btl/v4/transfers/approve \ -H 'x-api-key: ADYEN_BALANCE_PLATFORM_API_KEY' \ -H 'content-type: application/json' \ -H 'WWW-Authenticate: SCA realm="ApproveTransfers" auth-param1="eyJjaGFsbGVuZ2UiOiJiVlV6ZW5wek0waFNl..."' \ -X POST \ -d '{ "transferIds": [ "APUFHASUFD4AS", "407ASFPUHASFA" ] }' ``` #### Java ```java // Adyen Java API Library v33.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.transfers.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.model.RequestOptions; import com.adyen.service.transfers.*; Client client = new Client("ADYEN_BALANCE_PLATFORM_API_KEY", Environment.TEST); // Create the request object(s) ApproveTransfersRequest approveTransfersRequest = new ApproveTransfersRequest() .transferIds(Arrays.asList("APUFHASUFD4AS", "407ASFPUHASFA")); // Send the request TransfersApi service = new TransfersApi(client); service.approveInitiatedTransfers(approveTransfersRequest, new RequestOptions().idempotencyKey("UUID")); ``` #### PHP ```php setXApiKey("ADYEN_BALANCE_PLATFORM_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $approveTransfersRequest = new ApproveTransfersRequest(); $approveTransfersRequest ->setTransferIds(array("APUFHASUFD4AS", "407ASFPUHASFA")); $requestOptions['idempotencyKey'] = 'UUID'; // Send the request $service = new TransfersApi($client); $service->approveInitiatedTransfers($approveTransfersRequest, $requestOptions); ``` #### C\# ```cs // Adyen .net API Library v28.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Transfers; using Adyen.Service.Transfers; var config = new Config() { XApiKey = "ADYEN_BALANCE_PLATFORM_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) ApproveTransfersRequest approveTransfersRequest = new ApproveTransfersRequest { TransferIds = { "APUFHASUFD4AS", "407ASFPUHASFA" } }; // Send the request var service = new TransfersService(client); service.ApproveInitiatedTransfers(approveTransfersRequest, requestOptions: new RequestOptions { IdempotencyKey = "UUID"}); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v23.3.0 const { Client, TransfersAPI } = require('@adyen/api-library'); const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const approveTransfersRequest = { transferIds: [ "APUFHASUFD4AS", "407ASFPUHASFA" ] } // Send the request const transfersAPI = new TransfersAPI(client); transfersAPI.TransfersApi.approveInitiatedTransfers(approveTransfersRequest, { idempotencyKey: "UUID" }); ``` #### Go ```go // Adyen Go API Library v17.0.0 import ( "context" "github.com/adyen/adyen-go-api-library/v17/src/common" "github.com/adyen/adyen-go-api-library/v17/src/adyen" "github.com/adyen/adyen-go-api-library/v17/src/transfers" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) approveTransfersRequest := transfers.ApproveTransfersRequest{ TransferIds: []string{ "APUFHASUFD4AS", "407ASFPUHASFA", }, } // Send the request service := client.Transfers() req := service.TransfersApi.ApproveInitiatedTransfersInput().IdempotencyKey("UUID").ApproveTransfersRequest(approveTransfersRequest) service.TransfersApi.ApproveInitiatedTransfers(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v13.3.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_BALANCE_PLATFORM_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "transferIds": [ "APUFHASUFD4AS", "407ASFPUHASFA" ] } # Send the request adyen.transfers.transfers_api.approve_initiated_transfers(request=json_request, idempotency_key="UUID") ``` #### Ruby ```rb # Adyen Ruby API Library v10.1.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_BALANCE_PLATFORM_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :transferIds => [ 'APUFHASUFD4AS', '407ASFPUHASFA' ] } # Send the request adyen.transfers.transfers_api.approve_initiated_transfers(request_body, headers: { 'Idempotency-Key' => 'UUID' }) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v23.3.0 import { Client, TransfersAPI, Types } from "@adyen/api-library"; const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const approveTransfersRequest: Types.transfers.ApproveTransfersRequest = { transferIds: ["APUFHASUFD4AS", "407ASFPUHASFA"] }; // Send the request const transfersAPI = new TransfersAPI(client); transfersAPI.TransfersApi.approveInitiatedTransfers(approveTransfersRequest, { idempotencyKey: "UUID" }); ``` 4. Verify that the response header contains the following fields: * `status`: **401** * `auth-param1`: Base64-encoded blob of data. You will need `auth-param1` when you [authenticate your user](#authenticate-user). **Response header** ```json "WWW-Authenticate: SCA realm="ApproveTransfers" auth-param1="eyJjaGFsbGVuZ2UiOiJiVlV6ZW5wek0waFNl..."" ``` **Response for initiating the approval of a fund transfer** ```json { "type": "https://docs.adyen.com/errors/unauthorized", "title": "Unauthorized", "status": 401, "response": { "transferIds": [ "APUFHASUFD4AS", "407ASFPUHASFA" ] }, "errorCode": "00_401" } ``` 5. Pass `auth-param1` to the SDK as `sdkInput`. ## Authenticate user After [initiating a transfer](#initiate-transfer) request, you have 10 minutes to complete the authentication process and [finalize the transfer request](#finalize-transfer). When authenticating your user, PSD2 requires you to show to your user the amount and the counterparty (payee) of the transfer that the user is authenticating for. To comply with these regulations, we recommend that you implement a push notification and use the `amount` and `counterparty` fields from: * The response to the POST [/transfers](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers) request you used to create the transfer. * The response to a GET [/transfers/{id}](https://docs.adyen.com/api-explorer/transfers/latest/get/transfers/\(id\)) request. To authenticate your user with the Authentication SDK: 1. Trigger the SDK to start user authentication and pass the `auth-param1` value from [the previous step](#initiate-authentication) as `sdkInput`. ### Tab: Android (Kotlin) **Authenticate with SCA SDK** ```kotlin lifecycleScope.launch { if (adyenAuthentication.hasCredential("sdkInput")) { // Authenticate existing credential val authenticationResult: AuthenticationResult = adyenAuthentication.authenticate("sdkInput") when (authenticationResult) { is AuthenticationResult.AuthenticationSuccessful -> { authenticationResult.sdkOutput } is AuthenticationResult.Canceled -> { // User cancelled the authentication flow } is AuthenticationResult.Error -> { // Unexpected error authenticationResult.errorMessage } is AuthenticationResult.AuthenticationError -> { // FIDO API Error authenticationResult.authenticationError } } } else { // None of the existing credentials exist in this device } } ``` If successful, the SDK generates a Base64-encoded `sdkOutput` data blob. ### Tab: iOS (Swift) **Authenticate with SCA SDK** ```swift delegatedAuthenticationSession.authenticate(withBase64URLString: sdkInput) { [weak self] result in switch result { case let .success(sdkOutput): /// send the sdkOutput to the backend case let .failure(error): /// authentication failed } } ``` The SDK uses the [Apple DeviceCheck framework](https://developer.apple.com/documentation/devicecheck) to generate a Base64-encoded `sdkOutput` data blob. To do this, the SDK authenticates the user using Touch ID, Face ID, or the device passcode. To enable Face ID support, add `NSFaceIDUsageDescription` to `Info.plist`. ### Tab: Web (JavaScript) **Authenticate with SCA SDK** ```javascript const sdkOutput = await scaWebauthn.authenticate(sdkInput); ``` If successful, the SDK generates a Base64-encoded `sdkOutput` data blob. 2. Pass `sdkOutput` to your server. ## Finalize transfer The steps to initiate a transfer depend on whether you: * Authenticated the user when initiating a transfer request. * Authenticated the reviewer when approving a transfer request. The following tabs explain both methods for finalizing a transfer after completing SCA. ### Tab: Authenticated during initiation To finalize the transfer: 1. Make a POST [/transfers](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers) request, specifying the following parameters: The values of the body parameters must match the ones previously submitted to the `/transfers` endpoint [when initiating the transfer](#initiate-transfer). | Parameter | Type | Description | | ------------------------------------------------------------------------------------------------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [WWW-Authenticate](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#header-WWW_Authenticate) | Header | `SCA realm`: **Transfer**. `auth-param1`: Base64-encoded value of **sdkOutput** you get from the Authentication SDK when you [authenticate the user](#authenticate-user). | | [amount](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-amount) | Body | The amount of the transfer. | | [category](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-category) | Body | Set to **bank**. | | [description](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-description) | Body | A human-readable description for the transfer. | | [balanceAccountId](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-balanceAccountId) | Body | The unique identifier of the source balance account. | | [reference](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-reference) | Body | A reference of the transfer, only used internally within your balance platform. | | [referenceForBeneficiary](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-referenceForBeneficiary) | Body | A reference that is sent to the recipient. | | [counterparty.balanceAccountId](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers#request-counterparty-balanceAccountId) | Body | The unique identifier of the target balance account. | **Finalize funds transfer** #### curl ```bash curl 'https://balanceplatform-api-test.adyen.com/btl/v4/transfers' \ -H 'x-api-key: ADYEN_BALANCE_PLATFORM_API_KEY' \ -H 'content-type: application/json' \ -H 'WWW-Authenticate: SCA realm="Transfer" auth-param1="CeCcEEJf2UPC7pB0K7AtEgLZX7cTvnqNznJF...' \ -X POST \ -d '{ "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "internal", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } } }' ``` #### Java ```java // Adyen Java API Library v33.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.transfers.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.model.RequestOptions; import com.adyen.service.transfers.*; Client client = new Client("ADYEN_BALANCE_PLATFORM_API_KEY", Environment.TEST); // Create the request object(s) PartyIdentification partyIdentification3 = new PartyIdentification() .fullName("A. Klaassen"); IbanAccountIdentification ibanAccountIdentification = new IbanAccountIdentification() .iban("NL91ABNA0417164300") .type(IbanAccountIdentification.TypeEnum.IBAN); BankAccountV3 bankAccountV33 = new BankAccountV3() .accountHolder(partyIdentification3) .accountIdentification(new TransferInfoAccountIdentification(ibanAccountIdentification)); Amount amount = new Amount() .currency("EUR") .value(1000L); CounterpartyInfoV3 counterpartyInfoV3 = new CounterpartyInfoV3() .bankAccount(bankAccountV33); TransferInfo transferInfo = new TransferInfo() .balanceAccountId("BA00000000000000000000001") .reference("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER") .amount(amount) .referenceForBeneficiary("YOUR_REFERENCE_SENT_TO_BENEFICIARY") .description("YOUR_DESCRIPTION_FOR_THE_TRANSFER") .counterparty(counterpartyInfoV3) .category(TransferInfo.CategoryEnum.INTERNAL); // Send the request TransfersApi service = new TransfersApi(client); Transfer response = service.transferFunds(transferInfo, new RequestOptions().idempotencyKey("UUID")); ``` #### PHP ```php setXApiKey("ADYEN_BALANCE_PLATFORM_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $partyIdentification3 = new PartyIdentification(); $partyIdentification3 ->setFullName("A. Klaassen"); $transferInfoAccountIdentification = new TransferInfoAccountIdentification(); $transferInfoAccountIdentification ->setIban("NL91ABNA0417164300") ->setType("iban"); $bankAccountV33 = new BankAccountV3(); $bankAccountV33 ->setAccountHolder($partyIdentification3) ->setAccountIdentification($transferInfoAccountIdentification); $amount = new Amount(); $amount ->setCurrency("EUR") ->setValue(1000); $counterpartyInfoV3 = new CounterpartyInfoV3(); $counterpartyInfoV3 ->setBankAccount($bankAccountV33); $transferInfo = new TransferInfo(); $transferInfo ->setBalanceAccountId("BA00000000000000000000001") ->setReference("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER") ->setAmount($amount) ->setReferenceForBeneficiary("YOUR_REFERENCE_SENT_TO_BENEFICIARY") ->setDescription("YOUR_DESCRIPTION_FOR_THE_TRANSFER") ->setCounterparty($counterpartyInfoV3) ->setCategory("internal"); $requestOptions['idempotencyKey'] = 'UUID'; // Send the request $service = new TransfersApi($client); $response = $service->transferFunds($transferInfo, $requestOptions); ``` #### C\# ```cs // Adyen .net API Library v28.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Transfers; using Adyen.Service.Transfers; var config = new Config() { XApiKey = "ADYEN_BALANCE_PLATFORM_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) PartyIdentification partyIdentification3 = new PartyIdentification { FullName = "A. Klaassen" }; IbanAccountIdentification ibanAccountIdentification = new IbanAccountIdentification { Iban = "NL91ABNA0417164300", Type = IbanAccountIdentification.TypeEnum.Iban }; BankAccountV3 bankAccountV33 = new BankAccountV3 { AccountHolder = partyIdentification3, AccountIdentification = new TransferInfoAccountIdentification(ibanAccountIdentification) }; Amount amount = new Amount { Currency = "EUR", Value = 1000 }; CounterpartyInfoV3 counterpartyInfoV3 = new CounterpartyInfoV3 { BankAccount = bankAccountV33 }; TransferInfo transferInfo = new TransferInfo { BalanceAccountId = "BA00000000000000000000001", Reference = "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", Amount = amount, ReferenceForBeneficiary = "YOUR_REFERENCE_SENT_TO_BENEFICIARY", Description = "YOUR_DESCRIPTION_FOR_THE_TRANSFER", Counterparty = counterpartyInfoV3, Category = TransferInfo.CategoryEnum.Internal }; // Send the request var service = new TransfersService(client); var response = service.TransferFunds(transferInfo, requestOptions: new RequestOptions { IdempotencyKey = "UUID"}); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v23.3.0 const { Client, TransfersAPI } = require('@adyen/api-library'); const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const transferInfo = { amount: { currency: "EUR", value: 1000 }, balanceAccountId: "BA00000000000000000000001", category: "internal", description: "YOUR_DESCRIPTION_FOR_THE_TRANSFER", reference: "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", referenceForBeneficiary: "YOUR_REFERENCE_SENT_TO_BENEFICIARY", counterparty: { bankAccount: { accountHolder: { fullName: "A. Klaassen" }, accountIdentification: { type: "iban", iban: "NL91ABNA0417164300" } } } } // Send the request const transfersAPI = new TransfersAPI(client); const response = transfersAPI.TransfersApi.transferFunds(transferInfo, { idempotencyKey: "UUID" }); ``` #### Go ```go // Adyen Go API Library v17.0.0 import ( "context" "github.com/adyen/adyen-go-api-library/v17/src/common" "github.com/adyen/adyen-go-api-library/v17/src/adyen" "github.com/adyen/adyen-go-api-library/v17/src/transfers" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) partyIdentification3 := transfers.PartyIdentification{ FullName: common.PtrString("A. Klaassen"), } ibanAccountIdentification := transfers.IbanAccountIdentification{ Iban: "NL91ABNA0417164300", Type: "iban", } bankAccountV33 := transfers.BankAccountV3{ AccountHolder: partyIdentification3, AccountIdentification: transfers.IbanAccountIdentificationAsTransferInfoAccountIdentification(&ibanAccountIdentification), } amount := transfers.Amount{ Currency: "EUR", Value: 1000, } counterpartyInfoV3 := transfers.CounterpartyInfoV3{ BankAccount: &bankAccountV33, } transferInfo := transfers.TransferInfo{ BalanceAccountId: common.PtrString("BA00000000000000000000001"), Reference: common.PtrString("YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER"), Amount: amount, ReferenceForBeneficiary: common.PtrString("YOUR_REFERENCE_SENT_TO_BENEFICIARY"), Description: common.PtrString("YOUR_DESCRIPTION_FOR_THE_TRANSFER"), Counterparty: counterpartyInfoV3, Category: "internal", } // Send the request service := client.Transfers() req := service.TransfersApi.TransferFundsInput().IdempotencyKey("UUID").TransferInfo(transferInfo) res, httpRes, err := service.TransfersApi.TransferFunds(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v13.3.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_BALANCE_PLATFORM_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "internal", "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } } } # Send the request result = adyen.transfers.transfers_api.transfer_funds(request=json_request, idempotency_key="UUID") ``` #### Ruby ```rb # Adyen Ruby API Library v10.1.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_BALANCE_PLATFORM_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :amount => { :currency => 'EUR', :value => 1000 }, :balanceAccountId => 'BA00000000000000000000001', :category => 'internal', :description => 'YOUR_DESCRIPTION_FOR_THE_TRANSFER', :reference => 'YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER', :referenceForBeneficiary => 'YOUR_REFERENCE_SENT_TO_BENEFICIARY', :counterparty => { :bankAccount => { :accountHolder => { :fullName => 'A. Klaassen' }, :accountIdentification => { :type => 'iban', :iban => 'NL91ABNA0417164300' } } } } # Send the request result = adyen.transfers.transfers_api.transfer_funds(request_body, headers: { 'Idempotency-Key' => 'UUID' }) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v23.3.0 import { Client, TransfersAPI, Types } from "@adyen/api-library"; const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const partyIdentification3: Types.transfers.PartyIdentification = { fullName: "A. Klaassen" }; const ibanAccountIdentification: Types.transfers.IbanAccountIdentification = { iban: "NL91ABNA0417164300", type: Types.transfers.IbanAccountIdentification.TypeEnum.Iban }; const bankAccountV33: Types.transfers.BankAccountV3 = { accountHolder: partyIdentification3, accountIdentification: ibanAccountIdentification }; const amount: Types.transfers.Amount = { currency: "EUR", value: 1000 }; const counterpartyInfoV3: Types.transfers.CounterpartyInfoV3 = { bankAccount: bankAccountV33 }; const transferInfo: Types.transfers.TransferInfo = { balanceAccountId: "BA00000000000000000000001", reference: "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", amount: amount, referenceForBeneficiary: "YOUR_REFERENCE_SENT_TO_BENEFICIARY", description: "YOUR_DESCRIPTION_FOR_THE_TRANSFER", counterparty: counterpartyInfoV3, category: Types.transfers.TransferInfo.CategoryEnum.Internal }; // Send the request const transfersAPI = new TransfersAPI(client); const response = transfersAPI.TransfersApi.transferFunds(transferInfo, { idempotencyKey: "UUID" }); ``` 2. Verify that the response header contains `status` **authorised**. This means that the authentication and transfer request were successful.\ The following example shows a response for a successful funds transfer. **Finalize funds transfer response** ```json { "id": "1W1UG35U8A9J5ZLG", "amount": { "currency": "EUR", "value": 1000 }, "balanceAccountId": "BA00000000000000000000001", "category": "bank", "counterparty": { "bankAccount": { "accountHolder": { "fullName": "A. Klaassen" }, "accountIdentification": { "type": "iban", "iban": "NL91ABNA0417164300" } } }, "description": "YOUR_DESCRIPTION_FOR_THE_TRANSFER", "reference": "YOUR_UNIQUE_REFERENCE_FOR_THE_TRANSFER", "referenceForBeneficiary": "YOUR_REFERENCE_SENT_TO_BENEFICIARY", "direction": "outgoing", "reason": "pending", "status": "received" } ``` ### Tab: Authenticated during approval To finalize the transfer: 1. Make a POST [/transfers/approve](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers/approve) request, specifying the following parameters: The values of the body parameters must match the ones previously submitted to the `/transfers/approve` endpoint [when initiating the transfer](#initiate-transfer). | **Parameter name** | **Type** | **Required** | **Description** | | ----------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | [WWW-Authenticate](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers/approve#header-WWW_Authenticate) | Header | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | `SCA realm`: **ApproveTransfers**. `auth-param1`: Base64-encoded value of **sdkOutput** you get when you [authenticate the user](#authenticate-user). | | [transferIds](https://docs.adyen.com/api-explorer/transfers/latest/post/transfers/approve#request-transferIds) | Body | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | An array containing the unique identifiers of the transfers that you decide to approve. | **Finalize approval of funds transfers** #### curl ```bash curl https://balanceplatform-api-test.adyen.com/btl/v4/transfers/approve \ -H 'x-api-key: ADYEN_BALANCE_PLATFORM_API_KEY' \ -H 'content-type: application/json' \ -H 'WWW-Authenticate: SCA realm="ApproveTransfers" auth-param1="CeCcEEJf2UPC7pB0K7AtEgLZX7cTvnqNznJF..."' \ -X POST \ -d '{ "transferIds": [ "APUFHASUFD4AS", "407ASFPUHASFA" ] }' ``` #### Java ```java // Adyen Java API Library v33.0.0 import com.adyen.Client; import com.adyen.enums.Environment; import com.adyen.model.transfers.*; import java.time.OffsetDateTime; import java.util.*; import com.adyen.model.RequestOptions; import com.adyen.service.transfers.*; Client client = new Client("ADYEN_BALANCE_PLATFORM_API_KEY", Environment.TEST); // Create the request object(s) ApproveTransfersRequest approveTransfersRequest = new ApproveTransfersRequest() .transferIds(Arrays.asList("APUFHASUFD4AS", "407ASFPUHASFA")); // Send the request TransfersApi service = new TransfersApi(client); service.approveInitiatedTransfers(approveTransfersRequest, new RequestOptions().idempotencyKey("UUID")); ``` #### PHP ```php setXApiKey("ADYEN_BALANCE_PLATFORM_API_KEY"); $client->setEnvironment(Environment::TEST); // Create the request object(s) $approveTransfersRequest = new ApproveTransfersRequest(); $approveTransfersRequest ->setTransferIds(array("APUFHASUFD4AS", "407ASFPUHASFA")); $requestOptions['idempotencyKey'] = 'UUID'; // Send the request $service = new TransfersApi($client); $service->approveInitiatedTransfers($approveTransfersRequest, $requestOptions); ``` #### C\# ```cs // Adyen .net API Library v28.0.0 using Adyen; using Environment = Adyen.Model.Environment; using Adyen.Model; using Adyen.Model.Transfers; using Adyen.Service.Transfers; var config = new Config() { XApiKey = "ADYEN_BALANCE_PLATFORM_API_KEY", Environment = Environment.Test }; var client = new Client(config); // Create the request object(s) ApproveTransfersRequest approveTransfersRequest = new ApproveTransfersRequest { TransferIds = { "APUFHASUFD4AS", "407ASFPUHASFA" } }; // Send the request var service = new TransfersService(client); service.ApproveInitiatedTransfers(approveTransfersRequest, requestOptions: new RequestOptions { IdempotencyKey = "UUID"}); ``` #### NodeJS (JavaScript) ```js // Adyen Node API Library v23.3.0 const { Client, TransfersAPI } = require('@adyen/api-library'); const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const approveTransfersRequest = { transferIds: [ "APUFHASUFD4AS", "407ASFPUHASFA" ] } // Send the request const transfersAPI = new TransfersAPI(client); transfersAPI.TransfersApi.approveInitiatedTransfers(approveTransfersRequest, { idempotencyKey: "UUID" }); ``` #### Go ```go // Adyen Go API Library v17.0.0 import ( "context" "github.com/adyen/adyen-go-api-library/v17/src/common" "github.com/adyen/adyen-go-api-library/v17/src/adyen" "github.com/adyen/adyen-go-api-library/v17/src/transfers" ) client := adyen.NewClient(&common.Config{ ApiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", Environment: common.TestEnv, }) // Create the request object(s) approveTransfersRequest := transfers.ApproveTransfersRequest{ TransferIds: []string{ "APUFHASUFD4AS", "407ASFPUHASFA", }, } // Send the request service := client.Transfers() req := service.TransfersApi.ApproveInitiatedTransfersInput().IdempotencyKey("UUID").ApproveTransfersRequest(approveTransfersRequest) service.TransfersApi.ApproveInitiatedTransfers(context.Background(), req) ``` #### Python ```py # Adyen Python API Library v13.3.0 import Adyen adyen = Adyen.Adyen() adyen.client.xapikey = "ADYEN_BALANCE_PLATFORM_API_KEY" adyen.client.platform = "test" # The environment to use library in. # Create the request object(s) json_request = { "transferIds": [ "APUFHASUFD4AS", "407ASFPUHASFA" ] } # Send the request adyen.transfers.transfers_api.approve_initiated_transfers(request=json_request, idempotency_key="UUID") ``` #### Ruby ```rb # Adyen Ruby API Library v10.1.1 require "adyen-ruby-api-library" adyen = Adyen::Client.new adyen.api_key = 'ADYEN_BALANCE_PLATFORM_API_KEY' adyen.env = :test # Set to "live" for live environment # Create the request object(s) request_body = { :transferIds => [ 'APUFHASUFD4AS', '407ASFPUHASFA' ] } # Send the request adyen.transfers.transfers_api.approve_initiated_transfers(request_body, headers: { 'Idempotency-Key' => 'UUID' }) ``` #### NodeJS (TypeScript) ```ts // Adyen Node API Library v23.3.0 import { Client, TransfersAPI, Types } from "@adyen/api-library"; const client = new Client({ apiKey: "ADYEN_BALANCE_PLATFORM_API_KEY", environment: "TEST" }); // Create the request object(s) const approveTransfersRequest: Types.transfers.ApproveTransfersRequest = { transferIds: ["APUFHASUFD4AS", "407ASFPUHASFA"] }; // Send the request const transfersAPI = new TransfersAPI(client); transfersAPI.TransfersApi.approveInitiatedTransfers(approveTransfersRequest, { idempotencyKey: "UUID" }); ``` 2. Verify that you receive an **HTTP 200 OK** response with a header that contains `status` **authorised**. 3. Verify that you receive a [balancePlatform.transfer.updated](https://docs.adyen.com/api-explorer/transfer-webhooks/latest/post/balancePlatform.transfer.updated) webhook with `status` **authorised**. This means that the authentication and transfer approval were successful.