financial_accounts scenario pairs a login with the accounts you want back, each with balances, owners, transactions, investment holdings, statements, and recurring deposits, and serves them when the user signs in to a Truv test bank with that login. It drives Verification of Assets, cashflow transactions, and the bank-income flows.
Use it when the built-in assets credentials don’t cover the case you need: a specific balance, a direct deposit cadence your income engine has to recognize, an investment account, or a bank statement PDF with your own numbers. For the shared concepts, read Custom Sandbox Data first.
Create a scenario [Server-side]
This request creates a scenario with one checking account that receives a biweekly paycheck:Always send
"data_source": "financial_accounts". username and password are supported on payroll, financial accounts, and insurance, so Truv can’t infer the data source from them and refuses the request with data_source_required.Use it in Bridge
Start a sandbox verification withproduct_type: assets or transactions. In Truv Bridge, search for Truv Bank non-OAuth and sign in with acme.checking / s4ndb0x, or pick Truv Bank OAuth and enter the same login on the sandbox bank page it opens. The OAuth page then lists the scenario’s accounts for the user to select, the way a real OAuth bank does. The task completes with your accounts instead of Truv’s built-in test data. Read the result from the task webhooks, the assets report, and the transactions endpoint.
The scenario above sets no provider_id, so either test bank works. A scenario that sets provider_id: "truv_bank" answers only connections through that provider.
Matching fields
products restricts the scenario to a subset of assets, transactions, income, and employment. Empty, the default, matches every product.
Behavior
A financial accounts scenario accepts everybehavior_status, and each ends the task with that status except not_supported, which ends it with unavailable. behavior_mfa is replayed at login, and a response that doesn’t match a challenge’s answer or answers ends the task with mfa_error. See Behavior for the fields. A scenario with a failure status still shows up on the OAuth sandbox page, with nothing to select, so the task can end the way the scenario says.
How accounts are served
Truv builds the accounts fresh on every run, so the same scenario stays current without edits:- Ids are stable. Each account, owner, and holding gets an id derived from its position in the payload, so a refresh updates the records a previous run created instead of adding a second set. A transaction or statement keeps the
external_idyou give it. maskdefaults to the last four digits ofaccount_number.external_updated_atis the as-of time for balances and the end of everyrecurringseries. It defaults to the time of the run, which is what keeps a deposit history current.- Recurring series expand into transactions. See Recurring deposits.
- Incomplete records are dropped, not failed. A transaction with no
amountor no date, a statement with no library entry, and an amount outside the supported amount range are left out; the rest of the scenario is still served. typeandstatushave defaults. A transaction with notypeisDEBITwhen its amount is negative andCREDITotherwise. One with nostatusisPOSTED.transacted_atdefaults toposted_at.
Recurring deposits
Eachrecurring rule generates CREDIT transactions after start, through external_updated_at. A date on start itself is never generated. The amounts repeat in order.
The dates follow a fixed calendar schedule for each pay_frequency. They don’t count from start:
A
BW series with start: "2026-02-20", a Friday, has its first deposit on Monday 2026-03-02.
Transactions are served newest first. Authored and generated transactions share one per-account limit, and the most recent ones are kept.
Payload reference
Thepayload object contains an accounts array. Every field is optional unless noted: send only what your test needs, and leave the rest out.
accounts[]
accounts[]
accounts[].owners[]
accounts[].owners[]
accounts[].transactions[]
accounts[].transactions[]
accounts[].holdings[]
accounts[].holdings[]
accounts[].statements[]
accounts[].statements[]
accounts[].recurring[]
accounts[].recurring[]
Money and quantities are decimal strings, so nothing is lost to floating point:
"5231.44", not 5231.44.Examples
Each example is a request body forPOST /v1/sandbox/scenarios/ and creates a new scenario. Send it with the same curl command as the first scenario.
Two paychecks and rent
Add two deposit series on one account to give the bank income engine two employers to find, and a monthly rent debit alongside them. The amounts on the second series alternate, so every other deposit is larger.Savings and an investment account
Add more accounts to theaccounts array. Up to 10 fit in one scenario. An INVESTMENT account carries holdings.
Failing login
A failure status needs no payload. Use it to exercise the error paths in your integration.MFA challenge
behavior_mfa.challenges replays one screen per entry, in order, on both test banks. Any code other than answer ends the task with mfa_error.
Refresh-only data
Restrict a scenario to refreshes withis_refresh: true to set the data a data refresh should find. Create it alongside the acme.checking scenario with the same login; on a refresh it wins, because it sets is_refresh and the other doesn’t.
Attach statement PDFs
Each statement references an uploaded PDF bydocument_id, the id of a document library entry. Upload the PDF once, then reference its id.
id as the statement’s document_id.
id on the statement. Abbreviated: the account carries whatever other data your test needs.
Limits
These are the default limits for financial accounts payloads. The account-wide limits are listed on Custom Sandbox Data.Next steps
Assets Testing
Truv’s built-in bank credentials and sample reports
Payroll scenarios
Pair the same user with a payroll login
Data refresh
How refreshes reach your
is_refresh scenariosSandbox API reference
Full request and response schemas for every sandbox endpoint