Stripe Connect module API explorer

/api/user/connect/update-stripe-account (PATCH)

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

Returns object (company),object (individual)

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 querystring stripeid
invalid-stripeid missing querystring stripeid
invalid-account ineligible accessing account
invalid posted token
invalid-token missing posted token

Receives

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

Field Value Required Type
string required URL
string required URL
string required URL

NodeJS source (edit on github)

If you see a problem with the source submit a pull request on Github.

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

module.exports = {
  patch: async (req) => {
    if (!req.query || !req.query.stripeid) {
      throw new Error('invalid-stripeid')
    }
    req.body = req.body || {}
    if (global.stripeJS === 3 && !req.body.token) {
      throw new Error('invalid-token')
    }
    const stripeAccount = await global.api.user.connect.StripeAccount.get(req)
    if (!stripeAccount.requirements.currently_due.length) {
      throw new Error('invalid-stripe-account')
    }
    const accountInfo = {}
    if (global.stripeJS === 3) {
      accountInfo.account_token = req.body.token
    } else {
      let validateDOB = false
      if (req.body.dob_day) {
        validateDOB = true
        try {
          const day = parseInt(req.body.dob_day, 10)
          if (!day || day < 1 || day > 31) {
            throw new Error('invalid-dob_day')
          }
        } catch (s) {
          throw new Error('invalid-dob_day')
        }
      }
      if (req.body.dob_month) {
        validateDOB = true
        try {
          const month = parseInt(req.body.dob_month, 10)
          if (!month || month < 1 || month > 12) {
            throw new Error('invalid-dob_month')
          }
        } catch (s) {
          throw new Error('invalid-dob_month')
        }
      }
      if (req.body.dob_year) {
        validateDOB = true
        try {
          const year = parseInt(req.body.dob_year, 10)
          if (!year || year < 1900 || year > new Date().getFullYear() - 18) {
            throw new Error('invalid-dob_year111')
          }
        } catch (s) {
          throw new Error('invalid-dob_year')
        }
      }
      if (validateDOB) {
        if (!req.body.dob_day) {
          throw new Error('invalid-dob_day')
        }
        if (!req.body.dob_month) {
          throw new Error('invalid-dob_month')
        }
        if (!req.body.dob_year) {
          throw new Error('invalid-dob_year')
        }
        try {
          Date.parse(`${req.body.dob_year}/${req.body.dob_month}/${req.body.dob_day}`)
        } catch (error) {
          throw new Error('invalid-dob_day')
        }
      }
      accountInfo.metadata = {
        token: false
      }
      if (req.uploads) {
        if (req.uploads.verification_document_front) {
          const frontData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_document_front.name,
              data: req.uploads.verification_document_front.buffer
            }
          }
          const front = await stripeCache.execute('files', 'create', frontData, req.stripeKey)
          req.body.verification_document_front = front.id
        }
        if (req.uploads.verification_document_back) {
          const backData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_document_back.name,
              data: req.uploads.verification_document_back.buffer
            }
          }
          const back = await stripeCache.execute('files', 'create', backData, req.stripeKey)
          req.body.verification_document_back = back.id
        }
        if (req.uploads.verification_additional_document_front) {
          const frontData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_additional_document_front.name,
              data: req.uploads.verification_additional_document_front.buffer
            }
          }
          const front = await stripeCache.execute('files', 'create', frontData, req.stripeKey)
          req.body.verification_additional_document_front = front.id
        }
        if (req.uploads.verification_additional_document_back) {
          const backData = {
            purpose: 'identity_document',
            file: {
              type: 'application/octet-stream',
              name: req.uploads.verification_additional_document_back.name,
              data: req.uploads.verification_additional_document_back.buffer
            }
          }
          const back = await stripeCache.execute('files', 'create', backData, req.stripeKey)
          req.body.verification_additional_document_back = back.id
        }
      }
      for (const field of stripeAccount.requirements.currently_due) {
        const posted = field.split('.').join('_').replace('company_', '').replace('individual_', '')
        if (!req.body[posted]) {
          if (field === 'company.address.line2' ||
              field === 'company.verification.document' ||
              field === 'individual.verification.document' ||
              field === 'individual.verification.additional_document' ||
              field === 'external_account' ||
              field.startsWith('relationship.') ||
              field.startsWith('tos_acceptance.') ||
              field.startsWith('person_') ||
            (field === 'business_profile.url' && req.body.business_profile_product_description) ||
            (field === 'business_profile.product_description' && req.body.business_profile_url)) {
            continue
          }
          if (field === 'business_profile.product_description' && !req.body.business_profile_url) {
            throw new Error('invalid-business_profile_url')
          }
          throw new Error(`invalid-${posted}`)
        }
        if (posted.startsWith('business_profile_')) {
          const property = posted.substring('business_profile_'.length)
          accountInfo.business_profile = accountInfo.business_profile || {}
          accountInfo.business_profile[property] = req.body[posted]
        } else if (posted.startsWith('address_kanji_')) {
          const property = posted.substring('address_kanji_'.length)
          if (stripeAccount.business_type === 'company') {
            accountInfo.company = accountInfo.company || {}
            accountInfo.company.address_kanji = accountInfo.company.address_kanji || {}
            accountInfo.company.address_kanji[property] = req.body[posted]
          } else {
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual.address_kanji = accountInfo.individual.address_kanji || {}
            accountInfo.individual.address_kanji[property] = req.body[posted]
          }
        } else if (posted.startsWith('address_kana_')) {
          const property = posted.substring('address_kana_'.length)
          if (stripeAccount.business_type === 'company') {
            accountInfo.company = accountInfo.company || {}
            accountInfo.company.address_kana = accountInfo.company.address_kana || {}
            accountInfo.company.address_kana[property] = req.body[posted]
          } else {
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual.address_kana = accountInfo.individual.address_kana || {}
            accountInfo.individual.address_kana[property] = req.body[posted]
          }
        } else if (posted.startsWith('address_')) {
          const property = posted.substring('address_'.length)
          if (stripeAccount.business_type === 'company') {
            accountInfo.company = accountInfo.company || {}
            accountInfo.company.address = accountInfo.company.address || {}
            accountInfo.company.address[property] = req.body[posted]
          } else {
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual.address = accountInfo.individual.address || {}
            accountInfo.individual.address[property] = req.body[posted]
          }
        } else if (posted.startsWith('dob_')) {
          const property = posted.substring('dob_'.length)
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.dob = accountInfo.individual.dob || {}
          accountInfo.individual.dob[property] = req.body[posted]
        } else {
          if (stripeAccount.business_type === 'company') {
            const property = field.substring('company.'.length)
            accountInfo.company = accountInfo.company || {}
            accountInfo.company[property] = req.body[posted]
          } else {
            const property = field.substring('individual.'.length)
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual[property] = req.body[posted]
          }
        }
      }
      for (const field of stripeAccount.requirements.eventually_due) {
        const posted = field.split('.').join('_').replace('company_', '').replace('individual_', '')
        if (!req.body[posted]) {
          continue
        }
        if (posted.startsWith('business_profile_')) {
          const property = posted.substring('business_profile_'.length)
          accountInfo.business_profile = accountInfo.business_profile || {}
          accountInfo.business_profile[property] = req.body[posted]
        } else if (posted.startsWith('address_kanji_')) {
          const property = posted.substring('address_kanji_'.length)
          if (stripeAccount.business_type === 'company') {
            accountInfo.company = accountInfo.company || {}
            accountInfo.company.address_kanji = accountInfo.company.address_kanji || {}
            accountInfo.company.address_kanji[property] = req.body[posted]
          } else {
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual.address_kanji = accountInfo.individual.address_kanji || {}
            accountInfo.individual.address_kanji[property] = req.body[posted]
          }
        } else if (posted.startsWith('address_kana_')) {
          const property = posted.substring('address_kana_'.length)
          if (stripeAccount.business_type === 'company') {
            accountInfo.company = accountInfo.company || {}
            accountInfo.company.address_kana = accountInfo.company.address_kana || {}
            accountInfo.company.address_kana[property] = req.body[posted]
          } else {
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual.address_kana = accountInfo.individual.address_kana || {}
            accountInfo.individual.address_kana[property] = req.body[posted]
          }
        } else if (posted.startsWith('address_')) {
          const property = posted.substring('address_'.length)
          if (stripeAccount.business_type === 'company') {
            accountInfo.company = accountInfo.company || {}
            accountInfo.company.address = accountInfo.company.address || {}
            accountInfo.company.address[property] = req.body[posted]
          } else {
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual.address = accountInfo.individual.address || {}
            accountInfo.individual.address[property] = req.body[posted]
          }
        } else if (posted.startsWith('dob_')) {
          const property = posted.substring('dob_'.length)
          accountInfo.individual.dob = accountInfo.individual.dob || {}
          accountInfo.individual.dob[property] = req.body[posted]
        } else {
          if (stripeAccount.business_type === 'company') {
            const property = field.substring('company.'.length)
            accountInfo.company = accountInfo.company || {}
            accountInfo.company[property] = req.body[posted]
          } else {
            const property = field.substring('individual.'.length)
            accountInfo.individual = accountInfo.individual || {}
            accountInfo.individual[property] = req.body[posted]
          }
        }
      }
      if (req.body.business_profile_mcc) {
        const mccList = connect.getMerchantCategoryCodes(req.language)
        let found = false
        for (const mcc of mccList) {
          found = mcc.code === req.body.business_profile_mcc
          if (found) {
            break
          }
        }
        if (!found) {
          throw new Error('invalid-business_profile_mcc')
        }
        accountInfo.business_profile = accountInfo.business_profile || {}
        accountInfo.business_profile.mcc = req.body.business_profile_mcc
      }
      if (req.body.business_profile_url) {
        if (!req.body.business_profile_url.startsWith('http://') &&
            !req.body.business_profile_url.startsWith('https://')) {
          throw new Error('invalid-business_profile_url')
        }
        accountInfo.business_profile = accountInfo.business_profile || {}
        accountInfo.business_profile.url = req.body.business_profile_url
      }
      if (req.body.business_profile_product_description) {
        accountInfo.business_profile = accountInfo.business_profile || {}
        accountInfo.business_profile.product_description = req.body.business_profile_product_description
      }
      // TODO: these fields are optional but not represented in requirements
      // so when Stripe updates to have something like an 'optionally_due' array
      // the manual checks can be removed
      if (req.body.address_line2) {
        accountInfo.company.address = accountInfo.company.address || {}
        accountInfo.company.address.line2 = req.body.address_line2
      }
      if (req.body.address_country && req.body.address_country.length) {
        if (!connect.countryNameIndex[req.body.address_country]) {
          throw new Error('invalid-address_country')
        }
        if (stripeAccount.business_type === 'company') {
          accountInfo.company = accountInfo.company || []
          accountInfo.company.address = accountInfo.company.address || {}
          accountInfo.company.address.country = req.body.address_country
        } else {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.address = accountInfo.individual.address || {}
          accountInfo.individual.address.country = req.body.address_country
        }
      }
      if (req.body.address_state && req.body.address_state.length) {
        const states = connect.countryDivisions[req.body.address_country || stripeAccount.country]
        let found
        for (const state of states) {
          found = state.value === req.body.address_state
          if (found) {
            break
          }
        }
        if (!found) {
          throw new Error('invalid-address_state')
        }
        if (stripeAccount.business_type === 'company') {
          accountInfo.company.address = accountInfo.company.address || {}
          accountInfo.company.address.state = req.body.address_state
        } else {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.address = accountInfo.individual.address || {}
          accountInfo.individual.address.state = req.body.address_state
        }
      }
      if (req.body.address_postal_code) {
        if (stripeAccount.business_type === 'company') {
          accountInfo.company = accountInfo.company || {}
          accountInfo.company.address = accountInfo.company.address || {}
          accountInfo.company.address.postal_code = req.body.address_postal_code
        } else {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.address = accountInfo.individual.address || {}
          accountInfo.individual.address.postal_code = req.body.address_postal_code
        }
      }
      if (req.body.tax_id && !req.body.tax_id.length) {
        throw new Error('invalid-tax_id')
      }
      // TODO: check this document is required before updating
      // currently Stripe do not correctly report it as required
      // during testing it just goes straight to review without
      // submitting or ever requiring it
      if (stripeAccount.business_type === 'company') {
        if (req.body.verification_document_back) {
          accountInfo.company = accountInfo.company || {}
          accountInfo.company.verification = accountInfo.company.verification || {}
          accountInfo.company.verification.document = accountInfo.company.verification.document || {}
          accountInfo.company.verification.document.back = req.body.verification_document_back
        }
        if (req.body.verification_document_front) {
          accountInfo.company = accountInfo.company || {}
          accountInfo.company.verification = accountInfo.company.verification || {}
          accountInfo.company.verification.document = accountInfo.company.verification.document || {}
          accountInfo.company.verification.document.front = req.body.verification_document_front
        }
      } else {
        if (req.body.gender && req.body.gender !== 'male' && req.body.gender !== 'female') {
          throw new Error('invalid-gender')
        }
        // TODO: 7 was arbitrarily selected as a minimum
        // but there must be an actual minimum value, and it
        // should be possible to have per-country minimums
        if (req.body.id_number && (!req.body.id_number.length || req.body.id_number.length < 7)) {
          throw new Error('invalid-id_number')
        }
        if (req.body.ssn_last_4 && req.body.ssn_last_4.length !== 4) {
          throw new Error('invalid-ssn_last_4')
        }
        if (req.body.verification_document_back) {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.verification = accountInfo.individual.verification || {}
          accountInfo.individual.verification.document = accountInfo.individual.verification.document || {}
          accountInfo.individual.verification.document.back = req.body.verification_document_back
        }
        if (req.body.verification_document_front) {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.verification = accountInfo.individual.verification || {}
          accountInfo.individual.verification.document = accountInfo.individual.verification.document || {}
          accountInfo.individual.verification.document.front = req.body.verification_document_front
        }
        if (req.body.verification_additional_document_back) {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.verification = accountInfo.individual.verification || {}
          accountInfo.individual.verification.additional_document = accountInfo.individual.verification.additional_document || {}
          accountInfo.individual.verification.additional_document.back = req.body.verification_additional_document_back
        }
        if (req.body.verification_additional_document_front) {
          accountInfo.individual = accountInfo.individual || {}
          accountInfo.individual.verification = accountInfo.individual.verification || {}
          accountInfo.individual.verification.additional_document = accountInfo.individual.verification.additional_document || {}
          accountInfo.individual.verification.additional_document.front = req.body.verification_additional_document_front
        }
      }
    }
    try {
      const stripeAccountNow = await stripeCache.execute('accounts', 'update', req.query.stripeid, accountInfo, req.stripeKey)
      await stripeCache.delete(req.query.stripeid)
      return stripeAccountNow
    } catch (error) {
      if (error.message && error.message.startsWith('invalid-company_')) {
        throw new Error(error.message.replace('company_', ''))
      }
      throw error
    }
  }
}

