# Bank Account Linking (BAL)

# Introduction

Footprint is now excited to offer Bank Account Linking, which works seamlessly
with our existing identity and vaulting technologies. Powered by open banking
along with the best-in-class data aggregators, Footprint's Bank Account Linking
enables you to easily connect your product to 15k+ financial institutions,
cards, investment accounts, and more. Bank linking with Footprint comes with a
few unqiue benefits

* Use the same SDK to verify identities and link bank accounts (Native
  iOS/Android, React/Web, Flutter, and more).
* Automatic secure vaulting for bank account numbers, ownership data, and more.
  Utilize the vault proxy to securely, and compliantly execute bank transfers
  with one of our many partners.
* Built-in operations support in the Footprint dashboard: view accounts,
  balances, connection states, automatically re-link expired connections,
  decrypt bank account data, sift through transactions
* Strongly integrated with Footprint's Identity, Risk, and Fraud products: when
  a bank account is linked, Footprint automatically extracts account ownership
  and financial data to hydrate additional risk and fraud signals for verifying
  the identity behind the account. Seamlessly use Bank account data in identity
  verification (and vice-versa) without writing a single line of code.
* Simple unified APIs for pulling transaction data.

# Link SDK

The Link SDK is a widget that integrates with your frontend wherever it lives
(iOS, Android, or mobile web, or desktop) to provide users with a simple,
beautiful, and whitelabeled experience to connect their bank account to your
product.

## Generate a bank linking session token

