Stripe Connect module API explorer

/api/user/connect/update-payment-information (PATCH)

Account information like email addresses is generated with faker-js it is not real user information.

await global.api.user.connect.UpdatePaymentInformation.patch(req)

Returns object

{
  "stripeid": "acct_1LEC3URYutDxRFFv",
  "object": "stripeAccount",
  "accountid": "acct_99c01696e137e88c",
  "tokenUpdate": null,
  "stripeObject": {
    "id": "acct_1LEC3URYutDxRFFv",
    "object": "account",
    "business_profile": {
      "mcc": null,
      "name": null,
      "product_description": null,
      "support_address": null,
      "support_email": null,
      "support_phone": null,
      "support_url": null,
      "url": null
    },
    "business_type": "individual",
    "capabilities": {
      "card_payments": "inactive",
      "transfers": "inactive"
    },
    "charges_enabled": false,
    "company": {
      "address": {
        "city": null,
        "country": "US",
        "line1": null,
        "line2": null,
        "postal_code": null,
        "state": null
      },
      "directors_provided": true,
      "executives_provided": true,
      "name": null,
      "owners_provided": true,
      "tax_id_provided": false,
      "verification": {
        "document": {
          "back": null,
          "details": null,
          "details_code": null,
          "front": null
        }
      }
    },
    "country": "US",
    "created": 1656075373,
    "default_currency": "usd",
    "details_submitted": false,
    "email": null,
    "external_accounts": {
      "object": "list",
      "data": [
        {
          "id": "ba_1LEC3XRYutDxRFFvwZScLEhm",
          "object": "bank_account",
          "account": "acct_1LEC3URYutDxRFFv",
          "account_holder_name": "Marilyn Keebler",
          "account_holder_type": "individual",
          "account_type": null,
          "available_payout_methods": [
            "standard"
          ],
          "bank_name": "STRIPE TEST BANK",
          "country": "US",
          "currency": "usd",
          "default_for_currency": true,
          "fingerprint": "JimHdPVl5ugmtnve",
          "last4": "6789",
          "metadata": {},
          "routing_number": "110000000",
          "status": "new"
        }
      ],
      "has_more": false,
      "total_count": 1,
      "url": "/v1/accounts/acct_1LEC3URYutDxRFFv/external_accounts"
    },
    "future_requirements": {
      "alternatives": [],
      "current_deadline": null,
      "currently_due": [],
      "disabled_reason": null,
      "errors": [],
      "eventually_due": [],
      "past_due": [],
      "pending_verification": []
    },
    "metadata": {},
    "payouts_enabled": false,
    "requirements": {
      "alternatives": [],
      "current_deadline": null,
      "currently_due": [
        "business_profile.mcc",
        "business_profile.url",
        "individual.address.city",
        "individual.address.line1",
        "individual.address.postal_code",
        "individual.address.state",
        "individual.dob.day",
        "individual.dob.month",
        "individual.dob.year",
        "individual.email",
        "individual.first_name",
        "individual.last_name",
        "individual.phone",
        "individual.ssn_last_4",
        "tos_acceptance.date",
        "tos_acceptance.ip"
      ],
      "disabled_reason": "requirements.past_due",
      "errors": [],
      "eventually_due": [
        "business_profile.mcc",
        "business_profile.url",
        "individual.address.city",
        "individual.address.line1",
        "individual.address.postal_code",
        "individual.address.state",
        "individual.dob.day",
        "individual.dob.month",
        "individual.dob.year",
        "individual.email",
        "individual.first_name",
        "individual.last_name",
        "individual.phone",
        "individual.ssn_last_4",
        "tos_acceptance.date",
        "tos_acceptance.ip"
      ],
      "past_due": [
        "business_profile.mcc",
        "business_profile.url",
        "individual.address.city",
        "individual.address.line1",
        "individual.address.postal_code",
        "individual.address.state",
        "individual.dob.day",
        "individual.dob.month",
        "individual.dob.year",
        "individual.email",
        "individual.first_name",
        "individual.last_name",
        "individual.phone",
        "individual.ssn_last_4",
        "tos_acceptance.date",
        "tos_acceptance.ip"
      ],
      "pending_verification": []
    },
    "settings": {
      "bacs_debit_payments": {},
      "branding": {
        "icon": null,
        "logo": null,
        "primary_color": null,
        "secondary_color": null
      },
      "card_issuing": {
        "tos_acceptance": {
          "date": null,
          "ip": null
        }
      },
      "card_payments": {
        "decline_on": {
          "avs_failure": false,
          "cvc_failure": false
        },
        "statement_descriptor_prefix": null,
        "statement_descriptor_prefix_kana": null,
        "statement_descriptor_prefix_kanji": null
      },
      "dashboard": {
        "display_name": null,
        "timezone": "Etc/UTC"
      },
      "payments": {
        "statement_descriptor": null,
        "statement_descriptor_kana": null,
        "statement_descriptor_kanji": null
      },
      "payouts": {
        "debit_negative_balances": false,
        "schedule": {
          "delay_days": 2,
          "interval": "daily"
        },
        "statement_descriptor": null
      },
      "sepa_debit_payments": {}
    },
    "tos_acceptance": {
      "date": null,
      "ip": null,
      "user_agent": null
    },
    "type": "custom"
  },
  "requiresOwners": false,
  "requiresDirectors": false,
  "requiresExecutives": false,
  "appid": "tests_1656075372",
  "createdAt": "2022-06-24T12:56:14.605Z",
  "updatedAt": "2022-06-24T12:56:17.595Z"
}

