Skip to main content
Mode: balance_transfer
Opal Balance Transfer lets a borrower direct the proceeds of an approved loan to the liability accounts they want to pay down. This pre-built flow verifies the user’s identity, connects their liability accounts, collects any account numbers needed to make those accounts payable, and asks the user how much of the loan to send to each account. When the user confirms, your backend releases the payments.

What this mode does

Use this mode after your team has approved a loan, such as a debt consolidation or balance transfer loan, and knows the approved amount. You pass the approved loan terms when you create the token, and Opal guides the user through the following steps:
1

Identity verification

Opal verifies the user’s identity. This step is skipped automatically if the Entity is already verified.
2

Account selection

Opal shows the user’s liability accounts with their current balances. Only accounts that can receive a payment today, or that can become payable once the user provides the account number, are selectable.
3

Account verification

For each selected account that cannot receive payments yet, the user enters the account number. Accounts that are already payable skip this step. Accounts that still cannot receive payments after verification are removed from the allocation step.
4

Amount allocation

Opal prefills an amount for each account, starting with the highest balances, and shows how much of the loan remains to allocate. The user can edit or remove any amount, then confirms.
5

Release

Confirming does not move money. The session waits in pending_release until your backend calls Release Payments. Method then creates one payment per allocated account.

Before you start

  • Enable the mode. Balance Transfer must be enabled for your team. Until it is, token creation with mode: "balance_transfer" fails with INVALID_MODE. Contact your CSM to enable access to this mode.
  • Choose a source account. Payments are funded from a source account that your team can send payments from. Pass it when you release payments, or ask your CSM to configure a default source account for your team.
  • Confirm the payment description. Released payments use a description configured for your team. Contact your CSM to set or change it.

Parameters

All monetary values are in cents.

Allocation rules

Method validates every amount the user enters. Each allocation must be:
  • At least minimum_payment.
  • No more than the smallest of maximum_payment, the account’s current balance, and the portion of loan_amount not yet allocated to other accounts.
When the user confirms, Method also checks that:
  • At least one account has an allocation.
  • The total allocated does not exceed loan_amount.
  • If residual_amount_max is set, the unallocated amount (loan_amount minus the total allocated) does not exceed residual_amount_max.
  • Every allocated account can still receive a payment.
Opal enforces the same rules in its interface, so the user cannot confirm until every rule is met. Any unallocated amount stays with your team, and Opal tells the user that your team handles it.
Choose residual_amount_max based on how you plan to disburse leftover funds. Use 0 if the full loan must go to the user’s liability accounts. Omit it if you disburse any remainder to the borrower another way, such as a deposit to their bank account.

Create a token

You can create a balance transfer token using one of the supported patterns:
  • Existing entity: provide entity_id + mode + balance_transfer
  • Create new entity: provide entity + mode + balance_transfer
  • Resume session: provide session_id only (omit mode and balance_transfer)

Existing Entity

Create New Entity

Response

Store the session_id. You need it to check the session status and release payments.

Launch Opal

Events

In addition to the default session events and the identity, connect, and account verification events, this mode emits the following events. Match them on event.type.
If none of the selected accounts can receive payments after verification, Opal shows an empty state and the session ends with opal.session.exited.
Use events to update your interface, not to authorize money movement. Before you release payments, retrieve the session from your backend and confirm that bt.payout_status is pending_release.
For the full list of events, see Opal Events.

Check the session status

Retrieve the session with your secret API key to read the confirmed allocations and payout status.
The bt object on the session tracks the balance transfer:
See Retrieve Session for the full response.

Release payments

When your team is ready to fund the transfer, for example after the loan proceeds are available in your source account, release the payments.
Method creates one Payment per allocated account, from the source account to that liability account, for the allocated amount. Releasing payments behaves as follows:
  • Validation happens first. Method re-checks the allocations, the source account, and every destination account before any money moves. If a check fails, the request returns an error, the session stays in pending_release, and you can retry after resolving the issue.
  • Releasing is idempotent. Calling release again on a released session returns the session unchanged and creates no new payments.
  • Each payment is independent. If Method cannot create the payment for one account, that account’s entry in payment_ids is null and the other payments still go out. A released session cannot be released again, so handle any null entry separately, for example by creating a payment with the Payments API or by contacting your CSM.
Track each payment with the Payments API or the payment.create and payment.update webhooks. See Release Payments for the full request and response.

Resuming a session

If the user exits before confirming, create a new token with the session_id to resume. Opal keeps the user’s progress through identity verification, account selection, and account verification. Amounts are saved only when the user confirms, so Opal prefills them again when the user returns to the allocation step.

Errors

Errors use the INVALID_REQUEST type with one of the following sub types. An invalid source account returns the same errors as Create a Payment.