Plaid

Plaid Link is used to connect a supplier’s bank account for payouts and for underwriting evidence.

Module configuration

src/app/vendors/plaid/

export const plaidConfigFactory = (config: PlaidConfigData): PlaidLinkConfig => ({
    ...plaidDefaultConfig,
    env: config.sandbox ? PlaidEnv.Sandbox : PlaidEnv.Production,
});

@NgModule()
export class PlaidModule {
    static forRoot(config: PlaidConfigData): ModuleWithProviders<PlaidModule> {
        return {
            ngModule: PlaidModule,
            providers: [
                { provide: PLAID_CONFIG_DATA, useValue: config },
                { provide: PLAID_CONFIG, useFactory: plaidConfigFactory, deps: [PLAID_CONFIG_DATA] },
            ],
        };
    }
}

Default configuration:

export const plaidDefaultConfig: PlaidLinkConfig = {
    products:     [PlaidProducts.Assets],
    env:          PlaidEnv.Sandbox,
    countryCodes: [PlaidCountryCodes.Us],
};

products

Assets only. The Transactions, Auth and Identity members exist in PlaidProducts but are not requested.

countryCodes

US only — Plaid linking is not offered outside the United States.

env

sandbox or production, from environment.plaidSandbox. PlaidEnv.Development is never selected.

AppModule wires it with PlaidModule.forRoot({ sandbox: environment.plaidSandbox }).

The OAuth redirect

Some institutions require a full-page OAuth redirect, so the Link session must be resumed after the browser returns. AppModule handles this in its constructor, before any route is activated:

private handlePlaid(): void {
    const urlParams = new URLSearchParams(window.location.search);
    if (urlParams.get('oauth_state_id')) {
        this.oauthTokenService.oauthToken = window.location.href;          (1)
        this.oauthTokenService.linkToken  = localStorage.getItem('link_token');
        localStorage.removeItem('link_token');                             (2)
    }
}
1 The whole return URL becomes receivedRedirectUri for the resumed session.
2 link_token was stored before the redirect; it is read once and removed so a stale token cannot resume a later session.

OAuthTokenService holds both values for the component that reopens Link.

oauth_state_id is read from window.location.search, not from the Angular router. With hash routing the parameter sits before the #, so the router never sees it — hence the constructor-level handling.

State

Slice

plaid (PlaidFeatureModule)

Actions

savePlaidToken, savePlaidTokenSuccess, savePlaidTokenFailed, savePlaidTokenRefresh

export const savePlaidTokenRefresh = createAction(
    PlaidActionTypes.savePlaidTokenRefresh,
    props<{ externalProductId: string }>(),
);

savePlaidTokenRefresh covers re-authentication: an existing Plaid item whose credentials have expired must be re-linked against the same externalProductId rather than creating a new connection.

The linked account’s masked number is surfaced on the user as user.plaidAccountMask.

Entry points

Onboarding

The WithPlaid schema (3.0_plaid) requires Plaid linking at the repayment-information step. See Onboarding.

Transfer Information

Linking or relinking from /manage-account/transfer-information.

Dashboard notifications

collection_account (DashboardNotificationType.PlaidCollection) and advance_underwriting (PlaidAdvance) prompt a link.

Bank verification check

BankVerificationInfoModalService.check(plaidConfig), called from GlobalSubscriptionsService.init() with the injected PLAID_CONFIG.

Lost connection

modals/lost-bank-connection-modal/ prompts the supplier to re-link when the connection drops, and BannerService shows a persistent banner alongside it.

modals/bank-verification-info-modal/

Explains why bank verification is needed.

modals/lost-bank-connection-modal/

Re-link prompt.

modals/transfer-information/

Payout method management.

modals/switch-cd-dialog/

Switch between checking and deposit accounts.

widgets/payments-config-widget/

Dashboard summary of the configured method.