Receives

API routes may receive parameters from the URL and POST supporting simple and multipart:

Field Value Required Type
account_holder_type string required POST
account_number string configurable as required POST
bank_code string configurable as required POST
branch_code string configurable as required POST
bsb_number string configurable as required POST
clearing_code string configurable as required POST
currency string required POST
iban string configurable as required POST
institution_number string configurable as required POST
routing_number string configurable as required POST
sort_code string configurable as required POST
transit_number string configurable as required POST

Exceptions

These exceptions are thrown (NodeJS) or returned as JSON (HTTP) if you provide incorrect data or do not meet the requirements:

Exception Circumstances
invalid-account ineligible accessing account
invalid-account_holder_type missing querystring account_holder_type
invalid querystring account_holder_type
invalid-account_number missing querystring account_number
invalid querystring account_number
invalid-bank_code missing querystring bank_code
invalid querystring bank_code
invalid-bsb_number missing querystring bsb_number
invalid querystring bsb_number
invalid-clearing_code missing querystring clearing_code
invalid querystring clearing_code
invalid-currency missing querystring currency
invalid querystring currency
invalid-iban missing querystring iban
invalid querystring iban
invalid-institution_number missing querystring institution_number
invalid querystring institution_number
invalid-routing_number missing querystring routing_number
invalid querystring routing_number
invalid-sort_code missing querystring sort_code
invalid querystring sort_code
invalid-stripeid missing querystring stripeid
invalid querystring stripeid
invalid-transit_number missing querystring transit_number
invalid querystring transit_number

NodeJS source (view on github)

const connect = require('../../../../../index.js')
const dashboard = require('@layeredapps/dashboard')
const stripeCache = require('../../../../stripe-cache.js')

