Provides the essentials for a user to link their real payment methods with a virtual card.
Funding sources supply the means for a user to link a real funding source with a virtual card. A user can supply their checking or savings bank account, or their credit or debit card as a method to fund a transaction performed on the virtual card.
Creating a Funding Source
A funding source is created by invoking a series of steps from the retrieval of funding source configuration to setup and completion of the creation process.
Before creating a funding source, the identity of your user must first be verified via Secure Id Verification.
To begin the process of creating a funding source, call the setupFundingSource method. The funding source providers that your client application supports will inform which provider names you provide to the setupFundingSource method call. Funding source providers supported by the Virtual Cards service include stripe and checkout. You must also provide the name of your application to the setupFundingSource method. This name forms part of a shared configuration between your application, the Virtual Cards service, and any third party funding source providers you have a relationship with. Contact us if you are not certain what application name to use.
Bank Account based Funding Source
Bank account funding sources must be created using checkout as the funding source provider.
try {constprovisionalFundingSource=awaitvirtualCardsClient.setupFundingSource({ currency:'USD', type:FundingSourceType.BankAccount, applicationName:'yourApplicationName',// include only the provider(s) you will support supportedProviders: ['checkout'], })} catch (error) {// Handle/notify user of errors}
The call to setupFundingSource will return a ProvisionalFundingSource containing provisioning data required to continue the funding source creation process.
Plaid Financial Institution Selection
In order to continue the setup of a bank account funding source, a financial instiution containing the bank account used to fund the funding source must be selected. Plaid is the provider used to perform this process.
You must use the Plaid Link Web SDK in order to launch the Plaid Link flow to select a financial institution to fund the bank account funding source. The ProvisionalFundingSource.provisioningData property contains a linkToken required to instantiate the Plaid Link flow.
See the Plaid Link Web SDK documentation for more information:
The provisioning data also contains and authorizationText agreement which must be displayed and accepted by the user before creating the bank account funding source as governed by the NACHA organization.
Completing Funding Source Setup with Provider Specific Data
Once the Plaid Link flow has completed and data surrounding the selected bank account has been obtained, construct a provider specific completion data object and call the completeFundingSource method to finish the process of provisioning a funding :
constlinkSuccess:LinkSuccess=/** Result from Plaid Link flow */constcompletionData:CompleteFundingSourceCheckoutBankAccountCompletionDataInput= { provider:'checkout', type:FundingSourceType.BankAccount, publicToken:linkSuccess.public_token, institutionId:linkSuccess.metadata.institution?.institution_id, accountId:linkSuccess.metadata.accounts[0].id, authorizationText:provisioningData.authorizationText[0], }try {constfundingSource=awaitvirtualCardsClient.completeFundingSource({ id:provisionalFundingSource.id, completionData })} catch (error) {// Handle error}
try {let provisionalFundingSource =tryawait virtualCardsClient.setupFundingSource( withInput: SetupFundingSourceInput( type: .bankAccount, currency:"USD", applicationData: ClientApplicationData(applicationName:"yourApplicationName")),// include only the provider(s) you will support supportedProviders: ["checkout"]) )} catch {// Handle/notify user of errors}
The call to setupFundingSource will return a ProvisionalFundingSource containing provisioning data required to continue the funding source creation process.
Plaid Financial Institution Selection
In order to continue the setup of a bank account funding source, a financial instiution containing the bank account used to fund the funding source must be selected. Plaid is the provider used to perform this process.
You must use the Plaid Link iOS SDK in order to launch the Plaid Link flow to select a financial institution to fund the bank account funding source. The ProvisionalFundingSource.provisioningData property contains a linkToken required to instantiate the Plaid Link flow:
let linkToken = provisionalFundingSource.provisioningData.linkTokenlet authorizationText = provisionalFundingSource.provisioningData.authorizationTextvar linkHandler: Handler?var linkConfiguration =LinkTokenConfiguration( token: linkToken, onSuccess: { // Handle Plaid Link success// Data required to complete the funding source creation process can be obtained here })let result = Plaid.create(linkConfiguration)switch result {case .failure(let error):// Handle failed resultcase .success(let handler): handler.open(presentUsing: .viewController(self)) linkHandler = handler}
See the Plaid Link iOS SDK documentation for more information:
Some financial institutions support an OAuth authentication flow in which the user is redirected to the financial institution's website or mobile app to authenticate. We will handle setting up the Universal Link and deploying a domain to handle this flow however you will need to register the provided domain as an app links entitlement for iOS applications. The app links entitlement will need to be of the form applinks:<fully qualified domain>.
The provisioning data also contains and authorizationText agreement which must be displayed and accepted by the user before creating the bank account funding source as governed by the NACHA organization.
Completing Funding Source Setup with Provider Specific Data
Once the Plaid Link flow has completed and data surrounding the selected bank account has been obtained, construct a provider specific completion data object and call the completeFundingSource method to finish the process of provisioning a funding source:
let linkSuccess: LinkSuccess =/** Result from Plaid Link flow */let completionData =CheckoutBankAccountCompletionDataInput( publicToken: linkSuccess.publicToken, accountId: linkSuccess.metadata.accounts[0].id, institutionId: linkSuccess.metadata.institution.id, authorizationText: authorizationText[0])let completionDataInput = CompletionDataInput.checkoutBankAccount(completionData)try {let fundingSource =tryawait virtualCardsClient.completeFundingSource( withInput: CompleteFundingSourceInput( id: provisionalFundingSource.id, // This is the identifier of the provisional Funding Source. completionData: completionDataInput))} catch {// Handle/notify user of errors}
launch {try {val setupInput =SetupFundingSourceInput("USD", FundingSourceType.BANK_ACCOUNT,ClientApplicationData("yourApplicationName"),// include only the provider(s) you will supportlistOf("checkout")val provisionalFundingSource =withContext(Dispatchers.IO) { virtualCardsClient.setupFundingSource( setupInput ) }// The returned [provisionalFundingSource] has been created. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
The call to setupFundingSource will return a ProvisionalFundingSource containing provisioning data required to continue the funding source creation process.
Plaid Financial Institution Selection
In order to continue the setup of a bank account funding source, a financial instiution containing the bank account used to fund the funding source must be selected. Plaid is the provider used to perform this process.
You must use the Plaid Link Android SDK in order to launch the Plaid Link flow to select a financial institution to fund the bank account funding source. The ProvisionalFundingSource.provisioningData property contains a linkToken required to instantiate the Plaid Link flow:
val linkToken = provisionalFundingSource.provisioningData.linkTokenval authorizationText = provisionalFundingSource.provisioningData.authorizationText/** Callback used to register and launch the activity result from Plaid Link. */privateval linkAccountToPlaid =registerForActivityResult(OpenPlaidLink()) {when (it) {is LinkSuccess -> {// Handle Plaid Link success// Data required to complete the funding source creation process can be obtained here }is LinkExit -> {// Handle Plaid Link exit } }}privatefunlaunchPlaidLink(linkToken: String) {val tokenConfiguration = LinkTokenConfiguration.Builder() .token(linkToken) .build() linkAccountToPlaid.launch(tokenConfiguration)}
See the Plaid Link Android SDK documentation for more information:
The provisioning data also contains an authorizationText agreement which must be displayed and accepted by the user before creating the bank account funding source as governed by the NACHA organization.
Completing Funding Source Setup with Provider Specific Data
Once the Plaid Link flow has completed and data surrounding the selected bank account has been obtained, construct a provider specific completion data object and call the completeFundingSource method to finish the process of provisioning a funding source:
val linkSuccess: LinkSuccess=/** Result from Plaid Link flow */launch {try { val completionData =CheckoutBankAccountProviderCompletionData( publicToken = linkSuccess.publicToken, institutionId = linkSuccess.metadata.institution.id, accountId = linkSuccess.metadata.accounts[0].id, authorizationText = provisioningData.authorizationText[0], )val input =CompleteFundingSourceInput( provisionalFundingSource.id, completionData,null )val fundingSource =withContext(Dispatchers.IO) { virtualCardsClient.completeFundingSource( completeInput ) }// The returned [fundingSource] has been created. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
Testing bank account funding sources in sandbox
During application development, you will be using a sandbox Sudo Platform environment. The sandbox environment allows you to test bank account funding sources without requiring the full integration of the Plaid Link user interface.
The sandboxGetPlaidData method allows you to obtain the account ID and public token required to submit as completion data without the user interface.
This API is not available in production environments.
Plaid documents IDs of institutions available for sandbox testing here.
Sudo Platform pre-defines test accounts with particular behaviours:
The following example shows how to use the sandboxGetPlaidData API on each platform:
try {constinstitutionId='ins_109508'constdata=awaitvirtualCardsClient.sandboxGetPlaidData({ institutionId, plaidUsername:'custom_checking_500' })constcompletionData:CompleteFundingSourceCheckoutBankAccountCompletionDataInput= { provider:'checkout', type:FundingSourceType.BankAccount, authorizationText:provisioningData.authorizationText[0],// Must match institution ID passed to sandboxGetPlaidData institutionId,// Returned by sandboxGetPlaidData publicToken:data.publicToken, accountId:data.accountMetadata[0].accountId, }// Complete funding source ...}catch (err) {// handle error}
try {let institutionId ="ins_109508"let data =tryawait virtualCardsClient.sandboxGetPlaidData( institutionId: institutionId, plaidUsername:"custom_checking_500")let completionData =CheckoutBankAccountCompletionDataInput( publicToken: data.publicToken, // From sandboxGetPlaidData accountId: data.accountMetadata[0].accountId, // From sandboxGetPlaidData institutionId: institutionId, // Must match value passed to sandboxGetPlaidData authorizationText: authorizationText[0])// Complete funding source ...} catch {// Handle/notify user of errors}
launch {try {val institutionId ="ins_109508"valdata=withContext(Dispatchers.IO) { virtualCardsClient.sandboxGetPlaidData( institutionId,"custom_checking_500" ) }val completionData =CheckoutBankAccountProviderCompletionData( publicToken =data.publicToken, // From sandboxGetPlaidData institutionId = institutionId, // Must match value passed to sandbxoGetPlaidData accountId =data.accountMetadata[0].accountId, // From sandboxGetPlaidData authorizationText = provisioningData.authorizationText[0], )// Complete funding source ... } catch (e: FundingSourceException) {// Handle exception }}
Card based Funding Source
You can create a credit card funding source using either stripe or checkout as the funding source provider.
try {constprovisionalFundingSource=awaitvirtualCardsClient.setupFundingSource({ currency:'USD', type:FundingSourceType.CreditCard, applicationName:'yourApplicationName',// include only the provider(s) you will support supportedProviders: ['stripe','checkout'], })} catch (error) {// Handle/notify user of errors}
The call to setupFundingSource will return a ProvisionalFundingSource containing provisioning data required to continue the funding source creation process. To continue, you must use either the Stripe API or the checkout.com API to progress the funding source setup; the chosen provider must match that returned in the provisionalFundingSource.provisioningData property.
Retrieve the provider API key as well as other information pertaining to the funding source provider using the getFundingSourceClientConfiguration method:
try {constconfiguration=awaitvirtualCardsClient.getFundingSourceClientConfiguration()// [configuration] contains the list of funding source client configuration.} catch (error) {// Handle/notify user of errors}
Stripe Funding Source Preparation
For Stripe React integration, see the documentation at:
To setup a payment intent in Stripe, call StripeClient.confirmSetupIntent(confirmSetupIntentParams: ConfirmSetupIntentParams) and ensure that the ConfirmSetupIntentParams input parameter is populated with card details and billing details that you wish to add as a funding source.
Card and Billing Details are required.
Once a Setup Intent has been setup, call completeFundingSource to finish provisioning the FundingSource.
checkout.com Funding Source Preparation
For checkout.com JavaScript, see the documentation at:
To retrieve the tokenized card details as a payment token, handle the cardTokenized event in the checkout.com Frames integration. The token is returned in the token property of the event.
Completing Funding Source Setup with Provider Specific Data
Once the provider-specific data has been obtained, construct a provider specific completion data object and call the completeFundingSource method to finish the process of provisioning a funding source:
The completeFundingSource call accepts an optional updateCardFundingSource parameter (default value is true). This parameter is a flag to indicate whether to automatically update unfunded cards' funding source when a new funding source is created:
// For StripeconstcompletionData:CompleteFundingSourceStripeCardCompletionDataInput= { provider:'stripe', type:FundingSourceType.CreditCard, paymentMethod: setupIntentPaymentMethodAsString,// Retrieve from Stripe API}/// OR// For Checkout.comconstcompletionData:CompleteFundingSourceCheckoutCardCompletionDataInput= { provider:'checkout', type:FundingSourceType.CreditCard, paymentToken: paymentTokenReturnedFromFrames,// Retrieve from Checkout.com API}try {constfundingSource=awaitvirtualCardsClient.completeFundingSource({ id:provisionalFundingSource.id, completionData, // Optional flag to indicate whether to automatically update unfunded cards' funding source when a new funding source is created (defaults to true)
updateCardFundingSource:true,} catch (error) {if (error instanceof FundingSourceRequiresUserInteractionError) {// Handle additional user interaction } else {// Handle error }}
try {let provisionalFundingSource =tryawait virtualCardsClient.setupFundingSource( withInput: SetupFundingSourceInput( type: .creditCard, currency:"USD", applicationData: ClientApplicationData(applicationName:"yourApplicationName")),// include only the provider(s) you will support supportedProviders: ["stripe", "checkout"]) )} catch {// Handle/notify user of errors}
The call to setupFundingSource will return a ProvisionalFundingSource containing provisioning data required to continue the funding source creation process. To continue, you must use either the Stripe API or the checkout.com API to progress the funding source setup; the chosen provider must match that returned in the ProvisionalFundingSource.provisioningData property.
Retrieve the provider API key as well as other information pertaining to the funding source provider using the getFundingSourceClientConfiguration method and finding the client configuration for your supported provider(s):
try {let configuration =tryawait virtualCardsClient.getFundingSourceClientConfiguration()// [configuration] contains the list of funding source client configuration. } catch {// Handle/notify user of exception }}
To create a payment token in checkout.com, call CheckoutApiClient.createCardToken(card: CkoCardTokenRequest) and ensure that the CkoCardTokenRequest input parameter is populated with card details and billing details that you wish to add as a funding source.
Card and Billing Details are required.
Completing Funding Source Setup with Provider Specific Data
Once the provider-specific data has been obtained, construct a provider specific completion data object and call the completeFundingSource method to finish the process of provisioning a funding source:
/// Stripelet completionData =StripeCompletionDataInput( paymentMethodId: paymentMethodId // This is the payment method identifier of the Stripe SetupIntent success response.)/// OR/// checkout.comlet completionData =CheckoutCompletionDataInput( paymentToken: paymentToken // This is the payment token returned in the CkoCardTokenResponse returned by createCardToken
)try {let fundingSource =tryawait virtualCardsClient.completeFundingSource( withInput: CompleteFundingSourceInput( id: id, // This is the identifier of the provisional Funding Source. completionData: completionData))} catch {// Handle/notify user of errors}
launch {try {val setupInput =SetupFundingSourceInput("USD", FundingSourceType.CREDIT_CARD,ClientApplicationData("yourApplicationName"),// include only the provider(s) you will supportlistOf("stripe", "checkout")val provisionalFundingSource =withContext(Dispatchers.IO) { virtualCardsClient.setupFundingSource( setupInput ) }// The returned [provisionalFundingSource] has been created. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
The call to setupFundingSource will return a ProvisionalFundingSource containing provisioning data required to continue the funding source creation process. To continue, you must use either the Stripe API or the checkout.com API to progress the funding source setup; the chosen provider must match that returned in the ProvisionalFundingSource.provisioningData property.
Retrieve the provider API key as well as other information pertaining to the funding source provider using the getFundingSourceClientConfiguration method:
launch {try {val configuration =withContext(Dispatchers.IO) { virtualCardsClient.getFundingSourceClientConfiguration() }// [configuration] contains the list of funding source client configuration. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
Stripe Funding Source Preparation
For Stripe Android-Kotlin, see the documentation at:
To setup a setup intent in Stripe, call StripeClient.confirmSetupIntent(confirmSetupIntentParams: ConfirmSetupIntentParams) and ensure that the ConfirmSetupIntentParams input parameter is populated with card details and billing details that you wish to add as a funding source.
Card and Billing Details are required.
checkout.com Funding Source Preparation
For checkout.com Android-Kotlin, see the documentation at:
To create a payment token in checkout.com, call CheckoutApiClient.generateToken(cardTokenisationRequest: CardTokenisationRequest) and ensure that the CardTokenisationRequest input parameter is populated with card details and billing details that you wish to add as a funding source.
Card and Billing Details are required.
Completing Funding Source Setup with Provider Specific Data
Once the provider-specific data has been obtained, construct a provider specific completion data object and call the completeFundingSource method to finish the process of provisioning a funding source:
launch {try {val completionData =StripeCardProviderCompletionData( paymentMethodId // This is the payment method identifier of the Stripe SetupIntent success response. )/** OR ***/val completionData =CheckoutCardProviderCompletionData( paymentToken // This is the payment token returned from the checkout.com generateToken call. ) val completeInput =CompleteFundingSourceInput( provisionalFundingSource.id, completionData,null )val fundingSource =withContext(Dispatchers.IO) { virtualCardsClient.completeFundingSource( completeInput ) }// The returned [fundingSource] has been created. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
Continuing User Interaction
The completeFundingSource method can throw a FundingSourceRequiresUserInteraction exception. This indicates that further interaction with the user is required before the funding source setup process can be completed.
The thrown exception contains data indicating what action needs to be taken along with the source of the interaction requirement. The need for further interaction can arise because a particular payment processor needs to perform strong authentication (for example 3DS2). The requirement to handle this case is dependent on which provider(s) you are supporting in your application.
The following table indicates the types of user interaction that may be returned and how they should be handled:
Failure during payment processor interaction
If there is any failure returned from the payment processor (Stripe or Checkout.com) prior to calling completeFundingSource, then the provisional funding source returned by setupFundingSource method may be re-used for multiple attempts at completeFundingSource.
Examples of failures include the user entering incorrect expiry, billing address or security code information for a card.
Cancelling a Provisional Funding Source
If a user would like to cancel a provisional funding source before it is completed, they can call the cancelProvisionalFundingSource method. This method cancels setting up the funding source at the funding source provider and places the provisional funding source in the failed state.
// Collect the input provisionalFundingSourceId as appropriate // for your implementation.try {constprovisionalFundingSource=awaitvirtualCardsClient.cancelProvisionalFundingSource( provisionalFundingSourceId )// The returned `provisionalFundingSource` is now cancelled and is in a Failed state.} catch {// Handle/notify user of errors}
do {// Collect the input provisionalFundingSourceId as appropriate // for your implementation.let provisionalFundingSource =tryawait self.virtualCardsClient.cancelProvisionalFundingSource( withId: provisionalFundingSourceId)// The returned funding source is now cancelled and is in a failed state. } catch {// Handle/notify user of error}
// Collect the input provisionalFundingSourceId as appropriate // for your implementation.try {val provisionalFundingSource =withContext(Dispatchers.IO) { virtualCardsClient.cancelProvisionalFundingSource( provisionalFundingSourceId ) }// The returned [provisionalFundingSource] is now cancelled and // is in a FAILED state.} catch (e: FundingSourceException) {// Handle/notify user of exception}
Unfunded Funding Sources
If a user incurs a debit on a virtual card backed by a Bank Account funding source that cannot be fulfilled - generally due to insufficient funds in the bank account at the time the debit is presented - the funding source will be flagged as Unfunded. Funding sources in this condition will have the value UNFUNDED in the flags field of the funding source returned from the listFundingSources or getFundingSource methods.
If a user has an Unfunded funding source, very limited transaction velocities based on system policy will apply to all virtual cards owned by that user until the funding source is funded again.
Additionally, the user is not permitted to cancel an Unfunded funding source.
Unfunded funding sources also include the attribute unfundedAmount which indicates the amount by which the funding source is unfunded in the currency of the funding source.
In order to remove this flag from the funding source, the user should add the appropriate value of funds to their bank account and invoke the reviewUnfundedFundingSource endpoint with the appropriate funding source identifier.
The funding source will be reviewed and if the funds are available, will be marked as funded, restoring normal permitted transaction velocity for the user.
Transactions which cause a funding source to become unfunded may incur an additional service fee applied against that funding source.
try {
const fundingSource = await virtualCardsClient.reviewUnfundedFundingSource({
id,
})
// `fundingSource` contains the fundingSource object. Note that the review process
// occurs asynchronously and may take some time to complete so even if the
// immediately-returned funding source is still unfunded, the client may wait for
// notification of funding source update or poll to detect a successful review.
} catch {
// Handle/notify user of errors
}
do {
let fundingSource = try await self.virtualCardsClient.reviewUnfundedFundingSource(
withId: id,
)
// `fundingSource` contains the resultant object. Note that the review process
// occurs asynchronously and may take some time to complete so even if the
// immediately-returned funding source is still unfunded, the client may wait for
// notification of funding source update or poll to detect a successful review.
} catch {
// Handle/notify user of error
}
launch {
try {
val fundingSource = withContext(Dispatchers.IO) {
virtualCardsClient.reviewUnfundedFundingSource(
id,
)
}
// 'fundingSource' contains the resultant object. Note that the review process
// occurs asynchronously and may take some time to complete so even if the
// immediately-returned funding source is still unfunded, the client may wait for
// notification of funding source update or poll to detect a successful review.
} catch (e: FundingSourceException) {
// Handle/notify user of exception
}
}
Cancelling a Funding Source
If a user decides they want to remove a funding source from their account, the ability to provide them with the means to do so is applied with the cancelFundingSource method.
When a funding source is cancelled, any associated active virtual cards will no longer be able to process transactions. Any such transactions will be declined.
This API call is idempotent, so cancelling an already-cancelled funding source will yield the same result.
When a funding source is cancelled, the record of the funding source will not be deleted, but instead its state will be set to INACTIVE and will no longer be usable for provisioning virtual cards. This is because refunds are always returned to the same original funding source and so clients will need to be able to retain details about cancelled funding in case any such future refunds refer to them.
Any existing virtual cards funded by a cancelled funding source will become unfunded. These can be funded by creating a new funding source and setting the updateCardFundingSource parameter in the completeFundingSource method call to true.
Clients should check the result of the cancelFundingSource request to ensure that the funding source was able to be cancelled.
Unfunded funding sources are not permitted to be cancelled and such an attempt will result in a FundingSourceStateError being returned.
// Collect the input id however makes sense for your implementation.// const fundingSourceId = fundingSource.idtry {constfundingSource=awaitvirtualCardsClient.cancelFundingSource( fundingSourceId )// The returned `fundingSource` is now cancelled and in an INACTIVE state.} catch {// Handle/notify user of errors}
do {// Retrieve the id for canceling the funding source.let fundingSource =tryawait self.virtualCardsClient.cancelFundingSource(withId: id)// The returned funding source is now cancelled. } catch {// Handle/notify user of error}
// Collect the input id however makes sense for your implementation.// val fundingSourceId = fundingSource.idtry {val fundingSource =withContext(Dispatchers.IO) { virtualCardsClient.cancelFundingSource(fundingSourceId) }// The returned [fundingSource] is now cancelled.} catch (e: FundingSourceException) {// Handle/notify user of exception}
Refreshing a Funding Source
Bank account funding sources may periodically require the user to re-authorize access to them or for the user to login again. When this is necessary, the funding source have a REFRESH flag set on it. Funding sources requiring a refresh continue to be usable in a limited manner; virtual cards backed by these funding sources may be used for transactions but no new virtual cards will be available. Commonly, requiring a refresh is a precursor to the funding source being cancelled by the provider and so action should be taken in a reasonable time frame to restore such funding sources.
In order to restore a funding source to a fully usable, active state, clients should refresh any such funding sources using the refreshFundingSource method.
let refreshData: CheckoutBankAccountRefreshDataInputtry {let fundingSource =tryawait virtualCardsClient.refreshFundingSource( withInput: RefreshFundingSourceInput( id: id, refreshData: .checkoutBankAccount(refreshData), applicationData: ClientApplicationData(applicationName:"yourApplicationName"), language:"en-US"))} catch {ifcaselet .fundingSourceRequiresUserInteraction() {// Handle additional user interaction }else {// Handle/notify user of errors }}
val refreshData: CheckoutBankAccountProviderRefreshDatalaunch {try {val refreshInput =RefreshFundingSourceInput( id, refreshData,ClientApplicationData("yourApplicationName"), language ="en-US", )val fundingSource =withContext(Dispatchers.IO) { virtualCardsClient.refreshFundingSource( refreshInput ) } } catch (e: SudoVirtualCardsClient.FundingSourceException) {when (e) {is SudoVirtualCardsClient.FundingSourceException.FundingSourceRequiresUserInteractionException -> {// Handle additional user interaction }else-> {// Handle/notify user of exception } } }}
Continuing User Interaction
As with completeFundingSource, the refreshFundingSource method can throw a FundingSourceRequiresUserInteraction exception. This indicates that further interaction with the user is required before the funding source refresh process can be completed.
The thrown exception contains data indicating what action needs to be taken along with the source of the interaction requirement. The need for further interaction can arise because a particular payment processor needs to perform separate authentication (for example OAuth). The requirement to handle this case is dependent on which provider(s) you are supporting in your application.
The following table indicates the types of user interaction that may be returned and how they should be handled:
Testing funding source refresh
During application development, you will be using a sandbox Sudo Platform environment. The sandbox environment allows you to test bank account funding sources without requiring occurrence of events that would normally put a funding source in to the refresh state.
The sandboxSetFundingSourceToRequireRefresh method allows you to set a bank account funding source to this state.
This API is not available in production environments.
Once invoked, a short time in the future the funding source will have the refresh flag set.
The following examples show how to invoke the sandboxSetFundingSourceToRequireRefresh method on each platform:
A fetch of single or multiple funding sources can be performed remotely or locally by specifying the appropriate CachePolicy as part of the input.
Single Funding Source by Id
To retrieve a single funding source given its unique id, use the getFundingSource method. This method will return the record in an active or inactive state if it exists.
try {constfundingSource=awaitvirtualCardsClient.getFundingSource({ id, cachePolicy:CachePolicy.RemoteOnly, })// `fundingSource` contains the fundingSource object, else `undefined` if not found.} catch {// Handle/notify user of errors}
do {let fundingSource =tryawait self.virtualCardsClient.getFundingSource( withId: id, cachePolicy: .remoteOnly)// If the id matches a funding source, `fundingSource` will be returned, else nil.} catch {// Handle/notify user of error}
launch {try {val fundingSource =withContext(Dispatchers.IO) { virtualCardsClient.getFundingSource( id, cachePolicy = CachePolicy.REMOTE_ONLY ) }// If the [id] matches a funding source, [fundingSource] will be returned, else [null]. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
List Funding Sources
The ability to retrieve multiple or all funding sources available to the user is supported. The results can be paginated and can contain funding sources which may be active whilst others are inactive.
A call to a list API will return a ListOutput object containing a list of matching items and a nextToken to support pagination. If no results matching the input are found, the result will contain empty items.
try {constlistOutput=awaitvirtualCardsClient.listFundingSources({ cachePolicy:CachePolicy.RemoteOnly, limit:20, nextToken, })// `listOutput.items` contains the list of items matching the input.// Page through the results if `listOutput.nextToken` != undefined. } catch {// Handle/notify user of errors}
do {let listOutput =tryawait self.virtualCardsClient.getFundingSources( withLimit:20, nextToken: nextToken, cachePolicy: .remoteOnly)// `listOutput.items` contains the list of items matching the input.// Page through the results if `listOutput.nextToken` != nil.} catch {// Handle/notify user of error}
launch {try {val listOutput =withContext(Dispatchers.IO) { virtualCardsClient.listFundingSources( limit =20, nextToken = nextToken, cachePolicy = CachePolicy.REMOTE_ONLY ) }// [listOutput.items] contains the list of items matching the input.// Page through results if [listOutput.nextToken] != null. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
Listing Provisional Funding Sources
Provisional funding sources are created by calls to the setupFundingSource method. The ability to retrieve multiple or all provisional funding sources available to the user is supported. The results can be filtered and/or paginated.
A call to a list API will return a ListOutput object containing a list of matching items and a nextToken to support pagination. If no results matching the input are found, the result will contain empty items.
try {constfilter:ProvisionalFundingSourceFilterInput= { and: [ { id: { eq: idToGet } }, { state: { eq:ProvisionalFundingSourceState.Provisioning } }, ], }constlistOutput=awaitvirtualCardsClient.listProvisionalFundingSources( { filter, cachePolicy:CachePolicy.RemoteOnly, limit:5, nextToken, }, )// `listOutput.items` contains the list of items matching the input.// Page through the results if `listOutput.nextToken` != undefined. } catch {// Handle/notify user of errors}
do {let filter = ProvisionalFundingSourceFilterInput.and([ ProvisionalFundingSourceFilterInput.id(.equals(idToGet)), ProvisionalFundingSourceFilterInput.state(.equals(ProvisionalFundingSourceState.provisioning)) ])let listOutput =tryawait self.virtualCardsClient.listProvisionalFundingSources( withFilter: filter, limit:5, nextToken: nextToken, cachePolicy: .remoteOnly)// `listOutput.items` contains the list of items matching the input.// Page through the results if `listOutput.nextToken` != nil.} catch {// Handle/notify user of error}
launch {try {val filter =ProvisionalFundingSourceFilterInput( id =null, state =null, and =arrayListOf(ProvisionalFundingSourceFilterInput(IdFilterInput(null, idToGet)),ProvisionalFundingSourceFilterInput(null,ProvisionalFundingSourceStateFilterInput( ProvisionalFundingSource.ProvisioningState.PROVISIONING, ), ), ), or =null, not =null )val listOutput =withContext(Dispatchers.IO) { virtualCardsClient.listProvisionalFundingSources( filter, limit =5, nextToken, cachePolicy = CachePolicy.REMOTE_ONLY ) }// [listOutput.items] contains the list of items matching the input.// Page through results if [listOutput.nextToken] != null. } catch (e: FundingSourceException) {// Handle/notify user of exception }}
Subscribing to Funding Source Changes
Consumers of the SDK may choose to subscribe to notifications of changes to Funding Sources from the Sudo Platform rather than polling. This is done via the subscribeToFundingSourceChanges method. Subscribing is done across all Funding Sources associated with the client, not on a per-funding-source basis.
This method accepts a unique subscription identifier and a subscriber object which must implement the fundingSourceChanged(fundingSource: FundingSource): Promise<void> method. This handler should contain application-specific implementation of behavior in the event of a funding source change. The subscription object should also implement the connectionStatusChanged(state: ConnectionState): void method which is invoked in the event of subscription connection state changes between CONNECTED and DISCONNECTED. This handler allows the consumer to detect when the subscription connection has been lost and take appropriate corrective action.
awaitinstanceUnderTest.subscribeToFundingSourceChanges('subscription-id', {fundingSourceChanged(fundingSource:FundingSource):Promise<void> {// Implement handling for funding source changed behaviour },connectionStatusChanged(state:ConnectionState):void {// Implement handling for subscription connection status changed }, },)
If the subscribeToFundingSourceChanges method is called more than once with the same subscription id, subsequent invocations will replace the earlier subscriptions.
Unsubscribing
Once no longer interested in funding source changes, clients may unsubscribe by calling the unsubscribeFromFundingSourceChanges method, passing the same subscription identifier.