The first step is to create an onboarding session token for bank account
linking. Go to [the Footprint dashboard](https://dashboard.onefootprint.com/playbooks)
and create a Playbook with a bank-linking node. Then obtain a session token e.g. `obtok_vsd94fc0gksdfsdf824fx9JaGO7sgqHX` using the steps [mentioned in this article](/articles/guide/definitive-integration-guide#the-end-to-end-integration-step-3-create-an-onboarding-session-token).

## iOS (Swift UI)

To integrate bank linking into your SwiftUI application, install our
[Swift SDK](/articles/sdks/swift-introduction#installation-swift-package-manager)
and use the `FootprintBankLinking` view component. Provide the
`authToken` using the `token` obtained from the previous step, along with a
`redirectUri` that includes both the scheme and host of your application (e.g.,
a custom URL scheme configured in your app's `Info.plist`).

```swift
FootprintBankLinking(
    authToken: authToken,
    redirectUri: "footprintcomponentsdemo://banklinking",
    onSuccess: { response in
        print("Bank linking completed successfully, validation token: \(response.validationToken)")
    },
    onError: { error in // Called when an error occurs
        print("Error occurred during bank linking: \(error)")
    },
    onClose: { // Called when user closes the flow or the flow closes due to an error. If the flow closes due to an error, it will also call the onError callback
        print("Bank linking exited")
    }
)
```

The approach above lets you run bank linking separately using `FootprintBankLinkingWithAuthToken`. Just make sure it doesn’t run at the same time as any exisiting onboarding flow created using our Swift Onboarding Components SDK—since both use the same underlying object, it’s best to run them one after the other.

## Android

To integrate bank linking into your Android application, install our
[Android SDK](/articles/sdks/android-introduction#installation) and launch the
bank linking flow using the `token` obtained from the previous step. Use the
`FootprintBankLinking.launchWithAuthToken` method, providing the `authToken`,
activity `context`, and relevant callbacks:

```kotlin
Button(
    onClick = {
        coroutineScope.launch {
            try {
                FootprintBankLinking.launch(
                    obSessionToken = "obtok_VlGKyL3AF7HDQfgx0j223RmNEmwNadRWn7", // Use your auth token here
                    context = context,
                    onSuccess = {
                        val validationToken = it.validationToken
                        println("Bank linked. Validation token: $validationToken")
                    },
                    onError = { error -> // Called when an error occurs
                        println("Error linking bank: ${error.message}")
                    },
                    onClose = { // Called when user closes the flow or the flow closes due to an error. If the flow closes due to an error, it will also call the onError callback
                        println("User exited bank linking")
                    },
                    onEvent = { event -> // Called when an event occurs in the bank linking flow
                        println(
                            "Bank linking event: " +
                                    "name: ${event.name}, " +
                                    "link type: ${event.meta.linkType}, " +
                                    "institution name: ${event.meta.institutionName}, " +
                                    "institution id: ${event.meta.institutionId}, " +
                                    "timestamp: ${event.meta.timestamp}, " +
                                    "properties: ${event.properties} "
                        )
                    }
                )
            } catch (e: FootprintException) {
                println("Error initializing Footprint SDK: ${e.message}")
            }
        }
    }
) {
    Text("Link Bank Account")
}
```

### Handling Process Death

If Android terminates your app's process during the OAuth flow, you need to resume the bank linking session when the OAuth redirect returns. Override the `onNewIntent` method in your activity to check for the intent extra `"FOOTPRINT_BANK_LINKING_STATUS"`. If the value matches `FootprintBankLinkingFlowStatus.PENDING.value`, call `FootprintBankLinking.resumePendingLinking` with the same callbacks.

Here's an example:

```kotlin
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            OnboardingComponents(context = this)
        }
    }

    private fun handleResumeFootprintBAL(intent: Intent){
        val balStatus = intent.getStringExtra("FOOTPRINT_BANK_LINKING_STATUS")
        println("Received new intent with BAL status: $balStatus")
        if(balStatus != null && balStatus == FootprintBankLinkingFlowStatus.PENDING.value) {
            FootprintBankLinking.resumePendingLinking(
                context = this,
                onSuccess = {
                    val validationToken = it.validationToken
                    println("Bank linked. Validation token: $validationToken")
                },
                onError = { error ->
                    println("Error linking bank: ${error.message}")
                },
                onClose = {
                    println("User exited bank linking")
                },
                onEvent = { event ->
                    println(
                        "Bank linking event: " +
                                "name: ${event.name}, " +
                                "link type: ${event.meta.linkType}, " +
                                "institution name: ${event.meta.institutionName}, " +
                                "institution id: ${event.meta.institutionId}, " +
                                "timestamp: ${event.meta.timestamp}, " +
                                "properties: ${event.properties} "
                    )
                }
            )
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleResumeFootprintBAL(intent)
    }
}
```

The approach above lets you run bank linking separately using `FootprintBankLinking.launchWithAuthToken`. Just make sure it doesn’t run at the same time as any exisiting onboarding flow created using our Android Onboarding Components SDK—since both use the same underlying object, it’s best to run them one after the other.

## Web

Make sure to have the `@onefootprint/footprint-js` package installed (version
5.0.0 or higher):

```bash
npm install @onefootprint/footprint-js
```

```typescript
import { onboarding } from "@onefootprint/footprint-js";

onboarding.initialize({
  onboardingSessionToken: "obtok_UxM6Vbvk2Rcy1gzcSuXgk3sj3L9I0pAnNH",
  onComplete: (validationToken) => {
    console.log(validationToken);
  },
  onError: (error) => {
    console.log(error);
  },
  onAuth: (validationToken) => {
    console.log(validationToken);
  },
  onCancel: () => {
    console.log("User canceled the flow");
  },
  onClose: () => {
    console.log("User closed the flow");
  },
});
```

# Validation token

After the SDK completes and calls the success completion handler, it will pass
back a `validation_token` to you that you'll need to send to your backend and
validate with the Footprint API.

```sh
curl -X POST https://api.onefootprint.com/onboarding/session/validate \
   -u <API_KEY>: \
   -d '{"validation_token": "<VALIDATION_TOKEN_FROM_SDK>"}'
```

This API call redeems the validation token from the SDK and lets you confirm
that the link was completed successfully:

```json
{
  "user": {
    "fp_id": "fp_id_GSxJr68GAf5jUT3pdL9ndjf7TLkA3GCX",
    "onboarding_id": "ob_SRFT2a1mN7DAWJ0VPXkiqK",
    "playbook_key": "pb_test_VMooXd04EUlnu3AvMYKjMW",
  },
  "bank_link": {
    "link_id": "bank_link_xyz123...xyz321"
  }
  ...
}
```

Use (and store in your own database if needed) the `link_id` returned above in
the [bank linking APIs](#apis) to fetch data about the linked bank account(s).

Note: a single bank link may connect more than one bank accounts, see the APIs
linked below for the full data model accessible by a bank link.

# Webhooks

When a bank link connection is created or changed, Footprint sends the
`footprint.user.bank_link_updated` event. Setup webhooks and inspect the webhook
event payload documentation in the
[webhooks tab](https://dashboard.onefootprint.com/webhooks) on the dashboard.

# APIs and Vaulting

Footprint provides a set of APIs to interact with bank links, accounts, and
transactions. Additionally, bank account data is automatically vaulted when the
link is established.

## Bank linking terminology

| Name      | Description                                                                      |
| --------- | -------------------------------------------------------------------------------- |
| `link`    | A link to an institution for which the user has connected one or more `accounts` |
| `account` | A bank account like a checking or savings account connected via a `link`         |

## APIs

Footprint provides a set of APIs to get information about bank links, associated
accounts, balances, and transactions. For the full API specification, take a
look at the [Bank Linking API reference](/api-reference#bank-linking).

## Vaulting

Once linked, a bank account's sensitive data is automatically fetched and
vaulted using the `bank` account data identifier defined in the
[Bank account vault fields](/articles/vault/fields#bank-account-fields).

The bank `account_id` is used as the alias for the Bank account. For instance,
if a the link has an account with identifier `acc_xyz1234`, then the ACH account
number would be vaulted under data identifier
`bank.acc_xyz1234.ach_account_number`.