Bank Account Onboarding

Walks an applicant through bank-account onboarding: business details, personal details, optional additional owners, and a result screen.

Part ofEmbedded Banking

Walks an applicant through bank-account onboarding: business details, personal details, optional additional owners, and a result screen. The widget handles saving, validation, submission and waiting for the account to open; you supply auth and two callbacks.


Quick Start

The widget renders inline and fills its container, so mounting it is what shows it. Give the container a real height, typically a dedicated onboarding page or a route you navigate to from your own trigger (for example OfferWidget's primary CTA).

import { BankAccountOnboardingWidget } from '@tesouro/embedded-components-react';

export function OnboardingPage() {
  return (
    <div style={{ height: '100vh', minHeight: 600 }}>
      <BankAccountOnboardingWidget
        baseUrl="https://api.example.com"
        widgetToken="wt_live_abc123"
        organizationId="org_xyz"
        onEmbeddedOnboardingCompletedSuccessfully={handleComplete}
        onNavigateToDashboard={goToDashboard}
      />
    </div>
  );
}

Behaviour

  • The widget renders nothing until widget init and the organization's application status resolve, and nothing at all when the user is already ACTIVE / INACTIVE. Each suppression emits an onboarding.suppressed analytics event and calls onSuppressed(reason) — see Suppression reasons.
  • A draft your backend pre-populated resumes as the applicant's own when it holds their work email: the widget picks up its application client secret, so you pass no application ID or secret. Without the email it shows the "Application in progress" card.
  • One mounted widget serves one applicant. Remount it (a new React key) whenever the applicant changes. Swapping widgetToken in place is treated as a token rotation and keeps the form.
  • onEmbeddedOnboardingCompletedSuccessfully fires only when the account is fully open. An application still under review, declined, or slow to provision shows a "we'll email you" pending screen instead.
  • The first step has no Back button and there is no Cancel control, since the widget has nowhere to go back to; Back between completed steps still works.
  • Save and continue later saves the application and confirms with a toast, leaving the applicant on the same step. Delete removes it, confirms with a toast, and starts a fresh application. The toasts render inside the widget, so keep it mounted.
  • Disclosure acceptance is recorded once the account opens. If that fails, the success screen still shows and AcceptDisclosuresWidget is the retry path.

If the organization already has an application, the widget renders by its status:

ApplicationRenders
None, DELETED or CANCELEDThe form
DRAFT started by the applicantThe form, resumed
DRAFT started by someone else"Application in progress" card
SUBMITTED (either applicant)"Under review" card
DENIED (either applicant), within 30 days"Not approved" card
DENIED more than 30 days ago, or COMPLETENothing (onboarding.suppressed)

The card replaces the form. Its copy comes from labels.applicationStatus. Set showApplicationStatusRefresh to add a Check again button to the card; the widget does not re-read the status on window focus. If a re-check finds a status the widget has no copy for, the card switches to labels.applicationStatus.unavailable and keeps the button, so the user can try again.

Suppression reasons

Not every reason means an account exists. If you unlock account-scoped navigation from onSuppressed, branch on the reason rather than treating them alike.

OnboardingSuppressionReasonValueAccount provisioned?
UserAlreadyOnboardeduser_already_onboardedYes
OrganizationApplicationCompleteorganization_application_completeYes
UserInvitedToOrganizationuser_invited_to_organizationNo — pending disclosure acceptance
OrganizationApplicationStartedByOtherorganization_application_started_by_otherNo — another member's application is still in flight
OrganizationApplicationDenialExpiredorganization_application_denial_expiredNo — the application was denied more than 30 days ago
OrganizationApplicationStatusUnrecognizedorganization_application_status_unrecognizedNo — the application has a status the widget does not recognize

Props

Widget props

PropTypeDefaultDescription
onEmbeddedOnboardingCompletedSuccessfullyEvent() => voidRequiredCalled when the application is approved and the account is open.
onNavigateToDashboardEvent() => voidRequiredCalled when the user clicks the dashboard CTA on the result screen.
initialBusinessDetails
Partial<HostSupplied<BusinessDetailsValues>>
Partial<HostSupplied<BusinessDetailsValues>>
undefinedPrefills step 2 (business details); the user can still edit.
initialPersonalDetails
Partial<HostSupplied<PersonalDetailsValues>>
Partial<HostSupplied<PersonalDetailsValues>>
undefinedPrefills step 1 (personal details); the user can still edit.
initialAdditionalOwnersHostSuppliedOwner[][]Prefills the owners list on step 2.
bankLogoSrcstringundefinedBank logo URL for the result screen; falls back to the bank name as text.
disclosureLinksDisclosureLinksundefinedURLs for Terms of Use, Privacy Policy, Electronic Communication and Patriot Act on the Terms step. You resolve these; omit to leave unset.
onSuppressedEvent
(reason: OnboardingSuppressionReason) => void
(reason: OnboardingSuppressionReason) => void
undefinedCalled once the widget decides to render nothing, with the reason. Use it to swap in your own content instead of leaving the empty render.
showApplicationStatusRefreshbooleanfalseAdds a Check again button to the application status card that re-reads the organization's application. Never shown over the form or result screens.
onResultPhaseChangeEvent
(isInResultPhase: boolean) => void
(isInResultPhase: boolean) => void
undefinedCalled with true once the widget starts processing a submitted application, and with false if it unmounts after that. While true it keeps its processing or result screen up whatever the status read says, so leave it mounted.
Label overrides
PropTypeDefaultDescription
labelsLabelsBankAccountOnboardingWidgetLabelsEnglish labelsPer-step and shell copy overrides, merged with the English defaults.

Examples

Overriding labels

Pass only the strings you want to change; everything else falls back to English. See the exported BankAccountOnboardingWidgetLabels type for every key. APPLICATION_STATUS_LABELS_EN holds the English status-card copy, so an override can reuse it.

<BankAccountOnboardingWidget
  labels={{
    stepIndicator: {
      personal: 'Personal',
      business: 'Negocio',
      review: 'Revisión',
      terms: 'Términos',
      done: 'Listo',
    },
    businessDetails: { heading: 'Datos de la empresa' },
    result: { successHeadingLine1: 'Tu cuenta está lista' },
  }}
  onEmbeddedOnboardingCompletedSuccessfully={handleComplete}
  onNavigateToDashboard={goToDashboard}
/>

TypeScript

import type {
  BankAccountOnboardingWidgetProps,
  BankAccountOnboardingWidgetLabels,
  DisclosureLinks,
  OnboardingSuppressionReason,
  ApplicationStatusLabels,
  BusinessDetailsValues,
  BusinessDetailsLabels,
  PersonalDetailsValues,
  PersonalDetailsLabels,
  AdditionalOwner,
  AdditionalOwnersLabels,
  ResultLabels,
} from '@tesouro/embedded-components-react';

On this page