{"id":28384128,"url":"https://github.com/plaid/account-funding-tutorial","last_synced_at":"2025-06-25T22:30:58.020Z","repository":{"id":44559166,"uuid":"470754336","full_name":"plaid/account-funding-tutorial","owner":"plaid","description":null,"archived":false,"fork":false,"pushed_at":"2024-07-05T18:14:44.000Z","size":1684,"stargazers_count":13,"open_issues_count":7,"forks_count":8,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-30T08:16:27.658Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/plaid.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-16T21:17:21.000Z","updated_at":"2025-04-08T09:09:46.000Z","dependencies_parsed_at":"2024-06-07T22:54:48.729Z","dependency_job_id":null,"html_url":"https://github.com/plaid/account-funding-tutorial","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/plaid/account-funding-tutorial","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plaid%2Faccount-funding-tutorial","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plaid%2Faccount-funding-tutorial/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plaid%2Faccount-funding-tutorial/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plaid%2Faccount-funding-tutorial/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/plaid","download_url":"https://codeload.github.com/plaid/account-funding-tutorial/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/plaid%2Faccount-funding-tutorial/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261962108,"owners_count":23236872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-30T07:38:51.887Z","updated_at":"2025-06-25T22:30:58.006Z","avatar_url":"https://github.com/plaid.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Building account funding in the Plaid Pattern sample app\n\n### Table of Contents\n\n- [Overview](#overview)\n- [Your Task](#your-task)\n- [Setting Up](#setting-up)\n- Building account funding\n  - [Checkpoint 1: Implementing Link and initializing with Auth and Identity](#checkpoint-1-initializing-link-with-auth-and-identity)\n  - [Checkpoint 2: Retrieve identity and initial balance information associated with the account](#checkpoint-2-retrieve-identity-and-initial-balance-information-associated-with-the-account)\n  - [Checkpoint 3: Generating a partner processor token (Dwolla)](#checkpoint-3-generating-a-partner-processor-token)\n  - [Checkpoint 4: Parsing user name and email](#checkpoint-4-parsing-user-name-and-email)\n  - [Checkpoint 5: Checking real-time account balance](#checkpoint-5-checking-current-account-balance)\n  - [Checkpoint 6: Retrieving real-time account balance](#checkpoint-6-retrieving-real-time-balance-information)\n  - [Checkpoint 7: Verifying user identity](#checkpoint-7-verifying-user-identity)\n  - [Checkpoint 8: Initiating a transfer](#checkpoint-8-initiating-a-transfer)\n  - [Checkpoint 9: Sending the transfer request to Dwolla](#checkpoint-9-sending-the-transfer-request-to-dwolla)\n- [Let's try it all out!](#lets-try-it-all-out)\n- [Next steps](#next-steps)\n\n### Overview\n\nTransferring funds from a bank account into an app (i.e., \"account funding\") is a common use case when building with Plaid. In this tutorial, we'll demonstrate how to implement account funding in the Plaid Pattern sample app.\n\nAccount funding is commonly implemented using a combination of Plaid products and a Plaid partner (i.e., Stripe, Dwolla, etc.). In this tutorial, we'll use Plaid Auth, Balance, Identity (\"ABI\"), and Dwolla to build account funding into the Pattern sample app. We'll retrieve account information through a combination of Auth and Dwolla, use Balance to check the balance of an account, and use Identity to verify the identity of users initiating a transfer. Dwolla will be used to move (fictional) funds from a user's bank account into the Plaid Pattern sample app. For a full list of supported partners, see [Auth Payment Partners](https://plaid.com/docs/auth/partnerships/).\n\nFor a preview of what you'll be building toward, navigate to the \u003ca href=\"https://github.com/plaid/pattern-account-funding\" target=\"_blank\"\u003ePlaid Pattern sample app\u003c/a\u003e and follow the instructions in the README to launch the app. Once the app is up and running, create a user, enable \"Verify Identity Mode\", and proceed to link a bank account. Finally, click the \"Transfer funds\" button to transfer funds into the Pattern app.\n\n### Your Task\n\nIn this tutorial, you'll start with a \"skeleton\" version of the codebase for the Plaid Pattern sample app. Everything except the account funding functionality will exist in the skeleton codebase. You'll build account funding as you progress through the tutorial. We'll provide the code snippets needed to build this functionality, as well as an explanation of what each code snippet does.\n\nFinally, if you've progressed through the tutorial and would like to leave feedback, see [Feedback: Account Funding Tutorial](https://github.com/plaid/account-funding-tutorial/issues/7). We'll be sure to take a look and do our best to help.\n\n### Setting Up\n\nThere are a few things you'll need to do first to make sure you can successfully complete the tutorial.\n\n#### Install and run Docker\n\nTo run Plaid Pattern, you'll need Docker. If you don't already have Docker installed, refer to [Docker's documentation to get started](https://docs.docker.com/get-started/). Once Docker is installed, start Docker.\n\n#### Clone this repo to your machine\n\n```\ngit clone https://github.com/plaid/account-funding-tutorial.git \u0026\u0026 cd account-funding-tutorial/\n```\n\nInside of **pattern-af-tutorial/**, you'll find the skeleton codebase for this tutorial. This is where you'll build account funding.\n\n#### Install the client dependencies\n\n```\ncd pattern-af-tutorial/ \u0026\u0026 cd client/ \u0026\u0026 npm install\n```\n\n#### Enable the Plaid API\n\nFirst, create a **.env** file in the **pattern-af-tutorial/** directory. Copy the contents of the **.env.template** file into **.env**.\n\nNext, navigate to the \u003ca href=\"https://dashboard.plaid.com/team/keys\" target=\"_blank\"\u003eKeys section of your Plaid Dashboard\u003c/a\u003e. Set the following variables in your **.env** file using the client ID and secrets in your Dashboard:\n\n```bash\nPLAID_CLIENT_ID=\nPLAID_SECRET_SANDBOX=\n```\n\nWhen setting `PLAID_SECRET_SANDBOX`, use the value of the \"Sandbox\" secret in your Plaid Dashboard. Don't use quotes (`\"`) around any of the values (i.e., `PLAID_CLIENT_ID=adn08a280hqdaj0ad`, not `PLAID_CLIENT_ID=\"adn08a280hqdaj0ad\"`).\n\n#### Enable Dwolla\n\nNavigate to the \u003ca href=\"https://dashboard.plaid.com/team/integrations\" target=\"_blank\"\u003eIntegrations section of your Plaid Dashboard\u003c/a\u003e and enable Dwolla. This will ensure we can use Dwolla as a partner for the funds transfer. The app won't function properly if this integration isn't enabled.\n\nTo use the Dwolla API, \u003ca href=\"https://accounts-sandbox.dwolla.com/sign-up\" target=\"_blank\"\u003ecreate a sandbox account with Dwolla\u003c/a\u003e.\n\nAfter creating an account, we'll need to equip the skeleton codebase with the proper Dwolla API credentials. This will ensure we can actually make funds transfers using Dwolla.\n\nIn your **.env** file, set the following variables:\n\n```bash\nIS_PROCESSOR=true\nDWOLLA_ACCESS_TOKEN=\nDWOLLA_MASTER_ACCOUNT_ID=\n```\n\n`IS_PROCESSOR=true` will enable the app to use Dwolla for money movement.\n\nTo set `DWOLLA_ACCESS_TOKEN`, navigate to \u003ca href=\"https://dashboard-sandbox.dwolla.com/applications-legacy\" target=\"_blank\"\u003ehttps://dashboard-sandbox.dwolla.com/applications-legacy\u003c/a\u003e and click the \"Create Token\" button. Copy the value that appears in the pop-up modal and use it to set `DWOLLA_ACCESS_TOKEN`. Note that the access token will only be valid for 60 minutes.\n\nTo set `DWOLLA_MASTER_ACCOUNT_ID`, navigate to \u003ca href=\"https://dashboard-sandbox.dwolla.com/account/funding-sources\" target=\"_blank\"\u003ehttps://dashboard-sandbox.dwolla.com/account/funding-sources\u003c/a\u003e. Copy the value of \"ID\" at the bottom of the \"Superhero Savings Bank\" card. Use this value to set `DWOLLA_MASTER_ACCOUNT_ID`. Superhero Savings Bank will represent the bank account for your app (i.e., it's where the fictional funds coming from a user's bank account will be deposited).\n\nBe sure to save your changes!\n\n#### Running the app\n\nTo start the app, run `make debug` in the **pattern-af-tutorial/** directory. This command will prevent you from having to stop/start the app as you add code snippets. The app will run on localhost:3002 and will continue to run as you progress through the tutorial.\n\nSome code snippets contain `console.log()` statements that print out information related to the code in the snippet. They also print out success messages intended to help guide you as you progress through the checkpoints. For front end code, check the console in your browser to view the output of the `console.log()` statement. For back end code, run `make logs` in your terminal to view the output of the statement.\n\nIf you encounter issues when running the `make start` command, first ensure that Docker is running. If Docker is running and you're still encountering issues, try running `docker compose build server`. If you're still encountering issues after that, [file an Issue in this repo](https://github.com/plaid/account-funding-tutorial/issues).\n\n### Let's start building\n\nGreat! Now that we've set up everything, let's start building. Here's an outline of what we'll cover in the tutorial:\n\n- We'll start by implementing Link, generating a Link token and initializing with the Auth and Identity products\n- Then we'll move to the back end, where we'll build functionality to:\n  - Retrieve identity information to aid identity verification later\n  - Retrieve initial account balance from **/identity/get**\n  - Generate a processor token for Dwolla\n  - Retrieve real-time account balance using **/accounts/balance/get** (for use later when making transfer requests)\n- Finally, on the front end, we'll:\n  - Write helper functions to help verify user identity and check account balance when a user initiates a transfer\n  - Add the functionality to transfer funds\n\nLet's get started!\n\n### Checkpoint 1: Initializing Link with Auth and Identity\n\nPlaid Link is the client-side component used to link bank accounts to an app. To use Link, we need to first generate a Link token and then initialize Link with that token.\n\nLet's start in the back end. In the **pattern-af-tutorial/** directory, navigate to **server/routes/linkTokens.js**. This file defines the route for Link token creation. Take a look at the existing code that starts on line 42:\n\n```js\nconst linkTokenParams = {\n  user: {\n    // This should correspond to a unique id for the current user.\n    client_user_id: \"uniqueId\" + userId,\n  },\n  client_name: \"Pattern\",\n  products,\n  country_codes: [\"US\"],\n  language: \"en\",\n  webhook: httpTunnel.public_url + \"/services/webhook\",\n  access_token: accessToken,\n};\n```\n\nThe `linkTokenParams` object represents the parameters we'll use to generate a Link token. The `products` variable refers to the array of products we're initializing Link with (defined on line 29 of this file). Note that the `products` array initially contains only `'auth'`, but the logic on line 30 ensures we also initialize with `'identity'`. This is because using Identity is optional in the app.\n\nNow let's move to the front end. Navigate to **client/src/services/link.tsx**. Take a look at the code that starts on line 63:\n\n```js\nconst generateLinkToken = useCallback(async (userId, itemId, isIdentity) =\u003e {\n  // if itemId is not null, update mode is triggered\n  const linkTokenResponse = await getLinkToken(userId, itemId, isIdentity);\n  if (linkTokenResponse.data.link_token) {\n    const token = await linkTokenResponse.data.link_token;\n    console.log(\"success\", linkTokenResponse.data);\n\n    if (itemId != null) {\n      dispatch({\n        type: \"LINK_TOKEN_UPDATE_MODE_CREATED\",\n        id: itemId,\n        token: token,\n      });\n    } else {\n      dispatch({ type: \"LINK_TOKEN_CREATED\", id: userId, token: token });\n    }\n  } else {\n    dispatch({ type: \"LINK_TOKEN_ERROR\", error: linkTokenResponse.data });\n    console.log(\"error\", linkTokenResponse.data);\n  }\n}, []);\n```\n\nThe `generateLinkToken()` function generates a Link token. Under the hood, this function makes a call to `getLinkToken()` (defined in **[client/src/services/api.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/client/src/services/api.tsx#L64)**), which hits the route for Link token creation in **[server/routes/linkTokens.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/server/routes/linkTokens.js#L23)**.\n\nAt this point, you might be thinking: but where is Link actually initialized?\n\nNavigate to **client/src/components/LinkButton.tsx**. This file defines the `LinkButton` component used in the UI. When clicked in the app, it'll initialize Link with a Link token (along with the configurations we specified for the token) and open Link. When a user successfully links their bank account, you'll receive a public token via Link's `onSuccess()` callback function. The public token can then be [exchanged for an access token](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/server/routes/items.js#L115), which can be used to make API calls to the linked bank account. For more details on the token exchange flow and Link, see [the official Plaid Link documentation](https://plaid.com/docs/link/).\n\nThat just about covers the Link implementation in the Pattern app! Let's move on to adding some more functionality.\n\n### Checkpoint 2: Retrieve identity and initial balance information associated with the account\n\nTo verify identity later, we'll need the identity information associated with the linked bank account. We'll also need to establish an initial balance for the account so that we can use it later when a user initiates a transfer in the app.\n\nNavigate to **server/routes/items.js**. Replace line 172 with the following:\n\n```js\nif (isIdentity) {\n  const identityResponse = await plaid.identityGet(authAndIdRequest);\n  emails = identityResponse.data.accounts[0].owners[0].emails.map((email) =\u003e {\n    return email.data;\n  });\n\n  ownerNames = identityResponse.data.accounts[0].owners[0].names;\n  const fullName = ownerNames[0].split(\" \");\n  firstName = fullName[0];\n  lastName = fullName[fullName.length - 1];\n\n  if (isProcessor) {\n    balances = identityResponse.data.accounts[0].balances;\n  }\n}\n```\n\nThe `isIdentity` boolean in the code above represents whether the \"Verify Identity Mode\" checkbox was checked during account creation in the app. For the purposes of this tutorial, we'll assume it was checked, which sets `isIdentity` to true and executes the **/identity/get** call in the `if` block. From the response, we extract the owner names and emails associated with the account and store this information to verify user identity later.\n\nThe `isProcessor` boolean in the nested `if` statement represents whether a processor is being used to transfer funds. We're using Dwolla to transfer funds, so the code in the nested `if` block will execute. In this block, we retrieve the initial account balance from the **/identity/get** response.\n\nNote that we didn't call **/accounts/balance/get** to retrieve initial balance information. This is because there are several Plaid products other than Balance (like Identity and Auth) that return balance information suitable for establishing an initial balance. However, this data is typically updated about once a day and cached data is often returned, making it insufficient for real-time balance checks. In addition, **/accounts/balance/get** is billed on a per-request basis, so it's best (i.e., cost effective) to call it only when absolutely necessary. For subsequent balance checks in the app, we'll call **/accounts/balance/get** to retrieve the real-time balance. We'll provide more detail in a different checkpoint of the tutorial.\n\nTo try this code out, link a bank account in the app – you should see success messages in your console related to the code above. The app now retrieves identity and balance information for an account!\n\n### Checkpoint 3: Generating a partner processor token\n\nNext, we'll generate a partner processor token. This token will allow us to use Dwolla's API to transfer funds. Replace line 201 (after `let fundingSourceUrl = null;`) with the following:\n\n```js\nif (!isProcessor) {\n  authResponse = await plaid.authGet(authAndIdRequest);\n  authNumbers = authResponse.data.numbers.ach[0];\n  balances = authResponse.data.accounts[0].balances;\n} else {\n  const processorRequest = {\n    access_token: accessToken,\n    account_id: account.id,\n    processor: \"dwolla\",\n  };\n  const processorTokenResponse = await plaid.processorTokenCreate(\n    processorRequest\n  );\n  processorToken = processorTokenResponse.data.processor_token;\n\n  customerUrl = await createDwollaCustomer(firstName, lastName);\n\n  fundingSourceUrl = await createDwollaCustomerFundingSource(\n    account,\n    customerUrl,\n    processorToken\n  );\n}\n```\n\nWe're using a processor to transfer funds, so the code in the `else` block will execute. In the `else` block, we generate a processor token using Plaid's **/processor/token/create** endpoint. We also create a Dwolla Customer and obtain the corresponding Customer URL, which is necessary to create a Customer funding source. The funding source represents where a user's funds originate from when they transfer funds into the Pattern app.\n\nNote that this bit of code won't function properly if you didn't enable the Dwolla integration in the Plaid dashboard [as described earlier in the tutorial setup](#enable-dwolla).\n\nThe `createDwollaCustomer()` and `createDwollaCustomerFundingSource()` functions represent Dwolla-specific code needed to make transfers later. If you're interested in the details, refer to their implementations in **[server/routes/items.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/server/routes/items.js#L47)**.\n\nCheck your console for success messages related to this code. If implemented correctly, you'll see the processor token, Customer URL, and Customer funding source URL all printed to the console. If you're running into errors, ensure you've set the `IS_PROCESSOR` variable to `true` in your **.env** file.\n\n### Checkpoint 4: Parsing user name and email\n\nLet's briefly move to the front end and add functionality that will help verify user identity.\n\nWhen a user successfully creates an account in the app, they're redirected to their user page. This page is defined in **client/src/components/UserPage.tsx**. The page contains the user's name and email that was input when the account was created. We'll parse this information, save it, and later use it to verify the user's identity.\n\nInside of the `checkFullName()` function, replace lines 75-77 with the following:\n\n```js\nif (fullname != null) {\n  fullname = fullname.replace(\",\", \" \");\n  const fullnameArray = fullname.split(\" \");\n  console.log(`Verifying name:`, fullname);\n  console.log(`Checkpoint 4 (user name) complete!`);\n\n  return fullnameArray.every((name) =\u003e {\n    return ownerNames.some((identName) =\u003e {\n      return identName.toUpperCase().indexOf(name.toUpperCase()) \u003e -1;\n    });\n  });\n}\nreturn false;\n```\n\nInside of the `checkEmail()` function, replace lines 93-95 with the following:\n\n```js\nconsole.log(`Checking email:`, user_email);\nconsole.log(`Checkpoint 4 (user email) complete!`);\nreturn emails.includes(user_email);\n```\n\nThe `checkFullName()` function will be used later to compare the user's name (from the user page) against the array of owner names returned earlier by **/identity/get**. If there is a match, the function returns true. Otherwise, it returns false.\n\nThe `checkUserEmail()` function checks that the user's email (from the user page) exists in the array of emails returned earlier by **/identity/get**. If it's present, the function returns true. Otherwise, it returns false.\n\nIn addition, note that we'll later verify identity by checking a user's full legal name and email address against the data returned by **/identity/get**. In practice, you'll find that there are many ways of verifying identity, but for the purposes of this tutorial, we'll use these two pieces of user information.\n\nTry linking an account in the app. If successful, you should see the user's full name and email printed to your console.\n\n### Checkpoint 5: Checking current account balance\n\nNext, let's add code that will check the real-time balance of an account. Inside of the `getBalance()` function, replace lines 62-63 with the following:\n\n```js\nlet timeSinceCreation = 0; // time in milliseconds\nif (account != null) {\n  timeSinceCreation =\n    new Date().getTime() - new Date(account.created_at).getTime();\n}\n\nif (\n  account != null \u0026\u0026\n  item != null \u0026\u0026\n  (account.number_of_transfers !== 0 ||\n    timeSinceCreation \u003e 60 * 60 * 1000 || // if it's been more than one hour\n    account.available_balance == null)\n) {\n  const { data: newAccount } = await getBalanceByItem(\n    item.id,\n    account.plaid_account_id\n  );\n  console.log(`Checkpoint 5 complete!`);\n  console.log(`Getting new balance information...`);\n  setAccount(newAccount || {});\n} else {\n  console.log(`Checkpoint 5 complete!`);\n  console.log(`Don’t need to retrieve new balance just yet.`);\n}\n```\n\nThe `getBalance()` function retrieves the real-time balance of an account by calling **/accounts/balance/get**. The logic ensures that we retrieve real-time balance only on transfers initiated after the initial transfer (recall that for the initial transfer we use the balance information from **/identity/get**), or if more than one hour has elapsed since the last transfer (i.e., the last balance check).\n\nSo, when is this function used? We'll call this function when a user clicks the \"Transfer Funds\" button in the UI. Under the hood, this function makes a call to `getBalanceByItem()` (defined in **[client/src/services/api.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/client/src/services/api.tsx#L81)**), which hits a route that we'll define in the next checkpoint.\n\nIt's important to note that **/accounts/balance/get** is the only Plaid endpoint that returns real-time balance information. Although there are other Plaid endpoints that return balance information (i.e., **/identity/get**), you should avoid using the balance information they return if it's been less than 24 hours since the most recent call to that endpoint. This is because this balance data is typically updated about once a day, and cached data is often returned. For the most up-to-date balance information, always use **/accounts/balance/get**.\n\nTo test this code, link a bank account and then initiate a transfer. You should see the `Don't need to retrieve new balance just yet.` message in your console initially. The `Getting new balance information...` message will print once you've added in the transfer functionality, which you'll do in Checkpoints 8 and 9.\n\n### Checkpoint 6: Retrieving real-time balance information\n\nThe `getBalance()` function in the previous checkpoint is called in the front end, and hits a route in the back end that makes a call to **/accounts/balance/get**. This route is yet to be defined, so let's return to the back end and add it in.\n\nNavigate to **server/routes/items.js** and replace line 364 with the following:\n\n```js\n/**\n * Updates balances on account\n *\n * @param {number} itemId the ID of the item.\n * @param {string} accountId the account id.\n * @returns {Object[]} an array containing a single account.\n */\nrouter.put(\n  \"/:itemId/balance\",\n  asyncWrapper(async (req, res) =\u003e {\n    const { itemId } = req.params;\n    const { accountId } = req.body;\n    const { plaid_access_token: accessToken } = await retrieveItemById(itemId);\n    const balanceRequest = {\n      access_token: accessToken,\n      options: {\n        account_ids: [accountId],\n      },\n    };\n\n    const balanceResponse = await plaid.accountsBalanceGet(balanceRequest);\n\n    const account = balanceResponse.data.accounts[0];\n    const updatedAccount = await updateBalances(\n      accountId,\n      account.balances.current,\n      account.balances.available\n    );\n    console.log(`Checkpoint 6 complete!`);\n    console.log(`Available balance:`, account.balances.available);\n    res.json(updatedAccount[0]);\n  })\n);\n```\n\nThis route returns information associated with a bank account, including the real-time balance. When a user clicks the \"Transfer Funds\" button in the UI, the `getBalance()` function will be called, which ultimately hits this route to return the balance.\n\nThis route won't be hit until you add the transfer functionality later in Checkpoints 8 and 9. If you're testing out this code, expect to see console output similar to what you observed in the previous checkpoint.\n\n### Checkpoint 7: Verifying user identity\n\nLet's take a look at how identity is verified in the app. Navigate to **client/src/components/UserPage.tsx** and take a look at the following code (don't add it, as it's already present):\n\n```js\nuseEffect(() =\u003e {\n  if (\n    account != null \u0026\u0026\n    isIdentityChecked === false \u0026\u0026\n    user.should_verify_identity\n  ) {\n    const fullnameCheck = checkFullName(account.owner_names, user.fullname);\n    const emailCheck = checkUserEmail(account!.emails, user.email);\n    updateIdentityCheckById(userId, fullnameCheck \u0026\u0026 emailCheck); // update user_table in db\n    setIsIdentityChecked(fullnameCheck \u0026\u0026 emailCheck); // set state\n  }\n}, [account, checkUserEmail, checkFullName, userId, isIdentityChecked, user]);\n```\n\nThe code in this hook verifies the user's identity using the `checkFullName()` and `checkUserEmail()` functions we added earlier. It performs the verification by comparing the user's full name and email (from their user page) against the **/identity/get** data returned earlier (which we store in a database in a separate part of the codebase). This code executes only if the user's identity has not already been verified.\n\n### Transferring funds with Dwolla\n\nLet's recap what we've added so far:\n\n- We've implemented Link and initialized with Auth and Identity\n- In the back end:\n  - We added functionality that retrieves identity and initial balance information associated with an account\n  - We added functionality that generates a processor token so that we can use the Dwolla API for money movement\n  - We added functionality that retrieves real-time balance information\n- In the front end:\n  - We added two functions that parse and return a user's legal name and email address (to help verify identity)\n  - We added a function that retrieves the current balance of an account (to prevent transfers that exceed the balance of the origination account)\n\nWith this functionality in place, we're ready to add the functionality to transfer funds with Dwolla.\n\n### Checkpoint 8: Initiating a transfer\n\nYou've made it! Let's add the code that will initiate a transfer. Navigate to **client/src/components/Transfers.tsx**. In the `checkAmountAndInitiate()` function, replace lines 74-75 with the following:\n\n```js\nsetIsAmountOkay(balance != null \u0026\u0026 amount \u003c= balance \u0026\u0026 amount \u003e 0);\nsetTransferAmount(amount);\nsetShowTransferConfirmationError(false);\nif (amount \u003c= balance \u0026\u0026 amount \u003e 0) {\n  console.log(`Checkpoint 8 complete!`);\n  console.log(`Sending to processor:`, amount);\n  const confirmedAmount =\n    IS_PROCESSOR === \"true\"\n      ? await sendRequestToProcessor(\n          amount,\n          account.funding_source_url,\n          account.item_id\n        )\n      : completeAchTransfer(amount, account.plaid_account_id);\n  if (confirmedAmount == null) {\n    setShowTransferConfirmationError(true);\n  } else {\n    const response: TransferResponse | any = await updateAppFundsBalance(\n      props.userId,\n      confirmedAmount,\n      account.plaid_account_id\n    );\n    props.setAppFund(response.data.newAppFunds);\n    props.setAccount(response.data.newAccount);\n    setIsTransferConfirmed(true);\n  }\n}\n```\n\nThe `checkAmountAndInitiate()` function will attempt to transfer funds if the amount specified doesn't exceed the balance in the account and if the transfer amount is more than $0.00. Because we're using Dwolla, the funds will be transferred according to the logic in the `sendRequestToProcessor()` function (i.e., `IS_PROCESSOR` is true). Finally, the app is updated to reflect the newly available funds, and the number of successful transfers for this account is incremented by 1 (ensuring that **/accounts/balance/get** is called on subsequent transfers to return real-time balance information).\n\nTry this code out by linking an account and initiating a transfer in the app. You should see a success message in your console for this checkpoint, along with the transfer amount being sent to the processor. `sendRequestToProcessor()` doesn't exist (yet), so you'll also see `Checkpoint #9: can't transfer to Dwolla yet` in the console.\n\nIn the next (and final!) checkpoint, we'll add the `sendRequestToProcessor()` function used in `checkAmountAndInitiate()`.\n\n### Checkpoint 9: Sending the transfer request to Dwolla\n\nLet's add the functionality that sends the transfer request to Dwolla. Replace lines 59-60 in the `sendRequestToProcessor()` function with the following:\n\n```js\ntry {\n  const createTransfer = await makeTransfer(funding_source_url, amount, itemId);\n  console.log(`Checkpoint 9 complete!`);\n  console.log(`Transfer amount:`, createTransfer.data.transfer.amount);\n  return createTransfer.data.transfer.amount;\n} catch (e) {\n  if (e instanceof Error) {\n    console.error(\"error\", e.message);\n  }\n}\n```\n\n`sendRequestToProcessor()` calls Dwolla's **/transfers/** endpoint to make the transfer. Under the hood, this function makes a call to `makeTransfer()` (defined in **[client/src/services/api.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/client/src/services/api.tsx#L74)**), which hits the route for creating transfers with Dwolla (defined in **[server/routes/items.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/server/routes/items.js#L223)**).\n\nThe request payload includes `funding_source_url`, which is specific to this particular customer account. `funding_source_url` was originally returned by the Dwolla API and saved in a database when the processor token was passed to Dwolla (also defined in **[server/routes/items.js](https://github.com/plaid/account-funding-tutorial/blob/main/pattern-af-tutorial/server/routes/items.js#L76)**).\n\n### Let's try it all out!\n\nAt this point, you should have a fully functioning app with account funding. Run `make start` in the **pattern-af-tutorial/** directory. When the app is ready, navigate to http://localhost:3002. Create a user (be sure to check \"Verify Identity Mode\"), link a bank account, and initiate a transfer. Note that if it's been more than one hour since you created your initial Dwolla access token, you'll need to \u003ca href=\"https://dashboard-sandbox.dwolla.com/applications-legacy\" target=\"_blank\"\u003ecreate another Dwolla token\u003c/a\u003e and add it to your **.env** file.\n\nAfter completing the transfer, navigate to the [Customers section of your Dwolla sandbox account](https://dashboard-sandbox.dwolla.com/customers). This page of your account shows all of the users for whom you have created a funding source with Dwolla (i.e., users you created when using the Pattern app). In the [Transactions section of your account](https://dashboard-sandbox.dwolla.com/transactions), you'll see a list of all transactions into your account. If you are able to verify the transfers you've initiated via Pattern on these pages, then you've successfully built account funding! Congrats!\n\n#### Troubleshooting\n\nIf you're encountering errors when trying to link an account in the Pattern app, check the following:\n\n1. Ensure you have a fresh Dwolla access token. Dwolla access tokens are only valid for one hour. Navigate to \u003ca href=\"https://dashboard-sandbox.dwolla.com/applications-legacy\" target=\"_blank\"\u003ehttps://dashboard-sandbox.dwolla.com/applications-legacy\u003c/a\u003e and click on the \"Create Token\" button to create a new access token.\n\n2. Make sure your Plaid API keys are set in your **.env** file (i.e.,`PLAID_CLIENT_ID`, `PLAID_SECRET_SANDBOX`).\n\n3. Make sure you have entered the correct name and email when creating a user in \"Verify Identity Mode\" in the app. For name, use `Alberta Charleson`. For the email, use `accountholder0@example.com`.\n\n### Next steps\n\nSo, what'd you think? We'd love your feedback on the tutorial. We'll use it to improve this tutorial and future Plaid tutorials. To leave feedback, visit [Feedback: Account Funding Tutorial](https://github.com/plaid/account-funding-tutorial/issues/7). Thanks in advance!\n\nFor more resources on account funding, see the following:\n\n- [Auth](https://plaid.com/docs/auth/), [Balance](https://plaid.com/docs/balance/), [Identity](https://plaid.com/docs/identity/) documentation\n\n- [Plaid Payment Partners](https://plaid.com/docs/auth/partnerships/)\n\nOther official Plaid resources you might be interested in:\n\n- [Plaid Pattern (Personal Finance Management)](https://github.com/plaid/pattern) app – Similar to Plaid Pattern (Account Funding), but with a focus on personal finance management\n\n- [Plaid's Quickstart](https://github.com/plaid/quickstart) – Get started with a React front end and back end of your choice (Python, Ruby, Node, Java, or Go)\n\n- [Plaid's Tiny Quickstart](https://github.com/plaid/tiny-quickstart) – A minimal app that implements Plaid Link, Balances, and OAuth (available in vanilla JS and React)\n\n- [Plaid's YouTube channel](https://www.youtube.com/c/PlaidInc/videos) – A collection of Plaid Academy videos that explain various aspects of Plaid, including OAuth\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplaid%2Faccount-funding-tutorial","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplaid%2Faccount-funding-tutorial","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplaid%2Faccount-funding-tutorial/lists"}