VRPlatformVRPlatform
Build a Product UI

Bank Accounts and Connections

Connect Plaid, map feeds to GL accounts, and recover configuration

Last Updated: 2026-09-03

Version: 1.2

A bank Account is the GL posting target. An AccountConnection is an optional external identity discovered through Plaid or another provider. Connecting a feed never creates a second accounting account.

Account And Feed Model

account.banking.connections[] contains the linked AccountConnections. The outer item id is the accountConnectionId; its nested connection.id is the provider Connection ID.

Bank Accounts distinguish trust, operating, and external categories plus deposit and credit-card behavior. Respect the category, assignments, categoryLock, capabilities, and issues[] returned by the API.

Bank Fees and Interest Income are ordinary ledger accounts. Add them to the published global or partner ledger template when they should be present in a new team's chart. Use a BankRule when one team wants a repeatable interest mapping. The rule must explicitly select the intended account and party; VRPlatform has no global beneficiary default because the legal recipient depends on the team and jurisdiction.

Connect Plaid

Plaid configuration is one three-step session:

StepRequestResult
StartPOST /plaid/connectconnectId and Link token
Complete LinkPOST /plaid/connect/completeComplete configuration read model
Confirm mappingPOST /plaid/connect/configureAccount decisions and one initial sync

The connectId owns idempotency, selected environment, recovery, and final configuration. Do not create a second session while completion is still retryable.

An embedded product can receive embed:banking:v1. That bundle grants only the three Plaid connect requests above. It does not grant general Account, BankRecord, Transaction, report, or team-administration access. The embedded session remains bound to its team, partner, allowed origin, expiry, and revocation state. Use /banking as the embedded view path.

Plaid credentials, public and access tokens, Item IDs, Link session IDs, and provider payloads never appear in public audit events. Reviewed connection, account-connection, and account configuration changes can appear in the Activity Log.

Choose The Session Mode

ModeUseConnection ID
createAdd a new Plaid ItemOmit
updateRepair an existing Item with reusable credentialsRequire
replaceReplace credentials with a new ItemRequire

The optional environment is sandbox or production and defaults to production. Completion and configuration reuse the session's environment and do not accept it again.

New and replacement Items request Plaid Transactions only. Plaid Auth is not part of reconciliation and would exclude credit-card accounts. Update mode retains the existing Item's products.

Hostaway-region sessions use the hostaway Plaid customization, United States country scope, and the Hostaway client name for create, update, and replace.

Render Completion Directly

The completion response is the configuration screen model:

  • accounts contains eligible existing GL bank accounts;
  • bankAccountCategories contains available classifications; and
  • bankAccounts[] contains status, suggestions, capabilities, and typed issues for every discovered feed.

Do not fetch /accounts again or poll AccountConnections for discovery. Submit one connect or archive decision for every row whose configuration status is required. Optional opening balances use { date, centAmount }.

The final configuration executes all decisions sequentially in one transaction. A conflict rolls back every mapping. After commit, the API creates one durable initial sync.

Identity And Replacement Safety

A four-digit banking suffix is unique among a team's GL bank accounts. A feed and its linked Account may share the suffix because they represent the same bank account.

Plaid sandbox institutions reuse test masks. Sandbox sessions therefore do not use last four digits for suggestions or duplicate checks and do not copy the mask onto a GL Account. Provider identity checks still apply.

When replacement identity matches several historical feeds, the API does not guess. It returns the feed as unlinked and keeps eligible GL Accounts available for an explicit decision. A confirmed replacement can archive inactive predecessors but cannot displace an active feed. Historical BankRecords stay on the same GL Account.

Plaid credit feeds default to credit-card behavior. Relay Financial names that end in Credit Account receive the same classification when Plaid reports a checking or depository type.

Import Bank Activity

Plaid and provider feeds retain their source and AccountConnection identity. CSV imports use the canonical accountId; their accountConnectionId is null. See Import Data from CSV.