Test source (edit on github)

Tests perform real HTTP requests against a running Dashboard server.

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

describe('/api/user/connect/update-stripe-account', function () {
  this.timeout(60 * 60 * 1000)
  const rejectIndividualMissingResults = {}
  const rejectCompanyMissingResults = {}
  const submitIndividualResponse = {}
  const submitIndividualPayload = {}
  const submitCompanyResponse = {}
  const submitCompanyPayload = {}
  const testedIndividualRequiredFields = []
  const testedCompanyRequiredFields = [
    'relationship_title',
    'relationship_director',
    'relationship_executive',
    'relationship_representative',
    'relationship_owner'
  ]
  const uploadFields = [
    'verification_document_front',
    'verification_document_back',
    'verification_additional_document_front',
    'verification_additional_document_back'
  ]
  after(TestHelper.deleteOldWebhooks)
  before(async () => {
    await DashboardTestHelper.setupBeforeEach()
    await TestHelper.setupBeforeEach()
    await TestHelper.setupWebhook()
    const individuals = {}
    const companies = {}
    for (const country of connect.countrySpecs) {
      let individual = individuals[country.id]
      if (!individual) {
        individual = await TestHelper.createUser()
        await TestHelper.createStripeAccount(individual, {
          country: country.id,
          type: 'individual'
        })
        individuals[country.id] = individual
      }
      const individualPayload = TestStripeAccounts.createPostData(TestStripeAccounts.individualData[country.id])
      if (individualPayload === false) {
        continue
      }
      for (const field in individualPayload) {
        if (testedIndividualRequiredFields.indexOf(field) > -1) {
          continue
        }
        testedIndividualRequiredFields.push(field)
        const req3 = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${individual.stripeAccount.id}`)
        req3.account = individual.account
        req3.session = individual.session
        req3.body = TestStripeAccounts.createPostData(TestStripeAccounts.individualData[country.id])
        delete (req3.body[field])
        try {
          await req3.patch()
        } catch (error) {
          rejectIndividualMissingResults[field] = error.message
        }
      }
      const req3 = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${individual.stripeAccount.id}`)
      req3.account = individual.account
      req3.session = individual.session
      req3.body = TestStripeAccounts.createPostData(TestStripeAccounts.individualData[country.id])
      const submitResponse = await req3.patch()
      for (const field in individualPayload) {
        submitIndividualResponse[field] = submitResponse
      }
      submitIndividualPayload[country.id] = individualPayload
      let company = companies[country.id]
      if (!company) {
        company = await TestHelper.createUser()
        await TestHelper.createStripeAccount(company, {
          country: country.id,
          type: 'company'
        })
        companies[country.id] = company
      }
      const companyPayload = TestStripeAccounts.createPostData(TestStripeAccounts.companyData[country.id])
      if (companyPayload === false) {
        continue
      }
      for (const field in companyPayload) {
        if (testedCompanyRequiredFields.indexOf(field) > -1) {
          continue
        }
        testedCompanyRequiredFields.push(field)
        const req3 = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${company.stripeAccount.id}`)
        req3.account = company.account
        req3.session = company.session
        req3.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData[country.id])
        delete (req3.body[field])
        try {
          await req3.patch()
        } catch (error) {
          rejectCompanyMissingResults[field] = error.message
        }
      }
      const req4 = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${company.stripeAccount.id}`)
      req4.account = company.account
      req4.session = company.session
      req4.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData[country.id])
      const submitResponse2 = await req4.patch()
      for (const field in companyPayload) {
        submitCompanyResponse[field] = submitResponse2
      }
      submitCompanyPayload[country.id] = companyPayload
    }
    // upload fields
    const individual1 = await TestHelper.createUser()
    await TestHelper.createStripeAccount(individual1, {
      country: 'AT',
      type: 'individual'
    })
    await TestHelper.updateStripeAccount(individual1, TestStripeAccounts.createPostData(TestStripeAccounts.individualData.AT))
    const individual2 = await TestHelper.createUser()
    await TestHelper.createStripeAccount(individual2, {
      country: 'AT',
      type: 'individual'
    })
    await TestHelper.updateStripeAccount(individual2, TestStripeAccounts.createPostData(TestStripeAccounts.individualData.AT))
    await TestHelper.updateStripeAccount(individual2, null, {
      verification_document_front: TestHelper['success_id_scan_back.png'],
      verification_document_back: TestHelper['success_id_scan_back.png']
    })
    for (const field of uploadFields) {
      const user = field.startsWith('verification_additional') ? individual2 : individual1
      const property = field.replace('verification_', 'verification.').replace('_front', '').replace('_back', '')
      await TestHelper.waitForAccountRequirement(user, `individual.${property}`)
      const req2 = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
      req2.uploads = {
        verification_additional_document_front: TestHelper['success_id_scan_back.png'],
        verification_additional_document_back: TestHelper['success_id_scan_back.png'],
        verification_document_front: TestHelper['success_id_scan_back.png'],
        verification_document_back: TestHelper['success_id_scan_back.png']
      }
      delete (req2.uploads[field])
      try {
        await req2.patch()
      } catch (error) {
        rejectIndividualMissingResults[field] = error.message
      }
    }
  })
  describe('exceptions', async () => {
    describe('invalid-stripeid', () => {
      it('missing querystring stripeid', async () => {
        const user = await TestHelper.createUser()
        const req = TestHelper.createRequest('/api/user/connect/update-stripe-account')
        req.account = user.account
        req.session = user.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData.US)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-stripeid')
      })

      it('invalid querystring stripeid', async () => {
        const user = await TestHelper.createUser()
        const req = TestHelper.createRequest('/api/user/connect/update-stripe-account?stripeid=invalid')
        req.account = user.account
        req.session = user.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData.US)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-stripeid')
      })
    })

    describe('invalid-account', () => {
      it('ineligible accessing account', async () => {
        const user = await TestHelper.createUser()
        await TestHelper.createStripeAccount(user, {
          country: 'DE',
          type: 'company'
        })
        const user2 = await TestHelper.createUser()
        const req = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
        req.account = user2.account
        req.session = user2.session
        req.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData.DE)
        let errorMessage
        try {
          await req.patch(req)
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-account')
      })
    })
    // const invalidIndividualValues = {
    //   gender: 'invalid',
    //   id_number: '0',
    //   ssn_last_4: '0',
    //   dob_day: '0',
    //   dob_month: '0',
    //   dob_year: '0'
    // }
    // const invalidCompanyValues = {
    //   address_line1: false,
    //   address_city: false,
    //   address_state: 'invalid',
    //   address_country: 'invalid',
    //   address_postal_code: 'invalid',
    //   address_kana_line1: false,
    //   address_kana_city: false,
    //   address_kana_town: 'invalid',
    //   address_kana_state: 'invalid',
    //   address_kana_postal_code: false,
    //   address_kanji_line1: false,
    //   address_kanji_city: false,
    //   address_kanji_town: false,
    //   address_kanji_state: 'invalid',
    //   address_kanji_postal_code: false,
    //   business_profile_mcc: 'invalid',
    //   business_profile_url: 'invalid',
    //   tax_id: false,
    //   phone: 'invalid',
    //   name: false,
    //   name_kana: false,
    //   name_kanji: false
    // }
    const testedCompanyMissingFields = []
    for (const country of connect.countrySpecs) {
      const companyPayload = TestStripeAccounts.createPostData(TestStripeAccounts.companyData[country.id])
      for (const field in companyPayload) {
        if (testedCompanyMissingFields.indexOf(field) > -1) {
          continue
        }
        testedCompanyMissingFields.push(field)
        describe(`invalid-${field}`, async () => {
          it(`missing posted ${field} (company)`, async () => {
            const errorMessage = rejectCompanyMissingResults[field]
            assert.strictEqual(errorMessage, `invalid-${field}`)
          })

          // if (invalidCompanyValues[field] !== undefined && invalidCompanyValues[field] !== false) {
          //   it(`invalid posted ${field}`, async () => {
          //     const errorMessage = rejectCompanyInvalidResults[field]
          //     assert.strictEqual(errorMessage, `invalid-${field}`)
          //   })
          // }
        })
      }
    }
    const testedIndividualMissingFields = []
    for (const country of connect.countrySpecs) {
      const individualPayload = TestStripeAccounts.createPostData(TestStripeAccounts.individualData[country.id])
      for (const field in individualPayload) {
        if (testedIndividualMissingFields.indexOf(field) > -1) {
          continue
        }
        testedIndividualMissingFields.push(field)
        describe(`invalid-${field}`, async () => {
          it(`missing posted ${field} (individual)`, async () => {
            const errorMessage = rejectIndividualMissingResults[field]
            assert.strictEqual(errorMessage, `invalid-${field}`)
          })

          // if (invalidIndividualValues[field] !== undefined && invalidIndividualValues[field] !== false) {
          //   it(`invalid posted ${field}`, async () => {
          //     const errorMessage = rejectInvidividualInvalidResults[field]
          //     assert.strictEqual(errorMessage, `invalid-${field}`)
          //   })
          // }
        })
      }
    }

    describe('invalid-token', () => {
      it('missing posted token', async () => {
        global.stripeJS = 3
        const user = await TestHelper.createUser()
        await TestHelper.createStripeAccount(user, {
          country: 'GB',
          type: 'company'
        })
        const req = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
        req.account = user.account
        req.session = user.session
        req.body = TestHelper.createMultiPart(req, TestStripeAccounts.createPostData(TestStripeAccounts.companyData.GB), {
          verification_document_back: TestHelper['success_id_scan_back.png'],
          verification_document_front: TestHelper['success_id_scan_front.png']
        })
        let errorMessage
        try {
          await req.patch()
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-token')
      })

      it('invalid posted token', async () => {
        global.stripeJS = 3
        const user = await TestHelper.createUser()
        await TestHelper.createStripeAccount(user, {
          country: 'GB',
          type: 'company'
        })
        const req = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
        req.account = user.account
        req.session = user.session
        const body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData.GB)
        body.token = 'invalid'
        req.body = TestHelper.createMultiPart(req, body, {
          verification_document_back: TestHelper['success_id_scan_back.png'],
          verification_document_front: TestHelper['success_id_scan_front.png']
        })
        let errorMessage
        try {
          await req.patch()
        } catch (error) {
          errorMessage = error.message
        }
        assert.strictEqual(errorMessage, 'invalid-token')
      })
    })
  })

  describe('receives', () => {
    const testedCompanyRequiredFields = []
    for (const country of connect.countrySpecs) {
      const companyPayload = submitCompanyPayload[country.id]
      for (const field in companyPayload) {
        if (testedCompanyRequiredFields.indexOf(field) > -1) {
          continue
        }
        testedCompanyRequiredFields.push(field)
        it(`optionally-required posted ${field}`, async () => {
          const stripeAccountNow = submitCompanyResponse[field]
          if (field.startsWith('address_kana_')) {
            const property = field.substring('address_kana_'.length)
            assert.strictEqual(stripeAccountNow.company.address_kana[property], companyPayload[field])
          } else if (field.startsWith('address_kanji')) {
            const property = field.substring('address_kanji_'.length)
            if (field === 'address_kanji_patchal_code') {
              assert.strictEqual(stripeAccountNow.company.address_kanji[property], '1500001')
            } else {
              assert.strictEqual(stripeAccountNow.company.address_kanji[property], companyPayload[field])
            }
          } else if (field.startsWith('address_')) {
            const property = field.substring('address_'.length)
            assert.strictEqual(stripeAccountNow.company.address[property], companyPayload[field])
          } else if (field.startsWith('business_profile')) {
            const property = field.substring('business_profile_'.length)
            assert.strictEqual(stripeAccountNow.business_profile[property], companyPayload[field])
          } else {
            // TODO: Stripe may or may not transform the phone number
            // by removing hyphons and adding the country dial code
            // but submitting in that format is not allowed too
            if (field === 'phone') {
              if (stripeAccountNow.company[field] === companyPayload[field]) {
                assert.strictEqual(stripeAccountNow.company[field], companyPayload[field])
              } else {
                let withoutCountryCode = companyPayload[field]
                withoutCountryCode = withoutCountryCode.substring(withoutCountryCode.indexOf('4'))
                assert.strictEqual(stripeAccountNow.company[field], withoutCountryCode)
              }
            } else if (field === 'tax_id') {
              assert.strictEqual(stripeAccountNow.company.tax_id_provided, true)
            } else {
              assert.strictEqual(stripeAccountNow.company[field], companyPayload[field])
            }
          }
        })
      }
    }
    const testedIndividualRequiredFields = []
    for (const country of connect.countrySpecs) {
      const individualPayload = submitIndividualPayload[country.id]
      for (const field in individualPayload) {
        if (testedIndividualRequiredFields.indexOf(field) > -1) {
          continue
        }
        testedIndividualRequiredFields.push(field)
        it(`optionally-required posted ${field}`, async () => {
          const stripeAccountNow = submitIndividualResponse[field]
          if (field.startsWith('address_kana_')) {
            const property = field.substring('address_kana_'.length)
            assert.strictEqual(stripeAccountNow.individual.address_kana[property], individualPayload[field])
          } else if (field.startsWith('address_kanji')) {
            const property = field.substring('address_kanji_'.length)
            if (field === 'address_kanji_patchal_code') {
              assert.strictEqual(stripeAccountNow.individual.address_kanji[property], '1500001')
            } else {
              assert.strictEqual(stripeAccountNow.individual.address_kanji[property], individualPayload[field])
            }
          } else if (field.startsWith('address_')) {
            const property = field.substring('address_'.length)
            assert.strictEqual(stripeAccountNow.individual.address[property], individualPayload[field])
          } else if (field.startsWith('business_profile')) {
            const property = field.substring('business_profile_'.length)
            assert.strictEqual(stripeAccountNow.business_profile[property], individualPayload[field])
          } else if (field.startsWith('dob_')) {
            const property = field.substring('dob_'.length)
            assert.strictEqual(stripeAccountNow.individual.dob[property], parseInt(individualPayload[field], 10))
          } else {
            // TODO: Stripe may or may not transform the phone number
            // by removing hyphons and adding the country dial code
            // but submitting in that format is not allowed too
            if (field === 'phone') {
              if (stripeAccountNow.individual[field] === individualPayload[field]) {
                assert.strictEqual(stripeAccountNow.individual[field], individualPayload[field])
              } else {
                let withoutCountryCode = individualPayload[field]
                withoutCountryCode = withoutCountryCode.substring(withoutCountryCode.indexOf('4'))
                assert.strictEqual(stripeAccountNow.individual[field], withoutCountryCode)
              }
            } else if (field === 'ssn_last_4') {
              assert.strictEqual(stripeAccountNow.individual.ssn_last_4_provided, true)
            } else if (field === 'id_number') {
              assert.strictEqual(stripeAccountNow.individual.id_number_provided, true)
            } else {
              assert.strictEqual(stripeAccountNow.individual[field], individualPayload[field])
            }
          }
        })
      }
    }

    const uploadFields = [
      // may be company or individual verification document
      'verification_document_front',
      'verification_document_back',
      // only individual
      'verification_additional_document_front',
      'verification_additional_document_back'
    ]
    for (const field of uploadFields) {
      it(`optionally-required patched ${field}`, async () => {
        const user = await TestHelper.createUser()
        if (field.indexOf('additional') > -1) {
          await TestHelper.createStripeAccount(user, {
            country: 'GB',
            type: 'individual'
          })
        } else {
          await TestHelper.createStripeAccount(user, {
            country: 'GB',
            type: 'company'
          })
        }
        const req = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
        req.account = user.account
        req.session = user.session
        let body
        if (user.stripeAccount.business_type === 'company') {
          body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData.GB)
        } else {
          body = TestStripeAccounts.createPostData(TestStripeAccounts.individualData.GB)
        }
        req.body = TestHelper.createMultiPart(req, body, {
          [field]: TestHelper['success_id_scan_back.png']
        })
        const stripeAccountNow = await req.patch()
        if (field === 'verification_document_front') {
          assert.notStrictEqual(stripeAccountNow.company.verification.document.front, null)
          assert.notStrictEqual(stripeAccountNow.company.verification.document.front, undefined)
        } else if (field === 'verification_document_back') {
          assert.notStrictEqual(stripeAccountNow.company.verification.document.back, null)
          assert.notStrictEqual(stripeAccountNow.company.verification.document.back, undefined)
        } else if (field === 'verification_additional_document_front') {
          assert.notStrictEqual(stripeAccountNow.individual.verification.additional_document.front, null)
          assert.notStrictEqual(stripeAccountNow.individual.verification.additional_document.front, undefined)
        } else {
          assert.notStrictEqual(stripeAccountNow.individual.verification.additional_document.back, null)
          assert.notStrictEqual(stripeAccountNow.individual.verification.additional_document.back, undefined)
        }
      })
    }
  })

  describe('returns', () => {
    it('object (company)', async () => {
      const country = connect.countrySpecs[Math.floor(Math.random() * connect.countrySpecs.length)]
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: country.id,
        type: 'company'
      })
      const req = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData[country.id])
      req.uploads = {
        verification_document_back: TestHelper['success_id_scan_back.png'],
        verification_document_front: TestHelper['success_id_scan_front.png']
      }
      const stripeAccountNow = await req.patch()
      assert.strictEqual(stripeAccountNow.object, 'account')
      assert.strictEqual(stripeAccountNow.metadata.token, 'false')
    })

    it('object (individual)', async () => {
      const country = connect.countrySpecs[Math.floor(Math.random() * connect.countrySpecs.length)]
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: country.id,
        type: 'individual'
      })
      const req = TestHelper.createRequest(`/api/user/connect/update-stripe-account?stripeid=${user.stripeAccount.id}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createPostData(TestStripeAccounts.individualData[country.id])
      req.uploads = {
        verification_document_back: TestHelper['success_id_scan_back.png'],
        verification_document_front: TestHelper['success_id_scan_front.png']
      }
      req.filename = __filename
      req.saveResponse = true
      const stripeAccountNow = await req.patch()
      assert.strictEqual(stripeAccountNow.object, 'account')
      assert.strictEqual(stripeAccountNow.metadata.token, 'false')
    })
  })

  describe('configuration', () => {
    it('environment STRIPE_JS', async () => {
      global.stripeJS = 3
      const user = await TestHelper.createUser()
      await TestHelper.createStripeAccount(user, {
        country: 'US',
        type: 'company'
      })
      const req = TestHelper.createRequest(`/account/connect/edit-stripe-account?stripeid=${user.stripeAccount.id}`)
      req.account = user.account
      req.session = user.session
      req.body = TestStripeAccounts.createPostData(TestStripeAccounts.companyData.US)
      await req.post()
      const stripeAccountNow = await global.api.user.connect.StripeAccount.get(req)
      // TODO: verifying information was submitted by token is
      // not possible so for now when objects are updated
      // without a token they have a metadata.token = false flag set
      assert.strictEqual(stripeAccountNow.metadata.token, undefined)
    })
  })
})