Instant Transfer
Instant Transfer moves a supplier’s balance to a debit card immediately, outside the normal payout schedule, for a fee. Card capture is handled by TabaPay in an embedded iframe, so raw card data never touches the application.
Eligibility
Two independent gates:
|
Grants the |
|
Server-side gate on actually requesting a transfer. |
|
Holding |
Setup flow
InstantTransferService.openInstantTransferSetupModal()
openInstantTransferSetupModal(): Observable<any> {
this.twoFactorAuthenticationService.checkTwoFactorAuthenticationState().then(isTFAConfirmed => {
if (isTFAConfirmed) { (1)
this.dialogService.open<InstantTransferSetupModal>(InstantTransferSetupModal)
.beforeClosed()
.pipe(withLatestFrom(this.store.select(selectBusinessInformation)))
.subscribe(([res, bizInfo]) => this.nextStep(res, bizInfo));
} else {
this.onSetupFinish.error('twoFactorAuthenticationFail'); (2)
}
});
return this.onSetupFinish.asObservable();
}
| 1 | Setting up a payout card requires a confirmed second factor. This is the only product flow in the application that gates on 2FA directly rather than through a route guard. |
| 2 | A failed challenge errors the onSetupFinish subject, so callers can react. |
supplier clicks "Set up Instant Transfer"
→ 2FA challenge (TwoFactorAuthenticationService)
→ InstantTransferSetupModal opens with the TabaPay iframe
→ supplier enters card details inside the iframe
→ iframe posts a TabapayIframeEvent
success → updatePaymentConfigs(configs) → dispatch loadPaymentMethodsSuccess
→ InstantTransferSetupSuccessModal
→ optional makePaymentMethodAsDefault(paymentConfigKey)
→ dispatch fetchDashboardNotifications()
→ onSetupFinish.next('done')
error → openFailureModal(errorData, businessInformation)
The TabaPay iframe
views/partials/content/tabapay-iframe/ hosts the embedded form and translates
its postMessage traffic into typed events:
|
|
|
Carries the updated |
|
Carries |
The iframe origin comes from environment.tabapayUrl.
On success the service takes the returned configs and pushes them straight into the store, bypassing a refetch:
updatePaymentConfigs(configs: PaymentMethodModel[]): void {
this.store.dispatch(loadPaymentMethodsSuccess({ paymentMethods: configs }));
}
Error handling
openFailureModal() maps TabaPay’s error taxonomy onto specific, actionable
dialogs — each of which offers a "Try again" button that reopens the setup modal.
TabapayErrorCode |
TabapayErrorReason |
Modal |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
— |
|
|
|
|
|
|
|
|
anything else |
|
anything else |
— |
|
All configurations are built in instant-transfer.config.ts from a shared
baseConfig that supplies a Close button, a Try-again button wired to
openInstantTransferSetupModal, and a danger-coloured exclamation icon. Every
message interpolates supportEmail and supportPhone from
constants/contact.const.ts.
|
The address error modal interpolates the supplier’s business address from the
|
Fees
getFeesData(transferAmount: number): Observable<InstantTransferFeesData> {
return this.feesScheduleHelperService.getInstantTransferFees().pipe(
map(fees => this.feesScheduleHelperService.crateInstantTransferFeesData(transferAmount, fees)),
);
}
isFreeAccessEnabled(): Observable<boolean> {
return this.feesScheduleHelperService.hasFreeAccessPaymentFee();
}
FeesScheduleHelperService reads the fees slice, which is populated once by
fetchFees() from GlobalSubscriptionsService.init().
hasFreeAccessPaymentFee() also drives the success modal’s freeTrialAvailable
flag — suppliers without a free-access fee are told a free trial is available.
Default payout method
The success modal offers to make Instant Transfer the default:
if (res.setAsDefaultMethod) {
this.setInstantTransferAsDefaultMethod(instantTransferMethod.paymentConfigKey);
}
which dispatches makePaymentMethodAsDefault({ paymentConfigKey }) against the
paymentMethods slice. The relevant method is located by
configs.find(m ⇒ m.paymentType === PaymentMethodType.InstantTransfer).
UI surface
|
Dashboard CTA. |
|
|
|
Fee and limit details. |
|
The transfer request itself. |
|
Offer presentation during onboarding. |