Records earlier than a feed's configured start date are stored as inactive history. This is an expected exclusion, not a failed sync or reconnect signal.

When a feed resumes after a CSV stopgap import, the API warns if a new record has the same account, date, and exact amount as an active record from the other source. Those fields are not a unique identity, so neither record is merged or skipped. Let a manager review the warning.

Account And Feed Decisions

DecisionBehavior
Immutable account categoryDisable the selector
Initialize bankingWrite account state, opening Transaction, and feed checkpoint atomically
Credit-card opening balanceNegative feed checkpoint and positive opening Transaction line
Delete a protected AccountRespect the lock or use onLocked=archive when offered
Attach over an active feedonConflict=error, replace, or replace-and-detach-history
Detach a feedPreserve history by default; detach unreconciled history only when requested
Unselected Plaid feedSubmit action=archive

An Account referenced by a BankRule selector or posting line cannot be hard deleted; use onLocked=archive to preserve the rule. An active recurring fee that uses an Account as a direct posting account, tax posting account, or formula input blocks deletion and archive. Repoint or deactivate the fee first.

Banking initialization can create its opening-balance Transaction before the team has selected statementStartAt. Ordinary Transactions remain unavailable until accounting start is configured.

ACH Readiness

Account and AccountConnection reads expose capabilities.achPayments = { enabled, disabledReasons }. Use only an AccountConnection whose capability is enabled; a Ramp Connection does not make every embedded account eligible.

Ramp funding requires an active deposit AccountConnection with its provider account ID in uniqueRef. The replacement-stable persistentRef is not a funding requirement. Payment execution also checks that the linked source has one Ramp entity and bank-account ID and that the provider account matches the AccountConnection.

Contact reads expose only masked ACH state: provider, connection, last four, status, failure reason, and hasInFlightPayment. Full routing and account numbers are write-only through POST /contacts/{id}/payment-methods/ach and are never stored by VRPlatform.

Do not send a client-selected connectionId for ACH setup. The API resolves the single eligible Ramp flow. The first setup activates an unconfigured flow; an explicitly inactive, missing, or ambiguous setup remains blocked.

Ramp vendor creation requires contact email and country, plus state for a United States vendor. Phone and address are optional. When the contact has no location, the integration uses the connected Ramp business billing address. The pushRampVendors flow must select an active Ramp user as Vendor owner. ACH setup returns HTTP 422 before it queues verification when that setting is missing or no longer resolves to an active user on the same Ramp connection. The error code is RAMP_VENDOR_OWNER_REQUIRED; its context returns the flow, connection, and vendorOwner setting key so clients can open the existing connection setting.

An existing ownerless vendor cannot inherit a different vendor's owner or use the connection default retroactively. Contact ACH state returns status=failed with instructions in failureReason; send the user to that vendor in Ramp to assign an owner before ACH becomes ready.

Statement payout preview treats an unconfigured transfersToBills flow as eligible without activating it. The first otherwise-valid payout activates the flow. A dry run rolls that activation back, and an explicitly inactive flow remains unavailable.

An in-flight payout stays on the bank account selected when it was scheduled. Keep bank editing available, but explain that the change affects future payments only.

Plaid Recovery

ErrorClient action
PLAID_PROVIDER_UNAVAILABLERetry the same action and connectId
PLAID_CONNECT_IN_PROGRESSRetry the same completion; do not start another session
CONNECTION_RECONNECT_REQUIREDRun the existing Item's reconnect flow
PLAID_CONNECT_REQUIRES_NEW_LINKFollow context.restartMode and its Connection ID exactly
PLAID_CONNECT_CONFIGURATION_CHANGEDReplace the screen with context.result and reconfirm

Plaid Link error INVALID_UPDATED_USERNAME means update mode cannot repair the Item. Start a new replace session for the same Connection.

Do not infer create or replace mode from local state. Use the server-owned recovery directive. Display the stable top-level error and use allowlisted provider fields only for diagnostics.

API Reference

On this page