module.exports = {
  patch: async (req) => {
    if (!req.query || !req.query.stripeid) {
      throw new Error('invalid-stripeid')
    }
    const stripeAccount = await global.api.user.connect.StripeAccount.get(req)
    if (stripeAccount.accountid !== req.account.accountid) {
      throw new Error('invalid-stripe-account')
    }
    if (!req.body || !req.body.currency || !req.body.currency.length) {
      throw new Error('invalid-currency')
    }
    if (!req.body.country || !req.body.country.length) {
      throw new Error('invalid-country')
    }
    if (!connect.countrySpecIndex[req.body.country]) {
      throw new Error('invalid-country')
    }
    if (!req.body.account_holder_name || !req.body.account_holder_name.length) {
      throw new Error('invalid-account_holder_name')
    }
    if (!req.body.account_holder_type || !req.body.account_holder_type.length) {
      throw new Error('invalid-account_holder_type')
    }
    if (req.body.account_holder_type !== 'individual' &&
        req.body.account_holder_type !== 'company') {
      throw new Error('invalid-account_holder_type')
    }
    let requiredFields
    switch (req.body.country) {
      case 'AU':
        requiredFields = ['account_number', 'bsb_number']
        break
      case 'BR':
        requiredFields = ['account_number', 'routing_number', 'bank_code']
        break
      case 'GB':
        if (req.body.currency === 'gbp') {
          requiredFields = ['account_number', 'sort_code']
        } else {
          requiredFields = ['iban']
        }
        break
      case 'CA':
        requiredFields = ['account_number', 'institution_number', 'transit_number']
        break
      case 'MY':
      case 'US':
      case 'NZ':
        requiredFields = ['account_number', 'routing_number']
        break
      case 'HK':
        requiredFields = ['account_number', 'clearing_code', 'branch_code']
        break
      case 'JP':
      case 'SG':
        requiredFields = ['account_number', 'bank_code', 'branch_code']
        break
      default:
        requiredFields = ['iban']
        break
    }
    for (const field of requiredFields) {
      if (!req.body[field]) {
        throw new Error(`invalid-external_account.${field}`)
      }
      if (field === 'iban') {
        const countryPart = req.body[field].substring(0, 2).toUpperCase()
        if (!connect.countryCurrencyIndex[countryPart]) {
          throw new Error('invalid-external_account.iban')
        }
        const numericPart = req.body[field].substring(2)
        const integers = '0123456789'
        for (let i = 0, len = numericPart.length; i < len; i++) {
          if (integers.indexOf(numericPart.charAt(i)) === -1) {
            throw new Error('invalid-external_account.iban')
          }
        }
        continue
      }
      if (process.env.NODE_ENV === 'testing' && req.body[field] === 'TESTMYKL') {
        // do nothing
      } else {
        if (req.body[field].indexOf('-') === -1) {
          const int = parseInt(req.body[field], 10)
          if (!int && int !== 0) {
            throw new Error(`invalid-external_account.${field}`)
          }
          if (int.toString() !== req.body[field]) {
            if (req.body[field].startsWith('0')) {
              let zeroes = ''
              for (let i = 0, len = req.body[field].length; i < len; i++) {
                if (req.body[field].charAt(i) !== '0') {
                  break
                }
                zeroes += '0'
              }
              if (int > 0) {
                zeroes += int.toString()
              }
              if (zeroes !== req.body[field]) {
                throw new Error(`invalid-external_account.${field}`)
              }
            } else {
              throw new Error(`invalid-external_account.${field}`)
            }
          }
        }
      }
    }
    const currencies = connect.countryCurrencyIndex[stripeAccount.stripeObject.country]
    let foundCurrency = false
    for (const currency of currencies) {
      foundCurrency = currency.currency === req.body.currency
      if (foundCurrency) {
        break
      }
    }
    if (!foundCurrency) {
      throw new Error('invalid-currency')
    }
    const stripeData = {
      external_account: {
        object: 'bank_account',
        currency: req.body.currency,
        country: req.body.country,
        account_holder_name: req.body.account_holder_name,
        account_holder_type: req.body.account_holder_type
      }
    }
    for (const field of requiredFields) {
      if (field === 'iban') {
        stripeData.external_account.account_number = req.body[field]
        continue
      }
      if (req.body.country === 'AU' && field === 'bsb_number') {
        stripeData.external_account.routing_number = req.body[field]
        continue
      }
      if (req.body.country === 'CA' && (field === 'institution_number' || field === 'transit_number')) {
        stripeData.external_account.routing_number = `${req.body.transit_number}-${req.body.institution_number}`
        continue
      }
      if (req.body.country === 'HK' && (field === 'branch_code' || field === 'clearing_code')) {
        stripeData.external_account.routing_number = `${req.body.clearing_code}-${req.body.branch_code}`
        continue
      }
      if (req.body.country === 'JP' && (field === 'bank_code' || field === 'branch_code')) {
        stripeData.external_account.routing_number = `${req.body.branch_code}${req.body.bank_code}`
        continue
      }
      stripeData.external_account[field] = req.body[field]
    }
    try {
      const stripeAccountNow = await stripeCache.execute('accounts', 'update', req.query.stripeid, stripeData, req.stripeKey)
      await connect.Storage.StripeAccount.update({
        stripeObject: stripeAccountNow
      }, {
        where: {
          stripeid: req.query.stripeid,
          appid: req.appid || global.appid
        }
      })
      await dashboard.StorageCache.remove(req.query.stripeid)
      return global.api.user.connect.StripeAccount.get(req)
    } catch (error) {
      if (error.message && error.message.startsWith('invalid-external_account_')) {
        throw new Error(error.message.replace('external_account_', ''))
      }
      throw error
    }
  }
}

Test source (view on github)

/* eslint-env mocha */
const assert = require('assert')
const TestHelper = require('../../../../../test-helper.js')
const TestStripeAccounts = require('../../../../../test-stripe-accounts.js')
const DashboardTestHelper = require('@layeredapps/dashboard/test-helper.js')

describe('/api/user/connect/update-payment-information', function () {
  before(TestHelper.disableMetrics)
  after(TestHelper.enableMetrics)
  describe('exceptions', () => {
    let cachedResponses
    async function bundledData (retryNumber) {
      if (retryNumber) {
        cachedResponses = {}
      }
      if (cachedResponses && cachedResponses.finished) {
        return
      }
      cachedResponses = {}
      await DashboardTestHelper.setupBeforeEach()
      await TestHelper.setupBeforeEach()
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: 'AT',
        business_type: 'individual'
      })
      let req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      // account holder type
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.account_holder_type)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingAccountHolderType = error.message
      }
      req.body.account_holder_type = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidAccountHolderType = error.message
      }
      // currency
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.currency)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingCurrency = error.message
      }
      req.body.currency = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidCurrency = error.message
      }
      // iban
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.iban)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingIBAN = error.message
      }
      req.body.iban = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidIBAN = error.message
      }
      // account number
      await TestHelper.createStripeAccount(user, {
        country: 'AU',
        business_type: 'individual'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.account_number)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingAccountNumber = error.message
      }
      req.body.account_number = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidAccountNumber = error.message
      }
      // bsb number
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.bsb_number)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingBSBNumber = error.message
      }
      req.body.bsb_number = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidBSBNumber = error.message
      }
      // intiitution number
      await TestHelper.createStripeAccount(user, {
        country: 'CA',
        business_type: 'individual'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.institution_number)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingInstitutionNumber = error.message
      }
      req.body.institution_number = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidInstitutionNumber = error.message
      }
      // transit number
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.transit_number)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingTransitNumber = error.message
      }
      req.body.transit_number = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidTransitNumber = error.message
      }
      // sort code
      await TestHelper.createStripeAccount(user, {
        country: 'GB',
        business_type: 'individual'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.sort_code)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingSortCode = error.message
      }
      req.body.sort_code = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidSortCode = error.message
      }
      // branch code
      await TestHelper.createStripeAccount(user, {
        country: 'HK',
        business_type: 'individual'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.branch_code)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingBranchCode = error.message
      }
      req.body.branch_code = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidBranchCode = error.message
      }
      // clearing code
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.clearing_code)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingClearingCode = error.message
      }
      req.body.clearing_code = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidClearingCode = error.message
      }
      // bank code
      await TestHelper.createStripeAccount(user, {
        country: 'JP',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.bank_code)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingBankCode = error.message
      }
      req.body.bank_code = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidBankCode = error.message
      }
      // routing number
      await TestHelper.createStripeAccount(user, {
        country: 'MY',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      delete (req.body.routing_number)
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingRoutingNumber = error.message
      }
      req.body.routing_number = 'invalid'
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidRoutingNumber = error.message
      }
      // invalid stripe id
      req = TestHelper.createRequest('/api/user/connect/update-payment-information')
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), 'US')
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.missingStripeID = error.message
      }
      req = TestHelper.createRequest('/api/user/connect/update-payment-information?stripeid=invalid')
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), 'US')
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidStripeID = error.message
      }
      // invalid account
      const user2 = await TestHelper.createUser()
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user2.account
      req.session = user2.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), 'US')
      try {
        await req.patch()
      } catch (error) {
        cachedResponses.invalidAccount = error.message
      }
      cachedResponses.finished = true
    }

    describe('invalid-stripeid', () => {
      it('missing querystring stripeid', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingStripeID
        assert.strictEqual(errorMessage, 'invalid-stripeid')
      })

      it('invalid querystring stripeid', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidStripeID
        assert.strictEqual(errorMessage, 'invalid-stripeid')
      })
    })

    describe('invalid-account', () => {
      it('ineligible accessing account', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidAccount
        assert.strictEqual(errorMessage, 'invalid-account')
      })
    })

    describe('invalid-account_holder_type', () => {
      it('missing querystring account_holder_type', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingAccountHolderType
        assert.strictEqual(errorMessage, 'invalid-account_holder_type')
      })
      it('invalid querystring account_holder_type', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidAccountHolderType
        assert.strictEqual(errorMessage, 'invalid-account_holder_type')
      })
    })

    describe('invalid-currency', () => {
      it('missing querystring currency', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingCurrency
        assert.strictEqual(errorMessage, 'invalid-currency')
      })
      it('invalid querystring currency', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidCurrency
        assert.strictEqual(errorMessage, 'invalid-currency')
      })
    })

    describe('invalid-iban', () => {
      it('missing querystring iban', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingIBAN
        assert.strictEqual(errorMessage, 'invalid-external_account.iban')
      })
      it('invalid querystring iban', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidIBAN
        assert.strictEqual(errorMessage, 'invalid-external_account.iban')
      })
    })

    describe('invalid-account_number', () => {
      it('missing querystring account_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingAccountNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.account_number')
      })
      it('invalid querystring account_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidAccountNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.account_number')
      })
    })

    describe('invalid-bsb_number', () => {
      it('missing querystring bsb_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingBSBNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.bsb_number')
      })
      it('invalid querystring bsb_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidBSBNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.bsb_number')
      })
    })

    describe('invalid-institution_number', () => {
      it('missing querystring institution_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingInstitutionNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.institution_number')
      })
      it('invalid querystring institution_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidInstitutionNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.institution_number')
      })
    })

    describe('invalid-transit_number', () => {
      it('missing querystring transit_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingTransitNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.transit_number')
      })
      it('invalid querystring transit_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidTransitNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.transit_number')
      })
    })

    describe('invalid-sort_code', () => {
      it('missing querystring sort_code', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingSortCode
        assert.strictEqual(errorMessage, 'invalid-external_account.sort_code')
      })
      it('invalid querystring sort_code', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidSortCode
        assert.strictEqual(errorMessage, 'invalid-external_account.sort_code')
      })
    })

    describe('invalid-clearing_code', () => {
      it('missing querystring clearing_code', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingClearingCode
        assert.strictEqual(errorMessage, 'invalid-external_account.clearing_code')
      })
      it('invalid querystring clearing_code', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidClearingCode
        assert.strictEqual(errorMessage, 'invalid-external_account.clearing_code')
      })
    })

    describe('invalid-bank_code', () => {
      it('missing querystring bank_code', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingBankCode
        assert.strictEqual(errorMessage, 'invalid-external_account.bank_code')
      })
      it('invalid querystring bank_code', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidBankCode
        assert.strictEqual(errorMessage, 'invalid-external_account.bank_code')
      })
    })

    describe('invalid-routing_number', () => {
      it('missing querystring routing_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.missingRoutingNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.routing_number')
      })
      it('invalid querystring routing_number', async function () {
        await bundledData(this.test.currentRetry())
        const errorMessage = cachedResponses.invalidRoutingNumber
        assert.strictEqual(errorMessage, 'invalid-external_account.routing_number')
      })
    })
  })

  describe('receives', () => {
    let cachedResponses
    async function bundledData (retryNumber) {
      if (retryNumber) {
        cachedResponses = {}
      }
      if (cachedResponses && cachedResponses.finished) {
        return
      }
      cachedResponses = {}
      await DashboardTestHelper.setupBeforeEach()
      await TestHelper.setupBeforeEach()
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: 'DE',
        business_type: 'company'
      })
      let req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      // account holder type
      // currency
      // iban
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.accountHolderType = cachedResponses.currency = cachedResponses.iban = await req.patch()
      // account number
      // bsb number
      await TestHelper.createStripeAccount(user, {
        country: 'AU',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.accountNumber = cachedResponses.BSBNUmber = await req.patch()
      // institution number
      // transit number
      await TestHelper.createStripeAccount(user, {
        country: 'CA',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.institutionNumber = cachedResponses.transitNumber = await req.patch()
      // sort code
      await TestHelper.createStripeAccount(user, {
        country: 'GB',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.sortCode = await req.patch()
      // branch code
      // clearing code
      await TestHelper.createStripeAccount(user, {
        country: 'HK',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.branchCode = cachedResponses.clearingCode = await req.patch()
      // bank code
      await TestHelper.createStripeAccount(user, {
        country: 'JP',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.bankCode = await req.patch()
      // routing number
      await TestHelper.createStripeAccount(user, {
        country: 'MY',
        business_type: 'company'
      })
      req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), user.stripeAccount.stripeObject.country)
      cachedResponses.routingNumber = await req.patch()
      cachedResponses.finished = true
    }

    it('required posted account_holder_type', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('required posted currency', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted iban', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted account_number', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted bsb_number', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted institution_number', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted transit_number', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted sort_code', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted branch_code', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted clearing_code', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted bank_code', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })

    it('optionally-required posted routing_number', async function () {
      await bundledData(this.test.currentRetry())
      const stripeAccountNow = cachedResponses.routingNumber
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.total_count, 1)
    })
  })

  describe('returns', () => {
    it('object', async () => {
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: 'US',
        business_type: 'individual'
      })
      const req = TestHelper.createRequest(`/api/user/connect/update-payment-information?stripeid=${user.stripeAccount.stripeid}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createBankingData('individual', TestHelper.nextIdentity(), 'US')
      req.filename = __filename
      req.saveResponse = true
      const stripeAccountNow = await req.patch()
      assert.strictEqual(stripeAccountNow.object, 'stripeAccount')
      assert.strictEqual(stripeAccountNow.stripeObject.external_accounts.data.length, 1)
    })
  })
})