# Retrieve an employment history report for a link Source: https://docs.truv.com/api-reference/account-link-income-and-employment-reports/link_detail_reports_employment GET /v1/links/{link_id}/employment/report/ The endpoint returns the VOE report for a link # Retrieve an income and employment report for a link Source: https://docs.truv.com/api-reference/account-link-income-and-employment-reports/link_detail_reports_income GET /v1/links/{link_id}/income/report/ The endpoint returns the VOIE report for a link # The Link Income & Employment Reports object Source: https://docs.truv.com/api-reference/account-link-income-and-employment-reports/object Account link-level income and employment verification reports for individual account connections. Account Link Reports return income and employment data for a single account link (connection to a payroll provider). For aggregated reports across all of a user's account links, see [User Income and Employment Reports](/api-reference/user-income-and-employment-reports/object). # Attributes The table below covers information from the report response. | Attribute | Type | Description | | :-------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique identifier | | status | string | Status from [Connection Lifecycle](/api-reference/tasks/lifecycle) | | finished\_at | string | Time when report was finished | | completed\_at | string | ~~Time when report was completed~~ **(Deprecated, invalid datetime format)** | | access\_token | string, null | Access token for Link to payroll provider | | tracking\_info | string | Information passed to Truv Bridge from partner | | is\_suspicious | boolean | Flag indicating the data from the source is suspicious (e.g. fraud detected in uploaded documents or the user's SSN does not match the data) | | refresh\_status | string | Status of most recent refresh task | | employments | array of objects | List of employments, see [Employments object](#employments-object) | | pdf\_report | uri, null | Verification report in PDF format | | provider | string | Payroll provider name | | data\_source | string | Source of data: `payroll` - Payroll provider parsing, `docs` - User-uploaded documents, `financial_accounts` - Data from linked financial accounts | ## Employments object The Employments object contains the values and descriptions below. | Attribute | Type | Description | | :---------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | income | string | Income amount not including commission or bonuses, only for income product. Null for employment product | | income\_unit | string | Pay interval for income field, only for income product: `YEARLY` - Annual income, `MONTHLY` - Monthly income, `WEEKLY` - Weekly income, `DAILY` - Daily income, `HOURLY` - Hourly income. Null for employment product | | pay\_rate | string | Payment rate per pay cycle, only for income product. Null for employment product | | pay\_frequency | string | Pay frequency, only for income product: `M` - Monthly, `SM` - Semi-Monthly, `W` - Weekly, `BW` - Bi-Weekly, `A` - Annually, `SA` - Semiannually, `C` - Commission. Null for employment product | | statements | array of objects | List of Paystubs received from a payroll provider, only for income product, see [Statements object](#statements-object). Null for employment product | | annual\_income\_summary | array of objects | Annual income summary by years, only for income product, see [Annual income summary object](#annual-income-summary-object). Null for employment product | | bank\_accounts | array of objects | List of bank accounts linked to employment, only for income product, see [Bank accounts object](#bank-accounts-object). Null for employment product | | w2s | array of objects | List of W-2 forms linked to employment, only for income product, see [W2s object](#w2s-object). Null for employment product | | id | string | Unique ID | | is\_active | boolean | Status of active employment | | job\_title | string | Employee's job title | | job\_type | string | Employee's job type: `F` - Full Time, `P` - Part Time, `S` - Seasonal, `D` - Daily (per diem), `C` - Contract, `V` - Volunteer | | start\_date | date | Employee's hire date | | original\_hire\_date | date | Original hire date | | end\_date | date | Employee's end date | | external\_last\_updated | date | Indicates date of last updated employment data from Payroll Provider | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | | manager\_name | string, null | Supervisor's name | | profile | object | Person's identity information | | company | object | [Company object](#company-object) | | gse\_accepted | boolean | Status of provider eligibility from Fannie Mae Desktop Underwriter | ### Company object This table covers values within the company object. | Attribute | Type | Description | | :-------- | :----- | :-------------------------------- | | name | string | Company name | | address | object | [Address object](#address-object) | | phone | string | Company phone number | | ein | string | Employer Identification Number | #### Address object The values in this table are for the address object of the company. | Attribute | Type | Description | | :-------- | :----- | :---------- | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip | | country | string | Country | ### Statements object View the table below for information from the Statements object. | Attribute | Type | Description | | :-------------------- | :--------------- | :--------------------------------------------------------------------------------- | | id | string | Unique ID | | check\_number | string | External ID of pay stub from payroll provider | | pay\_date | date | Pay date | | net\_pay | string | Net pay | | net\_pay\_ytd | string | Net pay year to date | | gross\_pay | string | Gross pay | | gross\_pay\_ytd | string | Gross pay year to date | | bonus | string | Bonus | | commission | string | Commission | | hours | string | Work hours during pay period | | basis\_of\_pay | string | Basis of pay: `S` - Salary, `H` - Hourly, `D` - Daily, `W` - Weekly, `M` - Monthly | | period\_start | date | Period start | | period\_end | date | Period end | | regular | string | Regular pay | | regular\_ytd | string | Regular salary year to date | | other\_pay\_ytd | string | All other payment year to date | | bonus\_ytd | string | Bonus year to date | | commission\_ytd | string | Commission year to date | | overtime | string | Overtime pay | | overtime\_ytd | string | Overtime pay year to date | | other\_pay | string | All other payment | | earnings | array of objects | Earnings for this pay cycle by type | | earnings\_ytd | array of objects | Earnings year to date by type | | deductions | array of objects | Deductions for pay cycle by type | | deductions\_ytd | array of objects | Deductions year to date by type | | md5sum | string | MD5 hash value computed based on file content | | file | uri | Link to pay stub file, format is specified in the content-type | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | ### Annual income summary object Find information for the attributes and values of the annual income summary object. | Attribute | Type | Description | | :--------- | :------ | :---------------------- | | id | string | Unique ID | | year | integer | Income report year | | regular | string | Regular salary | | bonus | string | Bonus | | commission | string | Commission | | overtime | string | Overtime pay | | other\_pay | string | All other payment forms | | net\_pay | string | Net pay | | gross\_pay | string | Gross pay | ### Bank accounts object The table below covers the attributes within the bank accounts object. | Attribute | Type | Description | | :-------------- | :----- | :---------------------------------------------------------------------------------------------------------- | | account\_number | string | Account number | | routing\_number | string | Routing number | | account\_name | string | User friendly account name | | account\_type | string | Account type: `C` - Checking account, `S` - Savings account | | deposit\_type | string | Deposit type: `E` - Entire paycheck, `P` - Percentage of the paycheck, `A` - Fixed amount from the paycheck | | deposit\_value | string | Deposit value | | bank\_name | string | Bank name | ### W2s object The values in this table are for the W-2s object field. | Attribute | Type | Description | | :---------------------- | :------ | :-------------------------------------------------------------- | | file | uri | Link to W2 report file, format is specified in the content-type | | md5sum | string | MD5 hash value computed based on file content | | year | integer | Year | | wages | string | Wages, tips, other compensation (Section 1) | | federal\_tax | string | Federal income tax withheld (Section 2) | | social\_security\_wages | string | Social security wages (Section 3) | | social\_security\_tax | string | Social security tax withheld (Section 4) | | medicare\_wages | string | Medicare wages (Section 5) | | medicare\_tax | string | Medicare tax withheld (Section 6) | | gross\_pay | string | Gross pay | *** ## Earnings object The `earnings` or `earnings_ytd` field is an array that contains all earnings. Below is an example of the earnings object with the supported categories: `regular`, `bonus`, `commission`, `overtime`, `other_pay`. ```json theme={null} [ { "name": "Regular", "amount": "38072.0", "category": "regular", "rate": "475.9", "units": "80" }, { "name": "Bonus", "amount": "10000.0", "category": "bonus", "rate": null, "units": null } ] ``` *** ## Deductions object The `deductions` or `deductions_ytd` field is an array that contains all deductions. Below is an example of the deductions object. The supported categories are the following: `memo`, `medicare`, `retirement`, `benefit`, `socialsec`, `federal`, `state`, `garnishment`, `local`, `other`. ```json theme={null} [ { "amount": "127.01", "category": "socialsec", "name": "Social Security Tax" }, { "amount": "46.23", "category": "state", "name": "VA State Income Tax" }, { "amount": "29.7", "category": "medicare", "name": "Medicare Tax" } ] ``` # Endpoints Use the endpoints below to retrieve link-level reports. * [Retrieve an employment history report for an account link](/api-reference/account-link-income-and-employment-reports/link_detail_reports_employment) * [Retrieve an income and employment report for an account link](/api-reference/account-link-income-and-employment-reports/link_detail_reports_income) # Example response The sample below is a JSON response for the endpoint. ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "new", "finished_at": "2021-04-06T11:30:00Z", "completed_at": "2021-04-06 11:30:00+00:00", "access_token": "48427a36d43c4d5aa6324bc06c692456", "tracking_info": "user123456", "refresh_status": "new", "employments": [ { "income": "70000.00", "income_unit": "YEARLY", "pay_rate": "6500.00", "pay_frequency": "M", "statements": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "check_number": "29205182", "pay_date": "2018-05-15", "net_pay": "11500.32", "net_pay_ytd": "31980.64", "gross_pay": "13900.11", "gross_pay_ytd": "49200.00", "bonus": "100.00", "commission": "12000.00", "hours": "40.00", "basis_of_pay": "S", "period_start": "2018-05-01", "period_end": "2018-05-15", "regular": "1695.11", "regular_ytd": "23000.00", "other_pay_ytd": "700.00", "bonus_ytd": "1000.00", "commission_ytd": "24000.00", "overtime": "45.00", "overtime_ytd": "500.00", "other_pay": "60.00", "earnings": [ { "name": "Regular", "amount": "1935.77", "category": "regular", "rate": null, "units": null }, { "name": "Overtime", "amount": "60.58", "category": "overtime", "rate": "30.29", "units": "2" } ], "earnings_ytd": [ { "name": "Regular", "amount": "1935.77", "category": "regular", "rate": null, "units": null }, { "name": "Overtime", "amount": "60.58", "category": "overtime", "rate": "30.29", "units": "2" } ], "deductions": [ { "amount": "127.01", "category": "socialsec", "name": "Social Security Tax" }, { "amount": "46.23", "category": "state", "name": "VA State Income Tax" }, { "amount": "29.7", "category": "medicare", "name": "Medicare Tax" } ], "deductions_ytd": [ { "amount": "127.01", "category": "socialsec", "name": "Social Security Tax" }, { "amount": "46.23", "category": "state", "name": "VA State Income Tax" }, { "amount": "29.7", "category": "medicare", "name": "Medicare Tax" } ], "md5sum": "03639d6a6624f69a54a88ea90bd25e9d", "file": "https://citadelid-resources.s3-us-west-2.amazonaws.com/paystub_sample.pdf", "derived_fields": [ "basis_of_pay" ], "missing_data_fields": [ "earnings_ytd" ] } ], "annual_income_summary": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "year": 2018, "regular": "23000.00", "bonus": "1000.00", "commission": "24000.00", "overtime": "500.00", "other_pay": "700.00", "net_pay": "31980.64", "gross_pay": "49200.00" } ], "bank_accounts": [ { "account_number": "1234567890", "routing_number": "123456789", "account_name": "My Bank", "account_type": "C", "deposit_type": "A", "deposit_value": "200.00", "bank_name": "TD Bank" } ], "w2s": [ { "file": "https://citadelid-resources.s3-us-west-2.amazonaws.com/W2_sample.pdf", "md5sum": "f65e30c39124ad707ac4b3aeaee923a7", "year": 2020, "wages": "900.50", "federal_tax": "75.01", "social_security_wages": "900.50", "social_security_tax": "56.30", "medicare_wages": "900.50", "medicare_tax": "13.15", "gross_pay": "18211.48" } ], "id": "24d7e80942ce4ad58a93f70ce4115f5c", "is_active": false, "job_title": "PR associate", "job_type": "F", "start_date": "2018-01-01", "original_hire_date": "2017-06-21", "end_date": "2023-04-29", "external_last_updated": "2023-04-29", "dates_from_statements": false, "derived_fields": [ "is_active" ], "missing_data_fields": [ "w2s" ], "manager_name": "Jenny McDouglas", "profile": { "id": "48427a36d43c4d5aa6324bc06c692456", "created_at": "2022-06-07T15:00:00Z", "updated_at": "2022-06-31T15:00:00Z", "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "middle_initials": "K", "email": "john.doe@example.com", "ssn": "123456789", "date_of_birth": "1992-03-03", "home_address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" } }, "company": { "name": "Facebook Demo", "address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" }, "phone": "6503087300", "ein": "12-345678" } } ], "pdf_report": "https://citadelid-resources.s3-us-west-2.amazonaws.com/report.pdf", "provider": "adp", "data_source": "payroll" } ``` # Retrieve auth data Source: https://docs.truv.com/api-reference/auth/bank-auth-get GET /v1/links/{link_id}/auth/ The endpoint retrieves a list of connected financial accounts, including their bank identification numbers. # The Auth object Source: https://docs.truv.com/api-reference/auth/object Account and routing numbers for ACH, RTP, and wire transfers from connected financial accounts. Each auth response includes the standard account fields plus the `numbers` object, both documented below. The Auth endpoint returns account and routing numbers for a user's connected financial accounts. Use this data for ACH transfers, wire transfers, and account verification. # Attributes The auth response returns an `accounts` array. Each account includes the fields below plus a `numbers` object with account and routing numbers grouped by network type. ## Account object | Attribute | Type | Description | | :-------------- | :----------- | :----------------------------------------------------------------------------------------- | | `id` | string | Unique ID | | `created_at` | date-time | Timestamp when the account was created in Truv | | `updated_at` | date-time | Timestamp when the account was updated in Truv | | `type` | string, null | The account's type | | `subtype` | string, null | The account's subtype | | `mask` | string | Last 4 digits of account number | | `nickname` | string, null | User-defined name for the account | | `is_open` | boolean | Indicates whether the account is currently open | | `balances` | object | Balance information, see [Balances object](/api-reference/balances/object#balances-object) | | `provider` | string | Data provider ID | | `provider_name` | string | Data provider name | | `numbers` | object | Account and routing numbers grouped by network type, see [Numbers object](#numbers-object) | ## Numbers object Each key (`ACH`, `RTP`, `OTHERS`) contains an array of number objects. | Attribute | Type | Description | | :---------------------------- | :------ | :-------------------------------------------------------------------------- | | `account_number` | string | Unique identifier assigned to the financial account | | `routing_number` | string | Unique identifier for the financial institution, used to route transactions | | `is_tokenized_account_number` | boolean | Whether the account number has been tokenized by the institution | # Endpoints * [Retrieve auth data](/api-reference/auth/bank-auth-get) # Example response ```json theme={null} { "accounts": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z", "type": "CHECKING", "subtype": "MONEY_MARKET", "mask": "6789", "nickname": "My account", "is_open": true, "balances": { "currency_code": "USD", "balance": "100.00", "available_balance": "50.99", "credit_limit": "200.00" }, "provider": "truv", "provider_name": "Truv Bank", "numbers": { "ACH": [ { "account_number": "16002600", "routing_number": "123456789", "is_tokenized_account_number": true } ], "RTP": [ { "account_number": "16002600", "routing_number": "123456789", "is_tokenized_account_number": true } ], "OTHERS": [ { "account_number": "16002600", "routing_number": "123456789", "is_tokenized_account_number": true } ] } } ] } ``` # Authentication Source: https://docs.truv.com/api-reference/authentication How to authenticate with the Truv API ## Base URL All API requests use the same base URL regardless of environment: ``` https://prod.truv.com/v1/ ``` Your **Access Secret** determines which environment the request is routed to, not the URL. Sandbox and Production both use the same endpoint. *** ## API Authentication All Truv API requests require authentication using your **Client ID** and **Secret**. ### Get your credentials 1. Log in to [dashboard.truv.com](https://dashboard.truv.com) 2. Navigate to **Development** → **API Keys** 3. Copy your credentials **Keep your API Secret secure!** * Never expose your secret in client-side code * Don't commit credentials to version control * Use environment variables in production **Protect each Link's `access_token`** The `access_token` returned when a user connects a provider grants ongoing access to that user's data. Keep it on your backend, never in client-side code, and associate it with the user in your system. See [Bridge token best practices](/developers/best-practices/bridge-token). *** ## Authentication headers Include these headers in every API request: ```bash theme={null} X-Access-Client-Id: your_client_id X-Access-Secret: your_api_secret ``` ### Example Request ```bash theme={null} curl -X GET https://prod.truv.com/v1/users/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" ``` *** ## Environments | Environment | Base URL | Purpose | | -------------- | --------------------------- | ----------------------------------------- | | **Sandbox** | `https://prod.truv.com/v1/` | Testing with predefined sample data | | **Production** | `https://prod.truv.com/v1/` | Live data, each successful task is billed | Your Access Secret prefix determines the environment: | Prefix | Environment | Example | | ---------- | ----------- | -------------------------------------------------- | | `sandbox-` | Sandbox | `sandbox-a57b3109f1f4a8b3f2ebbc1c526950f1795464af` | | `prod-` | Production | `prod-e82c4f19d3a7b6e5f0c8d2a1b4e7f3a6d9c2b5e8` | Sandbox and production use the same base URL. Your Access Secret prefix determines which environment the request is routed to. *** ## API Key Rotation Rotate your API keys periodically or whenever credentials may have been compromised. ### Dashboard-Only Integrations If you create [Orders](/developers/integration/hosted-orders/new-user) exclusively through the Dashboard: 1. Create a new key in the [Truv Dashboard API Keys page](https://dashboard.truv.com/app/development/keys) 2. Delete the old key. Pending transactions with the original key continue to process ### API Integrations For embedded solutions or Orders created via the API: Generate a new key in the Truv Dashboard. Create a sandbox key first to test before updating production. Search your code for the `X-Access-Secret` header and replace the old key everywhere. Remove outdated keys to reduce risk. Pending transactions with the original key continue to process. Deleting keys cannot be undone. Confirm the new key is working before deleting the old one. *** ## Security For webhook verification and data protection guidelines, see the [Security](/api-reference/security) section. *** ## Next steps Understand orders, links, tasks, and the Truv data model Data protection, encryption, and compliance guidelines # List all balances Source: https://docs.truv.com/api-reference/balances/balances-list GET /v1/links/{link_id}/balances/ The endpoint allows developers to receive balances. # The Balances object Source: https://docs.truv.com/api-reference/balances/object Current balance data for connected financial accounts. Each balance belongs to an account. The balance fields appear within the `balances` object on each account. The Balances endpoint returns current balance information for all accounts associated with a link. # Attributes The balances endpoint returns a paginated list of accounts, each with a nested `balances` object. | Attribute | Type | Description | | :--------- | :--------------- | :------------------------------------------------------ | | `count` | integer | Total number of accounts | | `next` | uri | URL of the next page of results, `null` if none | | `previous` | uri | URL of the previous page of results, `null` if none | | `results` | array of objects | List of accounts, see [Account object](#account-object) | ## Account object | Attribute | Type | Description | | :----------- | :-------- | :----------------------------------------------------------- | | `id` | string | Unique ID | | `created_at` | date-time | Timestamp when the account was created in Truv | | `updated_at` | date-time | Timestamp when the account was updated in Truv | | `type` | string | The account's type | | `subtype` | string | The account's subtype | | `mask` | string | Last 4 digits of account number | | `nickname` | string | Description of account | | `balances` | object | Balance information, see [Balances object](#balances-object) | ## Balances object | Attribute | Type | Description | | :------------------ | :----- | :--------------------------------------------------------------------------------- | | `currency_code` | string | Three-character ISO 4217 currency code (e.g., `USD`) | | `balance` | string | Current account balance (nullable) | | `available_balance` | string | Available balance for use. `PENDING` transactions may not be reflected. (nullable) | | `credit_limit` | string | Credit limit, `null` for non-credit accounts (nullable) | # Endpoints * [List all balances](/api-reference/balances/balances-list) # Example response ```json theme={null} { "count": 1, "next": null, "previous": null, "results": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z", "type": "CHECKING", "subtype": "MONEY_MARKET", "mask": "6789", "nickname": "My account", "balances": { "currency_code": "USD", "balance": "100.00", "available_balance": "50.99", "credit_limit": "200.00" } } ] } ``` # Bank Account Webhook Events Source: https://docs.truv.com/api-reference/bank-accounts/events Webhook events for bank account creation and updates. Subscribe to these events via [Webhooks](/api-reference/webhooks) to receive notifications when bank account data becomes available or changes during a refresh. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Bank Account events on this page also include these fields: | Field | Description | | --------------- | ------------------------------------------------------------------------------ | | `link_id` | Identifier of the Link | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | | `task_id` | The associated Task | | `employment_id` | The associated employment record | | `objects_count` | Number of bank accounts retrieved | *** ## bank-accounts-created Fires when bank account data has been retrieved. This occurs once per [Link](/api-reference/links/object) for each non-refresh [Task](/api-reference/tasks/object) completion. Multiple responses are sent when additional bank accounts are found. ```json theme={null} { "webhook_id": "3cc6a3e58cbe4b71bbbe8b821d2242b8", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "bank-accounts-created", "event_created_at": "2022-08-23T17:32:19.269355Z", "objects_count": 2, "employment_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## bank-accounts-updated Fires when the bank account count changes during a refresh Task. For example, if a person had 3 bank accounts and now has 4. ```json theme={null} { "webhook_id": "3cc6a3e58cbe4b71bbbe8b821d2242b8", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "bank-accounts-updated", "event_created_at": "2022-08-23T17:32:19.269355Z", "objects_count": 2, "employment_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` # List all bank accounts Source: https://docs.truv.com/api-reference/bank-accounts/link-bank-accounts GET /v1/links/{link_id}/bank_accounts/ List of all bank accounts used for the direct deposit # The Bank Accounts object Source: https://docs.truv.com/api-reference/bank-accounts/object Learn how to manage bank accounts for the DDS and PLL. Manage bank accounts for Direct Deposit Switching (**DDS**) and Paycheck Linked Lending (**PLL**) with the endpoints in this section. Access information from bank accounts in a user's payroll account during **Verification of Income and Employment (VOIE)** before making deposit switches. ## Attributes The values in these sections are for bank account objects. | Attribute | Type | Description | | :-------------- | :----------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | | account\_number | string | Bank account number | | routing\_number | string | Routing number | | account\_name | string, null | User-friendly account name for bank account | | account\_type | string, null | Account type of bank account, includes two types: `C` - Checking account, `S` - Savings account | | deposit\_type | string, null | Deposit type of bank account, three types of deposits available: `E` - Entire paycheck, `P` - Percentage of paycheck, `A` - Fixed amount from paycheck | | deposit\_value | string, null | Deposit value of selected bank account | | bank\_name | string, null | Bank name | *** ## Endpoints The item below is the available endpoint. * [List all bank accounts](/api-reference/bank-accounts/link-bank-accounts) *** ## Example response This JSON object is a sample payload for the endpoint. ```json theme={null} [ { "account_number": "11114623", "routing_number": "101014378", "account_name": null, "account_type": "C", "deposit_type": "A", "deposit_value": "1604.98", "bank_name": "Sandbox Bank" }, { "account_number": "11111308", "routing_number": "101013399", "account_name": null, "account_type": "C", "deposit_type": "A", "deposit_value": "25.00", "bank_name": "Sandbox Bank" } ] ``` # Retrieve the most recent bank income report Source: https://docs.truv.com/api-reference/bank-income-insights/bank-income-report-retrieve GET /v1/links/{link_id}/income/transactions/reports/ Retrieves the most recent bank income report for the specified link. This endpoint returns the latest generated report containing transaction-based income analysis and verification data. # The Bank Income Report Object Source: https://docs.truv.com/api-reference/bank-income-insights/object Find more information about bank income reports. # Attributes The table below has the values and descriptions of the bank income report responses. | Attribute | Type | Description | | :-------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------- | | status | string | Status of report, possible values `success`, `processing` | | completed\_at | date-time | Time when report was completed | | days\_requested | int32 | Requested number of days for specified transactions | | tracking\_info | string | Additional optional identifier passed by user | | provider | string | Data provider identifier | | access\_token | string | Access token of existing Link | | companies | array of strings | List of companies person works for | | accounts | array of objects | List of bank accounts, see [Accounts object](#accounts-object) | | income | array of objects | List of bank income sources, see [Income object](#income-object) | | summary | object | Bank account information summary, see [Summary object](#summary-object) | | is\_suspicious | Boolean | Status of data from source marked as suspicious, such as if detecting fraud in uploaded documents or user SSN does not match data | ## Accounts object The values in this table are for the Accounts object. | Attribute | Type | Description | | :---------- | :--------------- | :---------------------------------------------------------------------- | | id | string | Unique identifier of account | | created\_at | date-time | Date and time when account was created in Truv | | updated\_at | date-time | Date and time when account was last updated in Truv | | type | string | Parent type of account, example `CHECKING` or `SAVINGS` | | subtype | string | Account subtype, example `PLAN_401_K`, `MONEY_MARKET`, or `HOME_EQUITY` | | mask | string | Masked banking account number associated with specific account | | nickname | string | Alternate account name | | owners | array of objects | List of account's owners | ## Owner object The values in this table are for the Owner object. | Attribute | Type | Description | | :------------- | :----- | :----------------------------------- | | id | string | Unique identifier of the owner | | full\_name | string | Full name of the owner | | email | string | Email of the owner | | phone | string | Phone of the owner | | address | object | Address of the owner | | relation\_type | string | Relation of the owner to the account | ## Income object This table contains the attributes in the Income object.
Attribute Type Description
start\_date date Minimum of all dates within specific income sources in user bank accounts for days requested by client
end\_date date Maximum of all dates within specific income sources in user bank accounts for days requested by client
account\_id string Unique identifier of account
income\_description string Original description for underlying income transactions
income\_category string Income category, see [Income categories](#income-categories) for possible values and gross-up details
avg\_deposit\_amount number The average amount received per deposit, typically net of taxes and deductions
avg\_gross\_deposit\_amount number The average gross payment per deposit. Gross pay is predicted based on the transaction data
pay\_frequency string Frequency of direct deposit posted into bank account, see values below `M` - Monthly\ `SM` - Semi-monthly\ `W` - Weekly\ `BW` - Bi-weekly\ `A` - Annually\ `SA` - Semi-annually\ `C`- Commission
next\_payment\_date date The next payment date for the income source
total\_amount number Total amount of earnings for the income source of the user in the summary
iso\_currency\_code string The ISO 4217 currency code of the amount or balance
transaction\_count integer Number of income transactions per end user for specific source
historical\_summary array of objects List of bank statements for each period, see [Historical summary object](#historical-summary-object)
### Income categories Each income source in the report is assigned one of the following categories. For categories that support gross-up, `avg_gross_deposit_amount` contains the estimated gross payment before taxes and deductions. For categories without gross-up, `avg_gross_deposit_amount` equals `avg_deposit_amount`. | Category | Value | Grossed up | | :-------------------- | :---------------------- | :--------- | | Paycheck | `PAYCHECK` | Yes | | Retirement | `RETIREMENT` | Yes | | Government Employment | `GOVERNMENT_EMPLOYMENT` | Yes | | EWA Payroll | `EWA_PAYROLL` | Yes | | Gig Economy | `GIG_ECONOMY` | No | | Government Benefits | `GOVERNMENT_BENEFITS` | No | | Rental | `RENTAL` | No | | Unemployment | `UNEMPLOYMENT` | No | | Private Benefits | `PRIVATE_BENEFITS` | No | | Cash or Check | `CASH_OR_CHECK` | No | | Tax Credits | `TAX_CREDITS` | No | | P2P Transfer | `P2P_TRANSFER` | No | ### Historical summary object The table below contains the attributes from the Historical summary object.
Attribute Type Description
start\_date date Start date of period covered in specific monthly summary, value is set to first day of month unless covered month is partial\ *NOTE: Partial months are the first month included in the summary when the requested date range does not begin with the first day of the month.*
end\_date date End date of period included in specific monthly summary, value is set to last day of the month unless covered month is partial\ *NOTE: Partial months are the last month included in the summary when the requested date range does not end with the last day of the month.*
total\_amount number Total amount of earnings for the income source of the user for the month in the summary
iso\_currency\_code string The ISO 4217 currency code of the amount or balance
transactions array of objects List of transactions, see [Transactions object](#transactions-object)
### Transactions object View information about the attributes in the Income object below. | Attribute | Type | Description | | :------------------ | :------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | amount | string | Settled value of transaction, denominated in transactions currency as stated in `iso_currency_code`, positive value when money moves out of account and negative otherwise. | | iso\_currency\_code | string | ISO 4217 currency code of amount or balance | | date | date | Date transaction occurred | | check\_number | string | Check number for transaction | | description | string | Human-readable transaction description | | pending | Boolean | Status of transaction as pending or not set | | transaction\_id | string | Unique identifier of transaction | ## Summary object View information about the attributes in the Summary object below. | Attribute | Type | Description | | :-------------------------- | :------ | :--------------------------------------------------------------------------------------------- | | start\_date | date | Minimum of all dates between income sources in user bank accounts for days requested by client | | end\_date | date | Maximum of all dates between income sources in user bank accounts for days requested by client | | income\_sources\_count | integer | Number of income sources per end user | | income\_categories\_count | integer | Number of income categories per end user | | income\_transactions\_count | integer | Number of income transactions per end user | | total\_amount | string | Total amount of earnings for user income in summary | | iso\_currency\_code | string | ISO 4217 currency code of amount or balance | # Endpoints View more information about the available endpoints below. * [Retrieves a bank income report](/api-reference/bank-income-insights/bank-income-report-retrieve) # Example response The JSON sample below is from the bank income response. ```json theme={null} { "access_token": "a1685cadf2fe4e179cf883d2c166efd0", "accounts": [ { "created_at": "2024-11-25T15:46:30.668062Z", "id": "3aed25abdbc246138b84a2afd46cb05b", "mask": "******0685", "nickname": null, "owners": [ { "address": { "city": "Redwood City", "country": null, "state": "CA", "street": "35 Dry Ridge Rd", "zip": "94062" }, "email": "john.doe@example.com", "full_name": "John Doe", "id": "a43909f402f84f2392257d1e6eaf715b", "phone": "14155554193", "relation_type": null } ], "subtype": null, "type": "CHECKING", "updated_at": "2024-11-25T15:46:30.668073Z" } ], "companies": [ "string" ], "completed_at": "2024-11-25T15:46:47.498456Z", "days_requested": 61, "income": [ { "account_id": "3aed25abdbc246138b84a2afd46cb05b", "avg_deposit_amount": "1327.84", "avg_gross_deposit_amount": "1765.19", "end_date": "2024-11-24", "historical_summary": [ { "end_date": "2024-09-30", "iso_currency_code": "USD", "start_date": "2024-09-25", "total_amount": "1327.84", "transactions": [ { "amount": "1327.84", "check_number": null, "date": "2024-09-27", "description": "string", "iso_currency_code": "USD", "pending": false, "transaction_id": "c08230e3b20c4cd0b319bc5c3062ae1d" } ] }, { "end_date": "2024-10-31", "iso_currency_code": "USD", "start_date": "2024-10-01", "total_amount": "2655.68", "transactions": [ { "amount": "1327.84", "check_number": null, "date": "2024-10-11", "description": "string", "iso_currency_code": "USD", "pending": false, "transaction_id": "a9b3aee936e04e6788af36c467206d29" }, { "amount": "1327.84", "check_number": null, "date": "2024-10-25", "description": "string", "iso_currency_code": "USD", "pending": false, "transaction_id": "4c262810f0534067b4f86fa76873a5f8" } ] }, { "end_date": "2024-11-24", "iso_currency_code": "USD", "start_date": "2024-11-01", "total_amount": "2655.68", "transactions": [ { "amount": "1327.84", "check_number": null, "date": "2024-11-08", "description": "string", "iso_currency_code": "USD", "pending": false, "transaction_id": "1d1c70529fb940918bcabbb235216679" }, { "amount": "1327.84", "check_number": null, "date": "2024-11-22", "description": "string", "iso_currency_code": "USD", "pending": false, "transaction_id": "67e88c96515c40d29e454bb27d407406" } ] } ], "income_category": "PAYCHECK", "income_description": "string", "iso_currency_code": "USD", "pay_frequency": "BW", "start_date": "2024-09-25", "total_amount": "6639.20", "transaction_count": 5 } ], "is_suspicious": false, "provider": "9f732f7a-b6e2-4c60-81eb-af6274f411dc", "status": "success", "summary": { "end_date": "2024-11-24", "income_categories_count": 1, "income_sources_count": 1, "income_transactions_count": 5, "iso_currency_code": "USD", "start_date": "2024-09-25", "total_amount": "6639.20" }, "tracking_info": null } ``` # List all bank statements Source: https://docs.truv.com/api-reference/bank-statements/link-bank-statements GET /v1/links/{link_id}/bank_statements/ The endpoint returns a list of bank statement PDFs collected for the link's accounts. # The Bridge Token object Source: https://docs.truv.com/api-reference/bridge-token/object Create tokens with the API to use Truv Bridge in your integration. A **bridge\_token** is a short-lived token that is required to open Truv Bridge. ### Bridge Token Attributes The attributes of the Bridge Token are below. | Attribute | Type | Description | | :------------------- | :----- | :------------------------------------------------------------------------------------------ | | bridge\_token | string | Unique ID of Bridge Token | | tracking\_info | string | Information to associate with current user | | product\_type | string | Indicates main product type | | data\_sources | array | List of data sources for the provided product type. Leave blank to apply default values. | | use\_case | string | Use case for the connection which will be used for billing. | | template\_id | string | An ID of a customization template. Leave blank to apply default values. | | allowed\_products | array | List of allowed product types for linked account, only main type is allowed if not included | | company\_mapping\_id | string | Company ID to skip search step | | provider\_id | string | Provider ID to skip search step | | access\_token | string | Access token of existing Link, used for data refresh with re-authentication | | account | object | Bank account info. Used for Direct deposit switching and Paycheck linked lending | ## Endpoints Below is the available endpoint list for creating a **bridge\_token**. * [Create a bridge token](/api-reference/bridge-token/users_tokens) *** ## Example response The example object below is from the `Create Bridge Token` endpoint. ```json theme={null} { "bridge_token": "2f67984a110747d190c39e1022c81837", "tracking_info": "any data for tracking current user", "client_name": "Truv Demo", "product_type": "income", "allowed_products": [ "income", "deposit_switch" ], "company_mapping_id": "99dd17074ac94aa9ace2621d657c7610", "access_token": "99dd17074ac94aa9ace2621d657c7610" } ``` # Create a bridge token Source: https://docs.truv.com/api-reference/bridge-token/users_tokens POST /v1/users/{user_id}/tokens/ The endpoint creates a bridge token for a user. This is typically the endpoint called before initializing the Bridge since the response from this call is passed to the TruvBridge.init function. # Search companies with autocomplete Source: https://docs.truv.com/api-reference/companies/company_autocomplete_search GET /v1/company-mappings-search/ The endpoint provides company search using prefix. # Get company information Source: https://docs.truv.com/api-reference/companies/company_info GET /v1/companies/{company_mapping_id}/ The endpoint returns detailed information for a specific company mapping, including basic company details, success rate, and bank account information. # Search companies Source: https://docs.truv.com/api-reference/companies/company_mapping POST /v1/companies/ The endpoint returns the `company_mapping_id` for a company if it exists. This `company_mapping_id` can be passed to the `/bridge-tokens` endpoint to have the user skip the company selection step and suggest a data provider. # The Companies object Source: https://docs.truv.com/api-reference/companies/object Search employers, check coverage, and map companies to payroll providers A **Company** represents an organization where a user works and receives income. Truv Bridge prompts users with a company search by default, allowing users to find and connect their employer's payroll system. When a `company_mapping_id` is passed directly into Truv Bridge, the user skips the search step entirely and goes straight to authentication. Each company typically maps to one [data provider](/api-reference/data-providers/object) — the payroll system or bank that stores the data. Check a company's `success_rate` and `mapping_status` before creating an order to optimize the user experience and decide whether to fall back to document upload. *** ## Attributes | Attribute | Type | Description | | -------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `company_mapping_id` | String | Unique company identifier. Pass to Truv Bridge to bypass employer search. | | `name` | String | Company name | | `domain` | String | Unique web domain of the company | | `logo_url` | String | URL to the company's logo | | `confidence_level` | String | Predicted success rate as a numeric string (`"0.0"`–`"1.0"`; values ≥ 0.5 indicate high success) | | `success_rate` | String | Predicted verification success: `"high"` — expected to succeed; `"low"` — may succeed (send if the user knows their payroll provider and is confident); `"unsupported"` — payroll verification not feasible; `null` — not enough attempts to determine | | `mapping_status` | String | Mapping to the payroll system: `"verified"` — Truv manually verified the mapped provider; `"mapped"` — a provider is mapped and the user won't select one in Bridge; `"unmapped"` — no provider mapped, the user must select one manually | *** ## Endpoints Search companies by name with autocomplete. Use results to populate or pre-fill Truv Bridge. Retrieve detailed attributes for a specific company by its mapping ID Map a domain or company name to a Truv company record and mapping ID *** ## Example response ```json theme={null} { "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456", "name": "Facebook Demo", "domain": "facebook.com", "logo_url": "https://citadelid-resources.s3-us-west-2.amazonaws.com/facebook.png", "confidence_level": "0.9", "success_rate": "high", "mapping_status": "verified" } ``` *** ## Common use cases Search for a company using the autocomplete endpoint, retrieve its `company_mapping_id`, and pass it when creating the Bridge token. The user lands straight on the login screen for their employer. No search step needed. ```javascript theme={null} // 1. Search for the company (the response is an array of companies) const results = await fetch('https://prod.truv.com/v1/company-mappings-search/?query=Facebook', { headers: { 'X-Access-Client-Id': CLIENT_ID, 'X-Access-Secret': SECRET } }); const companies = await results.json(); const { company_mapping_id } = companies[0]; // 2. Pass company_mapping_id when creating the Bridge token (server-side), // then initialize Truv Bridge with the returned token. const bridgeToken = await createBridgeToken({ company_mapping_id }); TruvBridge.init({ bridgeToken }).open(); ``` Use `success_rate` and `mapping_status` to decide whether to offer payroll-based verification or prompt the user to upload documents instead. | `success_rate` | `mapping_status` | Recommendation | | --------------- | ---------------- | --------------------------------------------- | | `"high"` | `"verified"` | Proceed with payroll verification | | `"low"` | `"mapped"` | Offer document upload as primary path | | `"unsupported"` | `"unmapped"` | Skip payroll. Go straight to document upload. | # Data Processing Source: https://docs.truv.com/api-reference/data-processing Processing stages, timing, and data availability during verification Truv processes verification data in sequential stages. Each stage produces progressively more data. Large documents and certain formats may require longer processing times. ## Processing stages | Stage | Approximate time | Description | | ---------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `login` | \< 10 seconds | User authentication with payroll provider | | `mfa` | 10–30 seconds | Payroll provider multi-factor authentication request from user | | `parse` | \~30 seconds | Collecting basic information about identity, employment, and list of paystubs with pay dates | | `full_parse` | \< 45 seconds, up to 5 minutes | Downloading and parsing paystubs, W-2s, and income sources. Data processing continues in the background after successful authentication and closing Truv Bridge | | `switch_deposit` | \~30 seconds | Updating pay allocations and specified distributions within user account | *** ## Median stage times Processing durations are approximations and may vary. * **Login**: 5 to 15 seconds * **Parse**: 30 to 60 seconds (Base parsing) * **Full parse**: 1 to 5 minutes *** ![Processing timeline](https://files.readme.io/87c2d19-timeline.png) Each task has a maximum limit of 20 minutes to complete. *** ## Data available at each stage | Stage | Data available | | -------------- | ----------------------------------------------------- | | **Login** | — | | **Base parse** | Identity, Employment, List of paystubs with pay dates | | **Full parse** | Paystubs, Parsed income, W-2s, Bank accounts | When using VOIE endpoints, data from the base parse is available without waiting for full parse to complete. Use [webhooks](/api-reference/webhooks) or the [Tasks API](/api-reference/tasks/tasks_read) to track progress. # The Data Providers object Source: https://docs.truv.com/api-reference/data-providers/object Look up payroll, bank, and insurance providers supported by Truv, filter by product type and data source A **Data Provider** is the underlying system that stores user data: payroll platforms (e.g., ADP, Workday, Gusto), banks (e.g., Chase, Wells Fargo), and insurance carriers. Each [company](/api-reference/companies/object) typically maps to one data provider. Use the Data Providers endpoints to check which providers Truv supports, verify coverage for a specific product type, and retrieve provider details before creating orders. Filter by `product_type` and `data_source` to find providers relevant to your use case. ### Supported product types `income`, `employment`, `deposit_switch`, `pll`, `insurance`, `transactions`, `assets` ### Supported data sources `payroll`, `docs`, `insurance`, `financial_accounts`, `tax`, `scoring_attributes` Before creating an order, confirm that the user's provider supports your product type by checking the `is_disabled` field and `success_rate`. *** ## Attributes | Attribute | Type | Description | | -------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `id` | String | Unique data provider identifier | | `name` | String | Data provider name (e.g., ADP, Chase, Gusto) | | `data_source` | String | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, `tax`, or `scoring_attributes` | | `logo_url` | String | URL to the provider's logo | | `is_disabled` | Boolean, null | `true` if the provider has not implemented the queried `product_type` yet; `null` when the `product_type` query parameter is omitted | | `success_rate` | String | Predicted verification success: `"high"` — expected to succeed; `"low"` — may succeed (send if the user knows their payroll provider and is confident); `"unsupported"` — payroll verification not feasible; `null` — not enough attempts to determine | *** ## Endpoints Retrieve all data providers filtered by product type and data source Get details for a specific data provider by ID *** ## Example response ```json theme={null} { "count": 123, "results": [ { "id": "adp", "name": "ADP", "data_source": "payroll", "logo_url": "https://cdn.truv.com/providers/adp.svg", "is_disabled": false, "success_rate": "high" } ], "next": "", "previous": "" } ``` # Retrieve a data provider Source: https://docs.truv.com/api-reference/data-providers/providers-detail GET /v1/providers/{id}/ This endpoint retrieves a data provider. # List all data providers Source: https://docs.truv.com/api-reference/data-providers/providers-list GET /v1/providers/ The endpoint returns a list of data providers filtered by the query parameter `product_type`. # Data Structure Source: https://docs.truv.com/api-reference/data-structure How Truv's core objects (Orders, Users, Links, and Tasks) relate to each other The Truv API is built around four core objects: **Orders**, **Users**, **Links**, and **Tasks**. Understanding how they connect is essential before integrating. Truv data structure: a client has many users; each user has many Account Links (one per data provider such as ADP, Kroger, or Workday); each Link resolves to one or more employments (companies); and each employment produces data such as tax documents, pay statements, bank accounts, and shifts. Tasks drive each connection. ## Object relationships Every verification follows the same path through these objects: 1. **Order → User.** You create an [Order](/api-reference/orders/object) with the applicant's details. Truv automatically creates a [User](/api-reference/users/object), generates a Bridge Token, and builds a landing page with a unique `share_url`. You can also create Users directly via the API if you manage your own frontend flow. 2. **User → Bridge Token.** A [Bridge Token](/api-reference/bridge-token/users_tokens) is a short-lived credential scoped to a single User. It controls which products the User can access, supports [deeplinking](/developers/integration/embedded-orders/deeplinking) to pre-select a provider, and sets the customization template. Pass it to your frontend to initialize Truv Bridge. 3. **Bridge Token → Link.** When the User authenticates with a data provider (payroll system, bank, or tax portal) through Truv Bridge, the system creates a [Link](/api-reference/links/object), a persistent connection to that provider. The Link has an `access_token` for all subsequent data operations. If the same User reconnects with the same credentials to the same provider, Truv returns the existing Link rather than creating a duplicate. 4. **Link → Task.** Each data retrieval or action through a Link is a [Task](/api-reference/tasks/object): fetching income data, switching a direct deposit, or refreshing stale data. A single Link can have multiple Tasks over its lifetime. 5. **Task → Data.** When a Task completes successfully, the verification data becomes available through the Link's data endpoints. Listen for `task-status-updated` [webhooks](/api-reference/webhooks) to know when data is ready. For the simplest integration, create an Order and let Truv handle everything: User creation, Bridge Token generation, and invite delivery. Use the lower-level User and Bridge Token APIs only when you need full control over the frontend experience. *** ## Orders An [Order](/api-reference/orders/object) is the starting point for every verification. Creating an Order automatically creates a User, generates a Bridge Token, and produces a landing page for the user to connect their account. ## Users A [User](/api-reference/users/object) represents a person connecting their accounts through Truv Bridge. Each User can have multiple Links across different providers, and each Link carries its own `access_token`, so a User with multiple connections has multiple access\_tokens. ## Links A [Link](/api-reference/links/object) is a persistent connection to a data provider for a specific User. Reusing the same credentials for the same provider returns the same Link. ## Tasks A [Task](/api-reference/tasks/object) is an individual action performed through a Link: fetching verification data, switching direct deposits, or refreshing a connection. Each Task progresses through a defined status flow from `new` to `done` or `error`. See [Task Lifecycle](/api-reference/tasks/lifecycle) for the full status diagram, processing times, and error handling. ## Data retrieval by source After a Task completes, the endpoint you use to retrieve data depends on the `data_source` value on the employer or financial account suborder. | `data_source` | Description | Retrieval endpoint | | -------------------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `payroll` | Payroll provider parsing | `GET /v1/links/{link_id}/income/report/` for income data, `GET /v1/links/{link_id}/employment/report/` for employment-only data | | `docs` | User-uploaded documents | Pre-signed URLs returned in the document upload response. Access the `file` field on each statement or W-2 object. | | `financial_accounts` | Bank account data (VOA) | `POST /v1/users/{user_id}/assets/reports/` to generate an asset report, or use the income insights endpoints for transaction-based income analysis | | `insurance` | Insurance provider data | Retrieved through the insurance suborder on the Order object | | `tax` | Tax documents | Retrieved through the tax document endpoints on the Link | | `scoring_attributes` | Transaction scoring attributes | Retrieved through the scoring attributes report endpoints | For `payroll` sources, the `income` product automatically includes employment data. You do not need to make a separate employment request if you already requested income. *** ## Field constraints Numeric fields across Truv's API use a consistent precision format. All monetary and quantity fields are stored as `DecimalField(max_digits=12, decimal_places=2)`, meaning up to 10 digits before the decimal point and exactly 2 digits after. | Field | Object | Format | Max value | | --------------- | -------------------------------------- | -------------------------------- | --------------- | | `gross_pay` | Statements, Annual income summary, W2s | Decimal string, 2 decimal places | `9999999999.99` | | `net_pay` | Statements, Annual income summary | Decimal string, 2 decimal places | `9999999999.99` | | `hours` | Statements | Decimal string, 2 decimal places | `9999999999.99` | | `income` | Employments | Decimal string, 2 decimal places | `9999999999.99` | | `pay_rate` | Employments | Decimal string, 2 decimal places | `9999999999.99` | | `bonus` | Statements, Annual income summary | Decimal string, 2 decimal places | `9999999999.99` | | `commission` | Statements, Annual income summary | Decimal string, 2 decimal places | `9999999999.99` | | `overtime` | Statements, Annual income summary | Decimal string, 2 decimal places | `9999999999.99` | | `regular` | Statements, Annual income summary | Decimal string, 2 decimal places | `9999999999.99` | | `other_pay` | Statements, Annual income summary | Decimal string, 2 decimal places | `9999999999.99` | | `deposit_value` | Bank accounts | Decimal string, 2 decimal places | `9999999999.99` | | `wages` | W2s | Decimal string, 2 decimal places | `9999999999.99` | All numeric values are returned as **strings** (e.g., `"70000.00"`), not as JSON numbers. Parse them as decimals in your application to avoid floating-point precision issues. # Retrieve a deposit switch report Source: https://docs.truv.com/api-reference/dds-reports/dds-report-retrieve GET /v1/users/{user_id}/deposit_switch/report/ The endpoint retrieves a deposit switch report for a user. # The User Deposit Switch Object Source: https://docs.truv.com/api-reference/dds-reports/object Find reference information on this page for Direct Deposit Switch (DDS) reports. Direct Deposit Switch (DDS) reports contain financial institution information from the user’s accounts. Learn more below about the data provided from reports. # Attributes The tables below cover the fields and descriptions from the responses. | Attribute | Type | Description | | :------------ | :--------------- | :------------------------------------------------------ | | completed\_at | date-time | Timestamp when report was completed | | links | array of objects | List of assets links, see [Links object](#links-object) | ## Links object The attributes and descriptions below are for the Links object. | Attribute | Type | Description | | :--------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------- | | link\_id | string | Unique identifier of Link | | tracking\_info | string | Additional optional identifier passed by user | | access\_token | string | Access token of existing Link | | provider | object | Provider information, see [Provider object](#provider-object) | | deposit\_details | object | Bank account info, for Direct Deposit Switch (DDS) and Paycheck Linked Lending (PLL), see [Deposit details object](#deposit-details-object) | ### Provider object The values in the table below are for the Provider object. | Attribute | Type | Description | | :-------------------------------- | :--------------- | :------------------------------------- | | id | string | Data provider identifier | | supported\_bank\_account\_actions | array of strings | List of supported bank account actions | ### Deposit details object View the info for the deposit details object below.
Attribute Type Description
account\_number string Account number
account\_type string Account type, see possible values below `checking` - Checking account\ `savings` - Savings account
routing\_number string Routing number
bank\_name string Bank name
deposit\_type string Deposit type, see possible values below `entire` - Entire paycheck\ `percent` - Percentage of paycheck\ `amount` - Fixed amount from paycheck
deposit\_value string Deposit value
# Endpoint The page below is for the available endpoint for DDS reports. * [Retrieve a deposit switch report](/api-reference/dds-reports/dds-report-retrieve) # Example response The JSON below is an example DDS report response. ```json theme={null} { "completed_at": "2022-05-04T11:30:00Z", "links": [ { "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "tracking_info": "string", "access_token": "99dd17074ac94aa9ace2621d657c7610", "provider": { "id": "adp", "supported_bank_account_actions": [ "create" ] }, "deposit_details": { "account_number": "16002600", "account_type": "checking", "routing_number": "123456789", "bank_name": "TD Bank", "deposit_type": "entire", "deposit_value": "50.00" } } ] } ``` # Retrieve a direct deposit switch report for a link Source: https://docs.truv.com/api-reference/deposit-switch/link_detail_reports_dds GET /v1/links/{link_id}/direct_deposit/report/ The endpoint returns the DDS report for a link # Retrieve a paycheck linked loan report Source: https://docs.truv.com/api-reference/deposit-switch/link_detail_reports_pll GET /v1/links/{link_id}/pll/report/ The endpoint returns the PLL report. # The Deposit Switch object Source: https://docs.truv.com/api-reference/deposit-switch/object Learn about the values for reports for Direct Deposit Switch (DDS). Direct Deposit Switch (**DDS**) reports contain the attributes in the tables below. ## Attributes The values below cover attributes for the Deposit Switch Report. | Attribute | Type | Description | | :---------------- | :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique identifier | | status | string | Status from [Connection Lifecycle](/api-reference/tasks/lifecycle) | | finished\_at | string | Time when report was finished | | completed\_at | string | ~~Time when report was completed~~ **(Deprecated, invalid datetime format)** | | access\_token | string | Access token for Link to payroll provider | | tracking\_info | string | Information passed to Truv Bridge from partner | | is\_suspicious | boolean | Flag to indicate if the data from the source is suspicious. E.g. fraud detected in uploaded documents or SSN of the user does not match with the data | | deposit\_details | object | Bank account info, for Direct Deposit Switch (DDS) and Paycheck Linked Lending (PLL), see [Deposit details object](#deposit-details-object) | | initial\_accounts | array of objects | List of initial accounts (nullable), see [Initial accounts object](#initial-accounts-object) | | pdf\_report | string | URL that points to the PDF file containing the report | | employer | object, null | Employer information, see [Employer object](#employer-object) | | provider | object | Payroll provider, see [Provider object](#provider-object) | ### Deposit details object This table has information for the deposit details object. | Attribute | Type | Description | | :-------------- | :----- | :-------------------------------------------------------------------------------------------------------------------------- | | account\_number | string | Account number | | account\_type | string | Account type: `checking` - Checking account, `savings` - Savings account | | routing\_number | string | Routing number | | bank\_name | string | Bank name | | deposit\_type | string | Deposit type: `entire` - Entire paycheck, `percent` - Percentage of the paycheck, `amount` - Fixed amount from the paycheck | | deposit\_value | string | Deposit value | ### Initial accounts object The information below is for the initial accounts object attributes. | Attribute | Type | Description | | :-------------- | :----- | :-------------------------------------------------------------------------------------------------------------------------- | | account\_number | string | Account number | | routing\_number | string | Routing number | | account\_type | string | Account type: `checking` - Checking account, `savings` - Savings account | | account\_name | string | Account name | | bank\_name | string | Bank name | | deposit\_type | string | Deposit type: `entire` - Entire paycheck, `percent` - Percentage of the paycheck, `amount` - Fixed amount from the paycheck | | deposit\_value | string | Deposit value | ### Employer object This table covers the employer object attributes. | Attribute | Type | Description | | :-------- | :----------- | :------------------ | | id | string | Employer ID | | name | string | Employer name | | logo\_url | string, null | Employer logo image | ### Provider object This table covers the payroll provider object attributes. | Attribute | Type | Description | | :-------- | :----- | :----------------------- | | id | string | Data provider ID | | name | string | Data provider name | | logo\_url | string | Data provider logo image | *** ## Endpoints Use the following endpoints to get information for Deposit Switch Reports. * [Retrieve a direct deposit switch report for a link](/api-reference/deposit-switch/link_detail_reports_dds) * [Retrieve a paycheck linked loan report](/api-reference/deposit-switch/link_detail_reports_pll) *** ## Example response The sample below is a JSON response for the endpoint. ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "new", "finished_at": "2021-04-06T11:30:00Z", "completed_at": "2021-04-06 11:30:00+00:00", "access_token": "48427a36d43c4d5aa6324bc06c692456", "tracking_info": "user123456", "deposit_details": { "account_number": "16002600", "account_type": "checking", "routing_number": "123456789", "bank_name": "TD Bank", "deposit_type": "percent", "deposit_value": "50.00" }, "initial_accounts": [ { "account_number": "16001234", "routing_number": "55999876" } ] } ``` # Create a new document collection Source: https://docs.truv.com/api-reference/document-collections/collections_create POST /v1/documents/collections/ The endpoint creates a new document collection and uploads documents in a single request. Documents are provided as base64-encoded content in JSON format. The uploaded files are automatically validated and queued for AI-powered categorization. # Delete a document collection Source: https://docs.truv.com/api-reference/document-collections/collections_delete DELETE /v1/documents/collections/{collection_id}/ The endpoint soft-deletes a document collection and all its associated files. The collection and files are marked as deleted but not physically removed from storage. # Finalize a collection Source: https://docs.truv.com/api-reference/document-collections/collections_finalize_create POST /v1/documents/collections/{collection_id}/finalize/ The endpoint finalizes a document collection by creating or updating links for all matched documents and users. Optionally accepts a subset of document IDs to finalize. If no document_ids provided, all recognized documents in the collection will be finalized. # Get collection finalization results Source: https://docs.truv.com/api-reference/document-collections/collections_finalize_retrieve GET /v1/documents/collections/{collection_id}/finalize/ Returns the current finalization results for the collection: the users involved, their links, and the documents associated with each link. This endpoint does not expose a top-level status; use the presence and contents of users/links/documents to inspect the result. # List all document collections Source: https://docs.truv.com/api-reference/document-collections/collections_list GET /v1/documents/collections/ The endpoint returns a paginated list of document collections for the authenticated user. # Get document collection details Source: https://docs.truv.com/api-reference/document-collections/collections_retrieve GET /v1/documents/collections/{collection_id}/ The endpoint returns detailed information about a specific collection, including all uploaded files and recognized documents with their categorization results. # Upload files to existing collection Source: https://docs.truv.com/api-reference/document-collections/collections_upload POST /v1/documents/collections/{collection_id}/upload/ The endpoint uploads additional files to an existing collection. Documents are provided as base64-encoded content in JSON format. Each uploaded file is automatically validated and queued for AI-powered categorization. # Delete an uploaded file Source: https://docs.truv.com/api-reference/document-collections/collections_uploaded_file_delete DELETE /v1/documents/collections/{collection_id}/upload/{uploaded_file_id}/ The endpoint soft-deletes a specific uploaded file from a collection. The file is marked as deleted but not physically removed from storage. # Get uploaded file details Source: https://docs.truv.com/api-reference/document-collections/collections_uploaded_file_retrieve GET /v1/documents/collections/{collection_id}/upload/{uploaded_file_id}/ The endpoint returns details about a specific uploaded file, including its processing status and any recognized documents. # The Document Collections object Source: https://docs.truv.com/api-reference/document-collections/object Find more information about document collections API. Document Collections provide a way to upload, process, and manage multiple documents in a single workflow. Documents are automatically validated and processed using AI-powered categorization to identify document types such as paystubs, W2s, 1099s, and more. # Quickstart We recommend using Python (works on all platforms): ```python theme={null} # save as prepare_request.py import base64, json, sys with open(sys.argv[1], 'rb') as f: content = base64.b64encode(f.read()).decode() json.dump({ "documents": [{ "mime_type": "application/pdf", "content": content, "filename": sys.argv[1] }] }, open('request.json', 'w')) ``` Run it: ```bash theme={null} python prepare_request.py mydocument.pdf curl -X POST https://prod.truv.com/v1/documents/collections/ \ -H "Content-Type: application/json" \ -d @request.json ``` # Collection Attributes The table below covers the attributes returned when listing document collections. | Attribute | Type | Description | | :--------------- | :-------- | :------------------------------------------------- | | collection\_id | string | Unique identifier for the collection | | created\_at | date-time | Date and time when the collection was created | | updated\_at | date-time | Date and time when the collection was last updated | | files\_count | integer | Number of uploaded files in the collection | | documents\_count | integer | Number of recognized documents in the collection | | users\_count | integer | Number of users associated with the collection | # Uploaded File Attributes The table below covers the attributes for uploaded files within a collection. | Attribute | Type | Description | | :----------------- | :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | file\_id | string | Unique identifier for the uploaded file | | filename | string | Name of the uploaded file | | mime\_type | string | MIME type of the file, valid values: `application/pdf`, `image/jpeg`, `image/png`, `image/tiff`, `image/webp`, `image/x-ms-bmp`, `image/heic`, `image/heif` | | status | string | Processing status of the file, valid values: `pending`, `validating`, `validated`, `invalid`, `duplicate`, `processing`, `successful`, `failed` | | validations | object, null | File validation results containing `is_viable_size`, `is_supported_type`, `is_accessible`, `is_valid`, `is_readable`, `is_unique` | | user\_id | string, null | Truv user ID associated with this file | | external\_user\_id | string, null | External system user ID associated with this file | # Recognized Document Attributes The table below covers the attributes for documents recognized within uploaded files. | Attribute | Type | Description | | :----------------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | document\_id | string | Unique identifier for the recognized document | | file\_id | string | ID of the uploaded file containing this document | | document\_type | string | Type of the document, valid values: `PAYSTUB`, `W2`, `F1099`, `F1040`, `BANK_STATEMENT`, `PASSPORT`, `GREEN_CARD`, `DRIVER_LICENSE`, `LETTER_OF_VERIFICATION`, `UTILITY_BILL`, `LEASE_AGREEMENT`, `INSURANCE_HOME_POLICY`, `INSURANCE_AUTO_POLICY`, `VOLUNTEER_LETTER`, `OTHER` | | document\_subtype | string, null | Subtype of the document, valid values: `F1099_MISC`, `F1099_NEC`, `F1099_DIV`, `F1099_INT`, `F1099_G`, `F1099_R`, `F_SSA1099`, `VOL_TRANSCRIPT`, `VOL_HOURS_LOG` | | status | string | Processing status of the document, valid values: `successful`, `failed`, `rejected` | | first\_name | string, null | First name extracted from the document | | last\_name | string, null | Last name extracted from the document | | user\_id | string, null | Truv user ID associated with this document | | external\_user\_id | string, null | External system user ID associated with this document | | start\_page | integer | Starting page number of the document within the file | | end\_page | integer | Ending page number of the document within the file | # Finalization After documents in a collection have been processed and categorized, use the finalize endpoint to create links for the recognized documents. This step converts the pre-processed documents into usable Truv links for retrieving income and employment data. ## Finalize request attributes The finalize endpoint returns a response containing users with their associated links and documents. ### User Object | Attribute | Type | Description | | :----------------- | :----------- | :--------------------------------------------- | | id | string | Truv user ID | | external\_user\_id | string, null | External system user ID (optional) | | links | array | List of links created or updated for this user | ### Link Object | Attribute | Type | Description | | :-------- | :----- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | link\_id | string | Truv link ID | | status | string | Current status of the link, valid values: `new`, `parse`, `full_parse`, `done`, `no_data`, `config_error`, `error`, `unavailable`. Final statuses (processing complete): `done`, `no_data`, `config_error`, `error`, `unavailable` | | documents | array | List of documents associated with this link | ### Document Object (in Finalize Response) | Attribute | Type | Description | | :---------------- | :----------- | :------------------------------------------------------ | | id | string | Recognized document ID | | document\_type | string | Type of the document (uppercase), e.g., `PAYSTUB`, `W2` | | document\_subtype | string, null | Subtype of the document (uppercase, optional) | # Endpoints Use the endpoints below to manage document collections. * [List all document collections](/api-reference/document-collections/collections_list) * [Create a new document collection](/api-reference/document-collections/collections_create) * [Get document collection details](/api-reference/document-collections/collections_retrieve) * [Delete a document collection](/api-reference/document-collections/collections_delete) * [Upload files to existing collection](/api-reference/document-collections/collections_upload) * [Get uploaded file details](/api-reference/document-collections/collections_uploaded_file_retrieve) * [Delete an uploaded file](/api-reference/document-collections/collections_uploaded_file_delete) * [Finalize a collection](/api-reference/document-collections/collections_finalize_create) * [Get collection finalization results](/api-reference/document-collections/collections_finalize_retrieve) # Example responses *** ## Collection detail response ```json theme={null} { "collection_id": "a1b2c3d4e5f6478899aabbccddeeff00", "created_at": "2025-11-11T10:00:00Z", "updated_at": "2025-11-11T10:05:00Z", "uploaded_files": [ { "file_id": "f1234567890abcdef1234567890abcde", "filename": "paystub.pdf", "mime_type": "application/pdf", "status": "successful", "validations": { "is_viable_size": true, "is_supported_type": true, "is_accessible": true, "is_valid": true, "is_readable": true, "is_unique": true }, "user_id": "a1b2c3d4e5f6478899aabbccddeeff00", "external_user_id": null } ], "documents": [ { "document_id": "d0c1234567890abcdef1234567890abc", "file_id": "f1234567890abcdef1234567890abcde", "document_type": "PAYSTUB", "document_subtype": null, "status": "successful", "first_name": "John", "last_name": "Doe", "user_id": "a1b2c3d4e5f6478899aabbccddeeff00", "external_user_id": null, "start_page": 1, "end_page": 2 } ], "users": [ { "id": "a1b2c3d4e5f6478899aabbccddeeff00", "external_user_id": "ext_user_789", "first_name": "John", "last_name": "Doe" } ] } ``` *** ## Finalization response ```json theme={null} { "users": [ { "id": "a1b2c3d4e5f6478899aabbccddeeff00", "external_user_id": "ext_user_789", "links": [ { "link_id": "c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9", "status": "done", "documents": [ { "id": "d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6", "document_type": "PAYSTUB", "document_subtype": null } ] } ] } ] } ``` # Employment Webhook Events Source: https://docs.truv.com/api-reference/employment/events Webhook events for employment data creation and updates. Subscribe to these events via [Webhooks](/api-reference/webhooks) to receive notifications when employment data becomes available or changes during a refresh. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Employment events on this page also include these fields: | Field | Description | | --------------- | ------------------------------------------------------------------------------ | | `link_id` | Identifier of the Link | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | | `task_id` | The associated Task | | `object_id` | The employment record ID | *** ## employment-created Fires when employment data has been extracted. This occurs once per [Link](/api-reference/links/object) for each non-refresh [Task](/api-reference/tasks/object) completion. Multiple responses are sent when additional employments are found. ```json theme={null} { "webhook_id": "984e2cf9b69e4bc29acea714f1d5a554", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "employment-created", "event_created_at": "2022-08-23T17:32:19.307951Z", "object_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## employment-updated Fires when employment data has changed during a refresh Task. ```json theme={null} { "webhook_id": "984e2cf9b69e4bc29acea714f1d5a554", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "employment-updated", "event_created_at": "2022-08-23T17:32:19.307951Z", "object_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` # List all employments Source: https://docs.truv.com/api-reference/employment/link-employments GET /v1/links/{link_id}/employments/ The endpoint returns a list of all employments. # Retrieve an employment Source: https://docs.truv.com/api-reference/employment/link-last-employment GET /v1/links/{link_id}/employment/ Get the most recent employment data # The Employment object Source: https://docs.truv.com/api-reference/employment/object Find information related to user employment with the endpoints in this section. Employment objects track the most recent user employment data, such as employer name, manager name, employer address, and other information. The employment data is associated with the `link_id` from Truv's Income and Employment product type. The `employments[]` array can contain multiple entries. These may represent **different employers** or **multiple positions at the same employer**. Multiple positions at the same employer occur when an employee is rehired after an absence -- each employment period appears as a separate entry. This is distinct from a promotion or title change, which updates the existing entry rather than creating a new one. When multiple entries exist for the same employer, use `original_hire_date` to identify the very first hire date at that employer and `start_date` to identify when the current (or most recent) employment period began. If the employee was never rehired, these two dates are the same. **Sandbox testing:** Use `multiple.employments` to test multiple entries from different employers, and `multiple.employments2` to test multiple positions at the same employer (rehire scenario). ## Attributes The values in this table cover attributes for the employment endpoints. | Attribute | Type | Description | | :---------------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | id | string | Unique ID of selected employee | | is\_active | boolean | Status of active employment | | job\_title | string | Job title of employee | | job\_type | string | Job types of employee: `F` - Full Time, `P` - Part Time, `S` - Seasonal, `D` - Daily, `C` - Contract, `V` - Volunteer | | start\_date | date | Start of the current employment period. For rehires, this is the date the employee was most recently hired back. | | original\_hire\_date | date | The very first hire date at this employer. Differs from `start_date` when the employee was rehired after a separation. | | end\_date | date | Employee's employment end date | | income | string | Base income amount, not including commission or bonuses | | income\_unit | string | Pay interval for income field reference: `YEARLY` - Annual income, `MONTHLY` - Monthly income, `WEEKLY` - Weekly income, `DAILY` - Daily income, `HOURLY` - Hourly income | | pay\_rate | string | Payment rate per pay cycle | | pay\_frequency | string | Pay frequency: `M` - Monthly, `SM` - Semi-Monthly, `W` - Weekly, `BW` - Bi-Weekly, `A` - Annually, `SA` - Semiannually, `C` - Commission | | external\_last\_updated | date | Indicates date of last update for employment data from payroll provider | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | | manager\_name | string, null | Supervisor name of employee | | company | object | [Company object](#company-object) | ### Company object This table covers values within the company object. | Attribute | Type | Description | | :-------- | :----- | :-------------------------------- | | name | string | Company name | | address | object | [Address object](#address-object) | | phone | string | Company phone number | | ein | string | Employer Identification Number | #### Address object The values in this table are for the address object of the company. | Attribute | Type | Description | | :-------- | :----- | :---------- | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip | | country | string | Country | *** ## Endpoint View the available endpoint for employment below. * [Retrieve an employment](/api-reference/employment/link-employments) *** ## Example response The JSON object below is the sample response for the endpoint. ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "income": "70000.00", "income_unit": "YEARLY", "pay_rate": "6500.00", "pay_frequency": "M", "is_active": false, "job_title": "PR associate", "job_type": "F", "start_date": "2018-01-01", "original_hire_date": "2017-06-21", "end_date": "2022-12-11", "external_last_updated": "2022-12-11", "derived_fields": [ "is_active" ], "missing_data_fields": [ "w2s" ], "manager_name": "Jenny McDouglas", "company": { "name": "Facebook Demo", "address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" }, "phone": "6503087300", "ein": "12-345678" } } ``` # Errors & Rate Limits Source: https://docs.truv.com/api-reference/errors HTTP error codes, API error response format, task error states, Bridge error codes, and rate limiting behavior Use the `code` field in the error response body to drive error-handling logic in your integration. The `message` field is human-readable and intended for logging and debugging. *** ## HTTP errors ### Error response format Most error responses return an `error` object with a machine-readable `code` and a `message`: ```json theme={null} { "error": { "code": "incorrect_parameters", "message": "Incorrect request parameters", "extra": { "invalid-params": [] } } } ``` The `extra` field appears on `400` responses only. It lists the specific fields that failed validation. `404` responses use a different shape: `{"detail": "Not Found."}` rather than the standard `error` object. ### Status codes | Status | `error.code` | Description | | ---------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `400 Bad Request` | `incorrect_parameters` | A required field is missing, a field value is invalid, or a combination of fields is not allowed. Check `extra.invalid-params` for specifics. | | `401 Unauthorized` | `authentication_failed` | The `X-Access-Client-Id` or `X-Access-Secret` header is missing, malformed, or the credentials do not match any key in the environment. | | `403 Forbidden` | `not_authenticated` | Credentials are valid but do not have permission to access this resource. Common cause: using sandbox credentials against a production resource. | | `404 Not Found` | *(see above)* | The requested resource ID does not exist or belongs to a different client. | | `405 Method Not Allowed` | — | The HTTP method is not supported on this endpoint. Check the [API Reference](/api-reference/openapi) for the supported method. | | `406 Not Acceptable` | — | The server can't produce a response matching the `Accept` header in your request. Truv responses are always `application/json` — remove restrictive `Accept` headers. | | `410 Gone` | `expired_token` | A token used in the Bridge flow is no longer valid. Most often a `public_token` exchange after expiry or reuse — see the [410 Gone response example](#response-examples) for recovery. | | `415 Unsupported Media Type` | — | The request payload format is unsupported. Set `Content-Type: application/json` and send a valid JSON body. | | `429 Too Many Requests` | `throttled` | Request rate limit exceeded. Back off and retry. See [Rate limits](#rate-limits). | | `500 / 502 / 503` | — | Truv-side error. Retry with exponential backoff. If errors persist, check status and contact [support@truv.com](mailto:support@truv.com). | ### Response examples Each entry in `invalid-params` carries a `field` (the offending parameter name) and a `message` (the validation reason). ```json theme={null} { "error": { "code": "incorrect_parameters", "message": "Incorrect request parameters", "extra": { "invalid-params": [ { "field": "products", "message": "This field is required." }, { "field": "user.email", "message": "Enter a valid email address." } ] } } } ``` ```json theme={null} { "error": { "code": "authentication_failed", "message": "No such token" } } ``` ```json theme={null} { "error": { "code": "not_authenticated", "message": "Authentication credentials were not provided." } } ``` ```json theme={null} { "detail": "Not Found." } ``` The most common trigger is calling `POST /v1/link-access-tokens/` with a `public_token` that was already exchanged or has aged out — `public_token` is single-use and short-lived. Less commonly, the upstream `bridge_token` has expired (valid for 6 hours from creation). ```json theme={null} { "error": { "code": "expired_token", "message": "Public token expired: 48427a36d43c4d5aa6324bc06c692456" } } ``` **Recovery** | Token | Action | | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `public_token` expired or reused | Re-run Truv Bridge so `onSuccess` returns a fresh `public_token`, then exchange it immediately at `POST /v1/link-access-tokens/`. | | `bridge_token` expired | Call [Create Bridge Token](/api-reference/bridge-token/users_tokens) for a new `bridge_token`, then re-initialize Bridge on the client. | See the [`bridge_token → public_token → access_token`](/developers/best-practices/bridge-token#understand-the-token-flow) flow for the full token lifecycle. ```json theme={null} { "error": { "code": "throttled", "message": "Request was throttled." } } ``` *** ## Rate limits Truv applies rate limits to protect platform stability and to keep latency predictable for every customer. Limits apply per access secret key. Sandbox and production have separate keys, so their limits are tracked independently. ### Standard limits | Surface | Limit | Scope | | ------------------------------------- | ------------------------------------------------ | --------------------- | | All API requests | **300 requests / minute** | Per access secret key | | Refresh endpoints, per `access_token` | **1 initial request + 3 refreshes per 24 hours** | Per `access_token` | The 300/minute limit covers all API requests authenticated with a given access secret key, across every endpoint. Requests over the limit return a `429 Too Many Requests` error. The per-`access_token` refresh limit covers `POST /v1/refresh/tasks/` and `GET /v1/refresh/tasks/{task_id}/`, plus `GET /v1/links/{link_id}/` re-fetches. Requests beyond the allowed window return the error message `Refresh limit for the access_token exceeded`. See the canonical [Links](/api-reference/links/object) and [Refresh](/api-reference/refresh/object) reference pages for the per-endpoint detail. These are the defaults for new accounts. Higher limits are available — see [Request a higher limit](#request-a-higher-limit) below. ### Handle 429 responses When a request exceeds a rate limit, Truv returns `429 Too Many Requests` with `error.code: throttled`. The connection is not penalized — subsequent requests succeed once your traffic drops back under the limit. Respect the `Retry-After` response header on `429` responses. The value is the number of seconds to wait before retrying. If the header is not present, fall back to exponential backoff starting at 1 second and capped at 60 seconds. ```text theme={null} # Pseudocode — Retry-After backoff with exponential fallback (capped at 60s) attempt = 0 loop: response = HTTP request if response.status != 429: return response retry_after = response.headers.get("Retry-After") # seconds, if Truv supplied it fallback = min(2 ** attempt, 60) # 1, 2, 4, 8, 16, 32, 60, 60, ... sleep(int(retry_after) if retry_after else fallback) attempt += 1 ``` Always check the response status before sleeping. The pseudocode above retries only on `429`; on `5xx` responses, [Truv-side error retry guidance](#status-codes) applies instead. On `2xx` or `4xx` other than `429`, return the response immediately — never retry blindly. ### Best practices * **Webhooks over polling.** Polling for status changes burns through your rate limit. Subscribe to [`order-status-updated` and `task-status-updated`](/api-reference/webhooks) and only call the API when a webhook fires. * **Stagger bulk jobs.** Spread high-volume work across time rather than bursting it, so you stay under the 300 / minute limit. * **Refresh deliberately.** The per-`access_token` refresh limit is designed for human-paced re-verification. Programmatic refresh on every page load exhausts the limit within minutes. * **Don't retry blindly.** Order creation is not idempotent — retrying a failed `POST /v1/orders/` creates a new Order. Store your application-level reference and de-duplicate before retrying. ### Request a higher limit Higher limits are available on request. To request one, contact your Truv Technical Account Manager or email [support@truv.com](mailto:support@truv.com) with: * Truv account name and environment (sandbox or production). * Current peak RPM and target peak RPM. * Time window when peaks occur (e.g., 7–9 PM ET on weekdays). * Use case context — e.g., "Recertification batch — 50,000 applicants over a 4-hour window." *** ## Task error states For all task error states, their causes, and recommended actions, see [Task Lifecycle — Error states](/api-reference/tasks/lifecycle#error-states). Subscribe to `task-status-updated` webhooks to receive error notifications in real time. *** ## Bridge errors Truv Bridge fires client-side errors through the `onEvent` callback when `type === 'ERROR'`. These are distinct from task error states — they fire in the browser during the connection flow, not through webhooks. ```javascript theme={null} onEvent: function(type, payload) { if (type === 'ERROR') { console.error(payload.error.error_code, payload.error.error_message); } } ``` For the full error code reference (`LOGIN_ERROR`, `MFA_ERROR`, `UNAVAILABLE`, `NO_DATA`, `LINK_EXISTS`, `ERROR`), error object shape, and recommended fallback routing, see [Bridge Events — Errors](/developers/sdks/bridge-events#errors). *** ## Document processing errors For document upload errors — `config_error` and `no_data` messages, fraud detection, and the complete review workflow — see [Fraud & Manual Review](/developers/fraud-and-manual-review). *** ## Webhook delivery retries For webhook timeout, retry policy, and signature verification, see [Webhooks — delivery and retries](/api-reference/webhooks). *** ## Next steps Complete task status flow and error state transitions Client-side error codes and fallback routing Document fraud detection and review workflows Real-time notifications for task and order status changes # Identity Webhook Events Source: https://docs.truv.com/api-reference/identity/events Webhook events for identity profile creation and updates. Subscribe to these events via [Webhooks](/api-reference/webhooks) to receive notifications when identity data becomes available or changes during a refresh. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Identity events on this page also include these fields: | Field | Description | | --------------- | ------------------------------------------------------------------------------ | | `link_id` | Identifier of the Link | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | | `task_id` | The associated Task | | `object_id` | The identity profile record ID | *** ## profile-created Fires when identity and profile information has been extracted. This occurs once per [Link](/api-reference/links/object) for each non-refresh [Task](/api-reference/tasks/object) completion. ```json theme={null} { "webhook_id": "81e4552a215d4f4695bc6fae2675aeee", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "profile-created", "event_created_at": "2022-08-23T17:32:19.295569Z", "object_id": "25d588c7cc1c43178375bdc1bc9852ac", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## profile-updated Fires when identity and profile information has changed during a refresh Task. ```json theme={null} { "webhook_id": "81e4552a215d4f4695bc6fae2675aeee", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "profile-updated", "event_created_at": "2022-08-23T17:32:19.295569Z", "object_id": "25d588c7cc1c43178375bdc1bc9852ac", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` # Retrieve an identity Source: https://docs.truv.com/api-reference/identity/link-identity GET /v1/links/{link_id}/identity/ Get the identity data for the user # The Identity object Source: https://docs.truv.com/api-reference/identity/object View information and details about the user's identity. Identity includes details about the user's personal identifiable information, such as the user's name, address, contact information, and other information. The information about the user is connected to the `link_id` of Truv's product types. ## Attributes The values in the table below cover attributes for identity. | Attribute | Type | Description | | :--------------- | :----------- | :------------------------------------------------------------ | | id | string | Unique user ID | | created\_at | string | ISO 8601 value for first time retrieving user's identity info | | updated\_at | string | ISO 8601 value for last time retrieving user's identity info | | first\_name | string | First name | | last\_name | string | Last name | | full\_name | string | Full name | | middle\_initials | string, null | Middle initials | | email | string, null | Email address | | `ssn` | string | Social Security Number, full or last 4 digits | | date\_of\_birth | date, null | Date of birth | | home\_address | object | [Address object](#address-object) | ### Address object The values in this table are for the address object of the user. | Attribute | Type | Description | | :-------- | :----- | :---------- | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip | | country | string | Country | *** ## Endpoint The item below is the available endpoint for Identity. * [Retrieve an identity](/api-reference/identity/link-identity) *** ## Example response The response below is the JSON object for the endpoint. ```json theme={null} { "id": "710097b33ec14f898df3644b563430e1", "created_at": "2022-08-10T09:30:48.520089Z", "updated_at": "2022-08-10T09:30:48.520114Z", "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "middle_initials": null, "email": "john.doe@gmail.com", "ssn": "221122112", "date_of_birth": "1992-03-03", "home_address": { "zip": "94062", "city": "Redwood City", "state": "CA", "street": "35 Dry Ridge Rd", "country": "US" } } ``` # Create a user bank income insights report Source: https://docs.truv.com/api-reference/income-insights/income-insights-report-create POST /v1/users/{user_id}/income_insights/reports/ The endpoint creates a bank income insights report for the user. # Retrieve a user bank income insights report Source: https://docs.truv.com/api-reference/income-insights/income-insights-report-retrieve GET /v1/users/{user_id}/income_insights/reports/{report_id}/ The endpoint retrieves a bank income insights report for the user. # The User Income Insights object Source: https://docs.truv.com/api-reference/income-insights/object Find more information on data returned by the user-level Income Insights report. The Income Insights report analyzes transaction data across a user's connected bank accounts to detect income sources, calculate averages, and forecast future income. # Attributes Values, data types, and descriptions for the report-level metadata in the response. | Attribute | Type | Description | | :-------------------- | :--------------- | :------------------------------------------------------------------------------------------------- | | report\_id | string | Unique identifier of the report | | created\_at | date-time | Timestamp when report was created | | completed\_at | date-time | Timestamp when report was completed | | days\_requested | integer | Number of days for requested transactions history | | links | array of objects | List of financial institutions connected, see [Link object](#link-object) | | bank\_income\_summary | object | Summary of income over all accounts, see [Bank Income Summary object](#bank-income-summary-object) | # Link object The information in this table is for values in the Links object. | Attribute | Type | Description | | :-------------------- | :--------------- | :---------------------------------------------------------------------------------- | | link\_id | string | Unique identifier of the link | | created\_at | date-time | Timestamp when the link was first created | | updated\_at | date-time | Timestamp of the most recent update made to the link | | provider | string | ID of the financial institution | | provider\_name | string | Name of the financial institution | | tracking\_info | string | Additional (optional) identifier passed by the user | | accounts | array of objects | List of demand-deposit accounts connected, see [Account object](#account-object) | | bank\_income\_sources | array of objects | List of income sources, see [Bank Income Source object](#bank-income-source-object) | ## Account object The information in this table is for values in the Accounts object. | Attribute | Type | Description | | :-------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------- | | id | string | Unique identifier of the account | | mask | string | The masked banking account number associated with the account | | nickname | string | An alternate name for the account | | type | enum | The type of account, see [Account Type enum](#account-type-enum) | | subtype | string | The sub-type of the account | | days\_available | integer | Days of transaction history available at report generation time, from earliest transaction to report date (inclusive) | | owners | array of objects | List of owners on the account, see [Owner object](#owner-object) | *** ## Owner object The information in this table is for values in the Owner object. | Attribute | Type | Description | | :------------- | :----- | :---------------------------------------------- | | id | string | Unique identifier of the owner | | full\_name | string | Account owner's full name | | email | string | Account owner's email address | | phone | string | Account owner's phone number | | address | object | Account owner's physical address | | relation\_type | string | The relationship this person has to the account | *** ## Income source qualification Truv groups a user's deposits into candidate sources and then decides which to surface as `bank_income_source` entries. Patterns that don't qualify still appear in the underlying transactions; they're just not surfaced as an income source. Two checks gate the decision: | Check | Rule | | :-------- | :------------------------------------------------------------------------ | | Recurring | A pay frequency is detected — weekly, bi-weekly, semi-monthly, or monthly | | Current | The most recent deposit is no more than 3 pay periods old | In practice a qualifying source needs at least 3 deposits. The "≥3" floor isn't a separate gate — it's enforced upstream by the employer-grouping step and by the pay-frequency model, both of which require at least 3 transactions before they'll emit a result. When the source-level total and per-period average are computed, major outlier deposits are trimmed (IQR filter). This shapes the published averages but is not a qualification check — a noisy source is still surfaced. These rules describe **regular** income. Irregular categories — `GIG_ECONOMY`, `RENTAL`, `EWA_PAYROLL`, `P2P_TRANSFER`, `TAX_CREDITS`, `CASH_OR_CHECK` — skip the Recurring check and use a relaxed Current tolerance (2 months). See the [Income category enum](#income-category-enum) for the full list. *** ## Bank income source object The information in this table is for values in the Bank Income Source object. | Attribute | Type | Description | | :------------------------------------------ | :--------------- | :--------------------------------------------------------------------------------------------------------------- | | start\_date | date | Earliest transaction date for this source | | end\_date | date | Latest transaction date for this source | | account\_id | string | Unique identifier of the associated account | | income\_description | string | A human-readable shorthand for the underlying transaction descriptions | | income\_category | string | The category of the income source, see [Income Category enum](#income-category-enum) | | pay\_frequency | enum | The rate at which income is deposited, see [Pay Frequency enum](#pay-frequency-enum) | | next\_payment\_date | date | The next payment date for the income source | | total\_amount | string | The sum of earnings for this income source, observed over the transaction history | | iso\_currency\_code | string | The ISO 4217 currency code for amounts in this source | | transaction\_count | integer | Number of income transactions for this source | | historical\_summary | array of objects | List of monthly summaries, see [Historical Summary object](#historical-summary-object) | | historical\_average\_monthly\_income | string | Historical average income deposited into the account, per calendar month, typically net of taxes and deductions. | | historical\_average\_monthly\_gross\_income | string | Historical average gross payment amount, per calendar month, predicted based on the transaction data. | | forecasted\_average\_monthly\_income | string | Forecasted income deposited into the account, per calendar month. | | avg\_deposit\_amount | string | The average amount received per deposit, typically net of taxes and deductions | | avg\_gross\_deposit\_amount | string | The average gross payment per deposit. Gross pay is predicted based on the transaction data | | employer | object | The normalized employer for the income source, see [Employer object](#employer-object) | *** ## Historical summary object The information in this table is for values in the Historical summary object. | Attribute | Type | Description | | :------------------ | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------- | | start\_date | date | The first date of this monthly period; will be the first day of the month unless the transaction history does not go back that far | | end\_date | date | The last date of this monthly period; will be the first day of the month unless such date is in the future | | total\_amount | string | Total amount of earnings for this monthly period | | iso\_currency\_code | string | The ISO 4217 currency code for amounts in this period | | transactions | array of objects | List of transactions, see [Transaction object](#transaction-object) | *** ## Transaction object The information in this table is for values in the Transaction object. | Attribute | Type | Description | | :------------------ | :------ | :---------------------------------------------------------- | | transaction\_id | string | Unique identifier for the transaction | | amount | string | Deposit amount | | iso\_currency\_code | string | The ISO 4217 currency code for this transaction | | date | date | Date the amount was posted to the account | | check\_number | string | The check number for the transaction | | description | string | A human-readable description for the transaction | | pending | boolean | True if the status of the transaction is pending or not set | *** ## Employer object The information in this table is for values in the Employer object. | Attribute | Type | Description | | :-------- | :----- | :--------------------------------- | | id | string | Unique identifier for the employer | | name | string | Name of the employer | | logo\_url | string | URL for the employer's logo image | # Bank Income Summary object The information in this table is for values in the Bank Income Summary object. | Attribute | Type | Description | | :------------------------------------------ | :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | start\_date | string | Earliest transaction date among all income sources | | end\_date | string | Latest transaction date among all income sources | | income\_sources\_count | integer | Number of income sources for this user | | income\_categories\_count | integer | Number of income categories for this user | | income\_transactions\_count | integer | Number of income transactions for this user | | total\_amounts | array of objects | Total amount of income observed in the transaction history, over all sources. One per currency. See [Total Amount object](#total-amount-object) | | historical\_average\_monthly\_income | array of objects | Total monthly average income earned historically, over all sources. One per currency. See [Total Amount object](#total-amount-object) | | historical\_average\_monthly\_gross\_income | array of objects | Total monthly average gross income earned historically, over all sources. One per currency. Gross amounts are estimated from transactions. See [Total Amount object](#total-amount-object) | | forecasted\_average\_monthly\_income | array of objects | Total forecasted monthly average income, over all sources. One per currency. See [Total Amount object](#total-amount-object) | | historical\_annual\_gross\_income | array of objects | Annualized gross income earned historically, over all sources. One per currency. See [Total Amount object](#total-amount-object) | | historical\_annual\_income | array of objects | Annualized income earned historically, over all sources. One per currency. See [Total Amount object](#total-amount-object) | | forecasted\_annual\_income | array of objects | Annualized forecasted income, over all sources. One per currency. See [Total Amount object](#total-amount-object) | *** ## Total amount object The information in this table is for values in the Total Amount object. | Attribute | Type | Description | | :------------------ | :----- | :---------------------------------------- | | amount | string | Total amount | | iso\_currency\_code | string | The ISO 4217 currency code for the amount | # Enumerated Types The following sets show the available values that an enum attribute could take. The `income_category` and `pay_frequency` fields are nullable and may return `null`. *** ## Account type enum | Attribute | Type | | :-------- | :----- | | CHECKING | string | | SAVINGS | string | | PREPAID | string | *** ## Income category enum | Value | Description | Grossed up | | :--------------------- | :--------------------------- | :--------- | | PAYCHECK | Regular paycheck deposits | Yes | | RETIREMENT | Retirement income | Yes | | GOVERNMENT\_EMPLOYMENT | Government employment income | Yes | | EWA\_PAYROLL | Earned wage access payroll | Yes | | GIG\_ECONOMY | Gig economy income | No | | GOVERNMENT\_BENEFITS | Government benefits | No | | RENTAL | Rental income | No | | UNEMPLOYMENT | Unemployment benefits | No | | PRIVATE\_BENEFITS | Private benefits | No | | CASH\_OR\_CHECK | Cash or check deposits | No | | TAX\_CREDITS | Tax credit payments | No | | P2P\_TRANSFER | Peer-to-peer transfers | No | | INTEREST | Interest income | No | | INVESTMENT | Investment income | No | | OTHER | Other income | No | *** ## Pay frequency enum | Value | Pay frequency | | :---- | :------------ | | `M` | Monthly | | `SM` | Semi-Monthly | | `W` | Weekly | | `BW` | Bi-Weekly | | `A` | Annually | | `SA` | Semiannually | | `C` | Commission | ## Permissible purpose enum A permissible purpose is required when creating an Income Insights report, passed in the `consumer_report_permissible_purpose` field. It identifies why you are requesting the consumer's financial data. | Value | Use case | | :------------------------------------------ | :--------------------------------------- | | `ACCOUNT_REVIEW_CREDIT` | Reviewing an existing credit account | | `ACCOUNT_REVIEW_NON_CREDIT` | Reviewing an existing non-credit account | | `EMPLOYMENT` | Employment verification | | `EXTENSION_OF_CREDIT` | Evaluating a credit application | | `LEGITIMATE_BUSINESS_NEED_TENANT_SCREENING` | Tenant screening | | `LEGITIMATE_BUSINESS_NEED_OTHER` | Other legitimate business need | | `WRITTEN_INSTRUCTION_PREQUALIFICATION` | Prequalification with written consent | | `WRITTEN_INSTRUCTION_OTHER` | Other use with written consent | # Endpoints View more information about the available endpoints for Income Insights reports. * [Create an income-insights report](/api-reference/income-insights/income-insights-report-create) * [Retrieve an income-insights report](/api-reference/income-insights/income-insights-report-retrieve) # Example response The JSON below is a sample response for the endpoint. ```json theme={null} { "report_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2022-05-04T11:30:00Z", "completed_at": "2022-05-04T12:00:00Z", "days_requested": 61, "links": [ { "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z", "provider": "chase", "provider_name": "Chase Bank", "tracking_info": "string", "accounts": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "mask": "****1234", "nickname": "My account", "type": "CHECKING", "subtype": "MONEY_MARKET", "days_available": 365, "owners": [ { "id": "2b623fa2fa9e49cea17d9692caa884c5", "full_name": "John Doe", "email": "john.doe@example.com", "phone": "14155554193", "address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" }, "relation_type": "AUTHORIZED_USER" } ] } ], "bank_income_sources": [ { "start_date": "2022-05-04", "end_date": "2022-05-04", "account_id": "24d7e80942ce4ad58a93f70ce4115f5c", "income_description": "Paycheck", "income_category": "PAYCHECK", "pay_frequency": "SM", "total_amount": "200.31", "iso_currency_code": "USD", "transaction_count": 1, "historical_summary": [ { "start_date": "2022-05-04", "end_date": "2022-05-04", "total_amount": "200.31", "iso_currency_code": "USD", "transactions": [ { "amount": "200.31", "iso_currency_code": "USD", "date": "2022-05-04", "check_number": "string", "description": "string", "pending": true, "transaction_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" } ] } ], "historical_average_monthly_income": "10000.00", "historical_average_monthly_gross_income": "12000.00", "forecasted_average_monthly_income": "10000.00", "next_payment_date": "2022-06-01", "avg_deposit_amount": "5000.00", "avg_gross_deposit_amount": "6000.00", "employer": { "id": "meta", "name": "Meta", "logo_url": "string" } } ] } ], "bank_income_summary": { "start_date": "2022-05-04", "end_date": "2022-05-04", "income_sources_count": 1, "income_categories_count": 1, "income_transactions_count": 1, "total_amounts": [ { "amount": "200.31", "iso_currency_code": "USD" } ], "historical_average_monthly_gross_income": [ { "amount": "200.31", "iso_currency_code": "USD" } ], "historical_average_monthly_income": [ { "amount": "200.31", "iso_currency_code": "USD" } ], "forecasted_average_monthly_income": [ { "amount": "200.31", "iso_currency_code": "USD" } ], "historical_annual_gross_income": [ { "amount": "200.31", "iso_currency_code": "USD" } ], "historical_annual_income": [ { "amount": "200.31", "iso_currency_code": "USD" } ], "forecasted_annual_income": [ { "amount": "200.31", "iso_currency_code": "USD" } ] } } ``` # Retrieve an insurance report Source: https://docs.truv.com/api-reference/insurance/link_detail_reports_insurance GET /v1/links/{link_id}/insurance/report/ The endpoint returns the Insurance report. # Retrieve an auto insurance report Source: https://docs.truv.com/api-reference/insurance/link_detail_reports_insurance_auto GET /v1/links/{link_id}/insurance/report/auto/ The endpoint returns the auto insurance report. # Retrieve a home insurance report Source: https://docs.truv.com/api-reference/insurance/link_detail_reports_insurance_home GET /v1/links/{link_id}/insurance/report/home/ The endpoint returns the home insurance report. # The Insurance object Source: https://docs.truv.com/api-reference/insurance/object View the comprehensive reference information for insurance data responses. ## Attributes The information in the table below covers the values for insurance report responses. | Attribute | Type | Description | | :------------- | :----------- | :----------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique identifier | | status | string | Status from [Connection Lifecycle](/api-reference/tasks/lifecycle) | | finished\_at | string | Time report was finished | | access\_token | string, null | Access token for Link to payroll provider | | tracking\_info | string | Information passed to Truv Bridge from partner | | is\_suspicious | boolean | Flag indicating if data from the source is suspicious, e.g. fraud detected in uploaded documents or the user's SSN does not match the data | | insurance | object | List of insurances, see Insurance object | | provider | string | Insurance Provider ID | | identity | object | Person's identity information | | pdf\_report | uri, null | Insurance report in PDF format | ### Insurance object These values are for the insurance object field. | Attribute | Type | Description | | :--------------- | :--------------- | :---------------------- | | policies | array of objects | List of policies | | drivers | array of objects | List of drivers | | addresses | array of objects | List of addresses | | driving\_records | array of objects | List of driving records | | agents | array of objects | List of agents | #### Policies object View the policies object values in the table below. | Attribute | Type | Description | | :-------------------------- | :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Policy ID | | policy\_type | string | Type of policy `AUTO` `NAMED_NON_OWNER` `CLASSIC_CAR` `BOAT` `CONDO` `FARMOWNER` `FLOOD` `HOMEOWNERS` `LANDLORD` `LIFE` `MOTORCYCLE` `TERM_LIFE` `UNIVERSAL_LIFE` `WHOLE_LIFE` `RENTERS` `SNOWMOBILE` `UMBRELLA` `RECREATIONAL_VEHICLE` `FIRE` `TRAILER` `PERSONAL_ARTICLES` `EARTHQUAKE` `BUSINESS_OWNERS` `COMMERCIAL_UMBRELLA` `COMMERCIAL_AUTO` `COMMERCIAL_FIRE` `COMMERCIAL_AGRIBUSINESS` `COMMERCIAL_PACKAGE` `COMMERCIAL_PROPERTY` `COMBO` `OFFROAD_VEHICLE` `WORKERS_COMPENSATION` `MOBILE_HOME` `PET` `PERSONAL_LIABILITY` `GENERAL_LIABILITY` `ERRORS_AND_OMISSIONS` `INLAND_MARINE` `GARAGE` `EXCESS_LIABILITY` `CYBER` `IDENTITY_THEFT` `COMMERCIAL_CRIME` `ARTISAN_AND_SERVICE_CONTRACTORS` `FARM_POLLUTION_LIABILITY` `FARM_UMBRELLA` `MANAGEMENT_LIABILITY` `GOLF_CART` `YACHT` `PERSONAL_WATERCRAFT` `STANDARD_PROPERTY` | | name | string | Human-friendly name | | description | string | Human-friendly description | | carrier\_policy\_number | string | Carrier policy number | | effective\_date | date-time | Policy effective date | | expiry\_date | date-time | Policy expiration date | | renewal\_date | date-time | Policy renewal date | | canceled\_date | date-time | Policy canceled date | | total\_premium\_cents | integer | Total policy premium in cents | | deductible\_cents | integer | Commercial policy deductible in cents | | carrier\_name | string | Insurance carrier name | | status | string | Policy status `ACTIVE` `CANCELLED` `EXPIRED` `UNVERIFIED` `PENDING_ACTIVATION` `PENDING_CANCELLATION` `RESCINDED` | | paid\_in\_full | boolean | Status of policy fully paid | | dwellings | array of objects | List of dwellings, see [Dwellings object](#dwellings-object) | | vehicles | array of objects | List of vehicles, see [Vehicles object](#vehicles-object) | | commercial\_named\_insureds | array of objects | List of commercial named insureds, see [Commercial named insureds object](#commercial-named-insureds-object) | | named\_insureds | array of objects | List of named insureds, see [Named insureds object](#named-insureds-object) | | claims | array of objects | List of claims, see [Claims object](#claims-object) | | loss\_events | array of objects | List of loss events, see [Loss events object](#loss-events-object) | | documents | array of objects | List of documents, see [Documents object](#documents-object) | #### Dwellings object The values in this table are for the dwellings object. | Attribute | Type | Description | | :----------------------- | :--------------- | :---------------------------------------------------------------------------------------- | | id | string | Dwelling ID | | address | object | Address object | | replacement\_cost\_cents | integer | Replacement cost in cents | | cash\_value\_cents | integer | Cash value in cents | | coverages | array of objects | List of dwelling coverages, see [Dwellings coverages object](#dwellings-coverages-object) | | mortgagees | array of objects | List of mortgagee objects, see [Mortgagees object](#dwellings-mortgagees-object) | #### Dwellings coverages object Find the information for the dwellings coverages object below. | Attribute | Type | Description | | :-------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | id | string | Dwelling coverage ID | | name | string | Name of coverage item `BASE` `DWELLING` `OTHER_STRUCTURES` `PERSONAL_PROPERTY` `BUSINESS_PROPERTY` `ORDINANCE_OR_LAW` `LOSS_OF_USE` `LOSS_ASSESSMENTS` `PERSONAL_LIABILITY` `PREMISES_LIABILITY` `REPLACEMENT_COST_FULL_VALUE` `REPLACEMENT_COST_DWELLING` `REPLACEMENT_COST_CONTENTS` `GUEST_MEDICAL_PROTECTION` `DAMAGE_TO_PROPERTY_OF_OTHERS` `MEDICAL_PAYMENTS` `ADDITIONAL_LIVING_EXPENSE` `FAMILY_LIABILITY_PROTECTION` `BUILDING_CODES` `WINDSTORM_OR_HAIL` `HURRICANE` `ALL_OTHER_PERILS` `ALL_PERILS` `EARTHQUAKE` `FLOOD` `PORTABLE_ELECTRONICS` `FASHION_ITEMS` `FINE_ART` `BICYCLE` `CAMERA` `JEWELRY` `MUSICAL_INSTRUMENT` `BUILDING` `CONTENTS` `ICC` | | premium\_cents | integer | Premium paid for coverage item, in cents | | per\_person\_limit\_cents | integer | Per-person limit, in cents | | per\_incident\_limit\_cents | integer | Per-incident limit, in cents | | deductible\_cents | integer | Deductible, in cents | | is\_declined | boolean | Status of coverage item | #### Dwellings mortgagees object The mortgagees object values for dwellings are in the table below. | Attribute | Type | Description | | :----------- | :----- | :----------------------------------------- | | id | string | ID of mortgagee | | name | string | Name of mortgagee | | type | string | Type of mortgagee `FIRST` `SECOND` `THIRD` | | loan\_number | string | Mortgage loan number | | address | object | Address object | #### Vehicles object View the information for the vehicles object below. | Attribute | Type | Description | | :-------------------- | :--------------- | :------------------------------------------------------------------------------------- | | id | string | Vehicle ID | | year | integer | Year | | make | string | Manufacturer | | model | string | Model | | series | string | Series | | series2 | string | Series 2 | | type | string | Vehicle type | | annual\_mileage | integer | Annual mileage | | vin | string | Vehicle identification number | | purchase\_date | date-time | Purchase date | | is\_removed | boolean | Status of vehicle policy | | lien\_holder | string | Vehicle lien holder name | | garaging\_address | object | Address object | | lien\_holder\_address | object | Address object | | coverages | array of objects | List of vehicle coverages, see [Vehicles coverages object](#vehicles-coverages-object) | | drivers | array of objects | List of vehicle drivers, see [Vehicles drivers object](#vehicles-drivers-object) | #### Vehicles coverages object The values in the table below are for the vehicle coverages object. | Attribute | Type | Description | | :----------------------------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | id | string | Vehicle coverage ID | | name | string | Name of coverage item `SINGLE_LIMIT_LIABILITY` `BODILY_INJURY_LIABILITY` `PROPERTY_DAMAGE_LIABILITY` `SUPPLEMENTAL_SPOUSAL_LIABILITY` `PERSONAL_INJURY_PROTECTION` `COMPREHENSIVE` `FULL_GLASS` `COLLISION_DEDUCTIBLE_WAIVER` `COLLISION` `UNINSURED_MOTORISTS` `UNINSURED_MOTORIST_BODILY_INJURY_LIABILITY` `UNINSURED_MOTORIST_PROPERTY_DAMAGE_LIABILITY` `UNINSURED_MOTORIST_BODILY_INJURY_AND_PROPERTY_DAMAGE_LIABILITY` `UNDERINSURED_MOTORISTS` `UNDERINSURED_MOTORIST_BODILY_INJURY_LIABILITY` `UNDERINSURED_MOTORIST_PROPERTY_DAMAGE_LIABILITY` `UNDERINSURED_MOTORIST_BODILY_INJURY_AND_PROPERTY_DAMAGE_LIABILITY` `UNINSURED_AND_UNDERINSURED_MOTORISTS` `UNINSURED_AND_UNDERINSURED_MOTORIST_BODILY_INJURY_LIABILITY` `UNINSURED_AND_UNDERINSURED_MOTORIST_PROPERTY_DAMAGE_LIABILITY` `UNINSURED_AND_UNDERINSURED_MOTORIST_BODILY_INJURY_AND_PROPERTY_DAMAGE_LIABILITY` `TOWING_AND_LABOR` `LOAN_OR_LEASE_ASSISTANCE` `RIDESHARE_GAP_PROTECTION` `MEDICAL_PAYMENTS` `ADDITIONAL_LIVING_EXPENSE` `FAMILY_LIABILITY_PROTECTION` `BUILDING_CODES` `EMERGENCY_ROAD_SERVICE` `RENTAL_REIMBURSEMENT` `CAR_RENTAL_AND_TRAVEL_EXPENSES` `MECHANICAL_BREAKDOWN` `SUPPLEMENTAL_UNINSURED_AND_UNDERINSURED_MOTORISTS` `EMERGENCY_EXPENSE` `REPLACEMENT_COST_PERSONAL_EFFECTS` `VACATION_LIABILITY_COVERAGE` `RV_MEDICAL` `EXTENDED_BENEFITS` `WAGE_EARNER_DISABILITY_BENEFITS` `ESSENTIAL_SERVICES_DISABILITY_BENEFITS` `DEATH_BENEFIT` `CAR_REPLACEMENT_ASSISTANCE` `FULL_TORT` `LIMITED_TORT` `COMBINED_SINGLE_LIMIT` `SPARE_PARTS` | | per\_day\_limit\_cents | integer | Per-day limit, in cents | | per\_mile\_premium\_tenth\_of\_cents | integer | Premium per mile, in tenth of cents | | premium\_cents | integer | Premium paid for coverage item, in cents | | per\_person\_limit\_cents | integer | Per-person limit, in cents | | per\_incident\_limit\_cents | integer | Per-incident limit, in cents | | deductible\_cents | integer | Deductible, in cents | | is\_declined | boolean | Status of coverage item | #### Vehicles drivers object The values below are for the vehicle drivers object. | Attribute | Type | Description | | :------------------------ | :------ | :--------------------------------------------------------------------------------------------------- | | id | string | Driver ID | | first\_name | string | First name | | middle\_name | string | Middle name | | last\_name | string | Last name | | drivers\_license | string | License number | | drivers\_license\_state | string | Driver license state | | date\_of\_birth\_str | string | Date of birth | | gender | string | Gender `MALE` `FEMALE` `NONBINARY` | | marital\_status | string | Marital status `SINGLE` `MARRIED` `DIVORCED` `WIDOWED` `SEPARATED` `CIVIL_UNION` | | relationship\_to\_insured | string | Relationship to the insured `INSURED` `SPOUSE` `BROTHER` `SISTER` `FATHER` `MOTHER` `DAUGHTER` `SON` | | is\_excluded | boolean | Status of driver from the policy or vehicle | #### Commercial named insureds object Use the table below for information about the commercial named insureds object. | Attribute | Type | Description | | :----------------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Commercial named insured ID | | name | string | Name of insured | | form\_of\_business | string | Form of business `INDIVIDUAL` `PARTNERSHIP` `LIMITED_LIABILITY_COMPANY` `S_CORPORATION` `CORPORATION` `JOINT_VENTURE` `NOT_FOR_PROFIT_ORGANIZATION` `TRUST` | | gl\_code | string | General liability class code | | sic\_code | string | Standard industrial classification code | | naics\_code | string | North American Industry Classification System code | | fein | string | Federal Employer Identification number | | `ssn` | string | Social Security Number | | is\_primary | boolean | Status of insured as primary | | address | object | Address object | #### Named insureds object The values in this table are for the named insureds object. | Attribute | Type | Description | | :----------- | :------ | :--------------------------- | | id | string | Named insured ID | | first\_name | string | First name | | middle\_name | string | Middle name | | last\_name | string | Last name | | full\_name | string | Full name | | is\_primary | boolean | Status of insured as primary | #### Claims object The claims object values are in the table below. | Attribute | Type | Description | | :------------------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | id | string | Claim ID | | dwelling\_id | string | Dwelling ID | | vehicle\_id | string | Vehicle ID | | driver\_id | string | Driver ID | | carrier\_claim\_identifier | string | Carrier claim identifier | | date\_occurred | date-time | Date claim occurred | | type | string | Claim type `WIND_AND_HAIL_DAMAGE` `WATER_DAMAGE_AND_FREEZING` `FIRE_AND_LIGHTNING_DAMAGE` `OTHER_PROPERTY_DAMAGE` `PERSONAL_LIABILITY` `POWER_OUTAGE_OR_SURGE` `THEFT` `CAR_ACCIDENT` `WINDSHIELD_DAMAGE` `ANIMAL_COLLISION` `VANDALISM` `WEATHER` `EMERGENCY_ROADSIDE_ASSISTANCE` `MEDICAL` `HURRICANE_DAMAGE` `SEWAGE_BACKUP` | | status | string | Status `OPEN` `CLOSED` | | date\_closed | date-time | Date claim was closed | | payout\_cents | integer | Payout in cents | | representative\_name | string | Representative name | | representative\_phone | string | Representative phone number | | representative\_email | string | Representative email address | | address | object | Address object | #### Loss events object Use the table below for information about the loss events object. | Attribute | Type | Description | | :---------------------- | :-------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Loss event ID | | date\_of\_occurrence | date-time | Date loss event occurred | | date\_of\_claim | date-time | Date of claim | | type | string | Loss event type `BURGLARY_AND_THEFT` `WATER_DAMAGE_AND_FREEZING_DAMAGE` `WIND_AND_HAIL_DAMAGE` `FIRE` `CUSTOMER_SLIPS_AND_FALLS` `CUSTOMER_INJURY_AND_DAMAGE` `PERSONAL_AND_ADVERTISING_INJURY` `EMPLOYEE_INJURY_OR_ILLNESS` `PRODUCT_LIABILITY` `STRUCK_BY_AN_OBJECT` `REPUTATIONAL_HARM` `VEHICULAR_ACCIDENT` `WINDSHIELD_DAMAGE` `STRIKE_RIOT_OR_CIVIL_COMMOTION` `EMERGENCY_ROADSIDE_ASSISTANCE` | | amount\_paid\_cents | integer | Amount paid in cents | | amount\_reserved\_cents | integer | Amount reserved in cents | | is\_subrogation | boolean | Status of subrogation | | is\_claim\_open | boolean | Status of claim | #### Documents object The documents object values are in the table below. | Attribute | Type | Description | | :------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------ | | id | string | Document ID | | title | string | Document title | | document\_type | string | Document type `INSURANCE_APPLICATION` `INSURANCE_BINDER` `DECLARATIONS` `ENDORSEMENT` `INSURANCE_ID_CARD` `VERIFICATION_OF_INSURANCE` | | date\_added | date-time | Document effective date | | file | string | File URL | #### Drivers object This table is a reference for the drivers object. | Attribute | Type | Description | | :------------------------ | :----- | :--------------------------------------------------------------------------------------------------- | | id | string | Driver ID | | first\_name | string | First name | | middle\_name | string | Middle name | | last\_name | string | Last name | | drivers\_license | string | License number | | drivers\_license\_state | string | Driver license state | | date\_of\_birth\_str | string | Date of birth | | gender | string | Gender `MALE` `FEMALE` `NONBINARY` | | marital\_status | string | Marital status `SINGLE` `MARRIED` `DIVORCED` `WIDOWED` `SEPARATED` `CIVIL_UNION` | | relationship\_to\_insured | string | Relationship to the insured `INSURED` `SPOUSE` `BROTHER` `SISTER` `FATHER` `MOTHER` `DAUGHTER` `SON` | #### Addresses object These values are for the address object. | Attribute | Type | Description | | :-------------- | :----- | :------------------------------------------------------------------------------------------------------ | | id | string | Address ID | | address\_nature | string | The type of address `MAILING` `PHYSICAL` `LIENHOLDER` `INCIDENT_LOCATION` `AGENCY_LOCATION` `MORTGAGEE` | | country | string | Country | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip code | #### Driving records object The values below are within the driving records object. | Attribute | Type | Description | | :-------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Driving record ID | | driver\_id | string | Driver ID | | incident\_date | date-time | Date incident occurred | | incident\_type | string | Incident type `ACCIDENT` `VIOLATION` | | violation\_type | string | The violation\_type is only available if `incident_type = VIOLATION` `MOVING` `SPEEDING` `RECKLESS_DRIVING` `DRIVING_WITHOUT_VALID_LICENSE` `HIT_AND_RUN` `DISTRACTED_DRIVING` `DRIVING_UNDER_INFLUENCE` `FAILURE_TO_YIELD` `TAILGATING` `OPEN_CONTAINER_OF_ALCOHOL` | | is\_at\_fault | boolean | Status of driver at fault | #### Agents object For information about the agents object, view the table and values below. | Attribute | Type | Description | | :---------------- | :--------------- | :---------------------------------------------------------- | | id | string | Agent info record ID | | address\_id | string | Address ID of agent or agency location | | agency\_name | string | Name of agency, `agency_name` or `agent_full_name` required | | agent\_full\_name | string | Name of agent, `agency_name` or `agent_full_name` required | | phone\_number | string | Phone number for the agent or agency | | email | string | Email for the agent or agency | | policy\_ids | array of strings | List of Policy IDs associated to agent | ### Identity object Use this table for values from the identity object. | Attribute | Type | Description | | :--------------- | :--------- | :-------------------------------------------------------------- | | id | string | ID of object | | created\_at | string | ISO 8601 value for first time retrieving person's identity info | | updated\_at | string | ISO 8601 value for last time retrieving person's identity info | | first\_name | string | First name | | last\_name | string | Last name | | full\_name | string | Full name | | middle\_initials | string | Middle initials | | email | string | Email address | | `ssn` | string | Social Security Number, full or last 4 digits | | date\_of\_birth | date, null | Date of birth | | home\_address | object | Address object | *** ## Endpoints Use the endpoint below to collect information from insurance reports. * [Retrieve an insurance report](/api-reference/insurance/link_detail_reports_insurance) *** ## Example response The sample below is a JSON response for the endpoint. ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "new", "finished_at": "2021-04-06T11:30:00Z", "access_token": "48427a36d43c4d5aa6324bc06c692456", "tracking_info": "user123456", "insurance": { "policies": [ { "id": "53c5ce0d-fb79-4f1c-bc27-32181b368fc7", "policy_type": "AUTO", "name": "AUTO AU192837", "description": "Effective 11/03/2021 - 11/03/2022", "carrier_policy_number": "HO132654", "effective_date": "2021-11-03T00:00:00Z", "expiry_date": "2021-11-03T00:00:00Z", "renewal_date": "2021-11-03T00:00:00Z", "canceled_date": "2021-11-03T00:00:00Z", "total_premium_cents": 150319, "deductible_cents": 0, "carrier_name": "progressive", "status": "ACTIVE", "paid_in_full": true, "dwellings": [ { "id": "b7a53a67-7266-42b6-a20e-97e8fc723bbc", "address": { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" }, "replacement_cost_cents": 2600, "cash_value_cents": 2600, "coverages": [ { "id": "b9087b71-c1b1-482d-be9f-92a2cf81fbb3", "name": "PERSONAL_PROPERTY", "premium_cents": 18514, "per_person_limit_cents": 0, "per_incident_limit_cents": 0, "deductible_cents": 50000, "is_declined": true } ], "mortgagees": [ { "id": "26a4ce3a-0b9f-4c3d-96c0-1c76529e3b52", "name": "string", "type": "FIRST", "loan_number": "string", "address": { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" } } ] } ], "vehicles": [ { "id": "26a4ce3a-0b9f-4c3d-96c0-1c76529e3b52", "year": 2010, "make": "CHEVROLET", "model": "Camaro", "series": "ZL1", "series2": "string", "type": "PASSENGER CAR", "annual_mileage": 26000, "vin": "1G1FK1R62J0158884", "purchase_date": "2010-10-02T12:00:00.000Z", "is_removed": true, "lien_holder": "Manhattan Bank", "garaging_address": { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" }, "lien_holder_address": { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" }, "coverages": [ { "id": "111da3f8-20b0-4839-81d7-6473437e493e", "name": "PROPERTY_DAMAGE_LIABILITY", "per_day_limit_cents": 0, "per_mile_premium_tenth_of_cents": 0, "premium_cents": 18514, "per_person_limit_cents": 0, "per_incident_limit_cents": 0, "deductible_cents": 50000, "is_declined": true } ], "drivers": [ { "id": "8857f648-c6ce-44df-8fa4-78eee16e9bb4", "first_name": "John", "middle_name": "Joseph", "last_name": "Doe", "drivers_license": "SUP1234012", "drivers_license_state": "DC", "date_of_birth_str": "05/03/1988", "gender": "MALE", "marital_status": "SINGLE", "relationship_to_insured": "INSURED", "is_excluded": true } ] } ], "commercial_named_insureds": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "Sample Business LLC", "form_of_business": "INDIVIDUAL", "gl_code": "10010", "sic_code": "6411", "naics_code": "524210", "fein": "123456789", "ssn": "123456789", "is_primary": true, "address": { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" } } ], "named_insureds": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "first_name": "string", "middle_name": "string", "last_name": "string", "full_name": "string", "is_primary": true } ], "claims": [ { "id": "", "dwelling_id": "", "vehicle_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "driver_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "carrier_claim_identifier": "string", "date_occurred": "2023-04-29T04:59:15.973Z", "type": "WIND_AND_HAIL_DAMAGE", "status": "OPEN", "date_closed": "2022-05-03T00:00:00Z", "payout_cents": 180111, "representative_name": "string", "representative_phone": "string", "representative_email": "string", "address": { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" } } ], "loss_events": [ { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "date_of_occurrence": "2022-05-03T00:00:00Z", "date_of_claim": "2022-05-03T00:00:00Z", "type": "BURGLARY_AND_THEFT", "amount_paid_cents": 123323, "amount_reserved_cents": 0, "is_subrogation": true, "is_claim_open": true } ], "documents": [ { "id": "55ad7bb6-f5a3-4ebf-91fb-2802391eb261", "title": "11-03-2021 - Auto - Automobile Policy Renewal Declarations", "document_type": "INSURANCE_APPLICATION", "date_added": "2022-05-03T00:00:00Z", "file": "https://truv-statements.s3.amazonaws.com/insurance/example_file" } ] } ], "drivers": [ { "id": "8857f648-c6ce-44df-8fa4-78eee16e9bb4", "first_name": "John", "middle_name": "Joseph", "last_name": "Doe", "drivers_license": "SUP1234012", "drivers_license_state": "DC", "date_of_birth_str": "05/03/1988", "gender": "MALE", "marital_status": "SINGLE", "relationship_to_insured": "INSURED" } ], "addresses": [ { "id": "a497f96b-94be-443e-88bb-c8289085c922", "address_nature": "MAILING", "country": "US", "street": "344 Clinton St, Apartment 3D", "city": "Brooklyn", "state": "NY", "zip": "11231" } ], "driving_records": [ { "id": "da9d46ad-8ddb-4b4b-bc7e-7a381a738f7d", "driver_id": "da9d46ad-8ddb-4b4b-bc7e-7a381a738f7c", "incident_date": "2021-04-23T00:00:00.000Z", "incident_type": "ACCIDENT", "violation_type": "MOVING", "is_at_fault": true } ], "agents": [ { "id": "da9d46ad-8ddb-4b4b-bc7e-7a381a738f7d", "address_id": "da9d46ad-8ddb-4b4b-bc7e-7a381a738f7c", "agency_name": "string", "agent_full_name": "string", "phone_number": "string", "email": "string", "policy_ids": [ "3fa85f64-5717-4562-b3fc-2c963f66afa6" ] } ] }, "provider": "progressive", "identity": { "id": "48427a36d43c4d5aa6324bc06c692456", "created_at": "2022-06-07T15:00:00Z", "updated_at": "2022-06-30T15:00:00Z", "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "middle_initials": "K", "email": "john.doe@example.com", "ssn": "123456789", "date_of_birth": "1992-03-03", "home_address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" } }, "pdf_report": "https://citadelid-resources.s3-us-west-2.amazonaws.com/report.pdf" } ``` # List all investment holdings Source: https://docs.truv.com/api-reference/investments/link-investments-list GET /v1/links/{link_id}/investments/ The endpoint returns a paginated list of investment accounts and their associated holdings, including positions, quantities, values, and asset details. Supports optional filtering by account IDs, account subtypes, and holding types. # Retrieve liabilities Source: https://docs.truv.com/api-reference/liabilities/link_liabilities GET /v1/links/{link_id}/liabilities/ The endpoint returns liability accounts including credit cards and loans with detailed balance and payment information. # The Liabilities object Source: https://docs.truv.com/api-reference/liabilities/object Retrieve user liability data from connected financial accounts. Use the Liabilities endpoints to retrieve liability data from a user's connected financial accounts. This includes information about loans, credit cards, and other debt obligations held at financial institutions. # Attributes ## Accounts The `accounts` array lists each liability account. The credit and loan terms below reference these accounts by `account_id`. | Attribute | Type | Description | | :--------- | :----------- | :----------------------------------------------------------------------------------- | | `id` | string | Unique account identifier | | `type` | string | Account type (see [Account types](#account-types)) | | `subtype` | string, null | Account subtype (see [Account types](#account-types)) | | `mask` | string, null | Last 4 digits of account number | | `nickname` | string, null | User-friendly account name | | `balances` | object | Balance information: `currency_code`, `balance`, `available_balance`, `credit_limit` | ## Credit liabilities Credit cards and lines of credit. | Attribute | Type | Description | | :----------------------- | :-------- | :----------------------------------------- | | `account_id` | string | Unique account identifier | | `purchases_apr` | decimal | APR for purchases | | `advances_apr` | decimal | APR for cash advances | | `credit_line` | decimal | Total credit line | | `current_balance` | decimal | Current outstanding balance | | `balance_as_of` | date-time | Date and time the balance was last updated | | `available_credit` | decimal | Available credit | | `available_cash` | decimal | Available cash advance | | `minimum_payment_amount` | decimal | Minimum payment due | | `next_payment_amount` | decimal | Next payment amount | | `next_payment_date` | date | Next payment due date | | `last_payment_amount` | decimal | Last payment made | | `last_payment_date` | date | Date of last payment | | `last_stmt_balance` | decimal | Last statement balance | | `last_stmt_date` | date | Last statement date | | `past_due_amount` | decimal | Amount past due | ## Loan liabilities Auto loans, student loans, personal loans, and mortgages. | Attribute | Type | Description | | :--------------------------- | :-------- | :----------------------------------------- | | `account_id` | string | Unique account identifier | | `original_principal` | decimal | Original loan principal | | `principal_balance` | decimal | Current principal remaining | | `balance_as_of` | date-time | Date and time the balance was last updated | | `interest_rate` | decimal | Current interest rate percentage | | `interest_rate_as_of` | date-time | Date rate was last updated | | `interest_paid_year_to_date` | decimal | Total interest paid YTD | | `loan_term` | string | Loan term in months | | `maturity_date` | date-time | Loan maturity date | | `escrow_balance` | decimal | Escrow balance (mortgages) | | `next_payment_amount` | decimal | Next payment amount | | `next_payment_date` | date-time | Next payment due date | | `last_payment_amount` | decimal | Last payment made | | `last_payment_date` | date-time | Date of last payment | ## Account types An account has a `type` and an optional `subtype`. **`type`** — one of: `LOAN`, `CREDIT_CARD`, `LINE_OF_CREDIT`, `MORTGAGE`, `CHECKING_LINE_OF_CREDIT` **`subtype`** — one of (nullable): `BROKERAGE`, `STUDENT`, `AUTO`, `PERSONAL`, `PERSONAL_WITH_COLLATERAL`, `HELOC`, `HOME_EQUITY`, `RV`, `SMALL_BUSINESS` ## Loan balance verification A common use case for liabilities data is **loan balance verification in refinance scenarios**. Lenders retrieve outstanding loan balances to confirm payoff amounts before closing. Liabilities data comes from a connected financial account. The member connects their bank account through Truv Bridge using either the Transactions or Assets (VOA) product. Once the connection is established, the liabilities endpoint returns outstanding loan balances, credit obligations, and payment history for the connected accounts. See [Financial Accounts](/developers/coverage-financial-accounts) for supported institutions and account types. Liabilities data is derived from the financial institution connection created by the Transactions or Assets product. No separate connection step is required — connect the account with either product, then query the liabilities endpoint for the same link. # Endpoints * [Retrieve liabilities](/api-reference/liabilities/link_liabilities) # Example response ```json theme={null} { "accounts": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "type": "CREDIT_CARD", "mask": "6789", "balances": { "currency_code": "USD", "balance": "2407.16", "available_balance": "92.84", "credit_limit": "2500.00" } } ], "liabilities": { "credit": [ { "account_id": "24d7e80942ce4ad58a93f70ce4115f5c", "purchases_apr": "23.49", "credit_line": "2500.00", "current_balance": "2407.16", "available_credit": "92.00", "minimum_payment_amount": "0.00", "next_payment_date": "2025-08-23", "last_payment_amount": "300.00", "last_payment_date": "2025-08-13" } ], "loans": [] } } ``` # Delete a link Source: https://docs.truv.com/api-reference/links/delete_link_by_link_id DELETE /v1/links/{link_id}/ The endpoint removes a link and all associated data. # Account Link Webhook Events Source: https://docs.truv.com/api-reference/links/events Webhook events for Account Link connections, disconnections, and deletions Subscribe to these events via [Webhooks](/api-reference/webhooks) to track Account Link state changes in real time. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Account Link events on this page also include these fields: | Field | Description | | --------------- | ------------------------------------------------------------------------------ | | `link_id` | The Link identifier | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | *** ## link-connected Fires when a Link connection is successfully established. ```json theme={null} { "webhook_id": "e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0", "event_type": "link-connected", "event_created_at": "2022-08-24T13:54:00.000000Z", "link_id": "d39d86dcc20c46e0ae75ba9ab1311a21", "product": "income", "data_source": "payroll", "tracking_info": null, "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## link-disconnected Fires when a Link connection fails during a refresh task. ```json theme={null} { "webhook_id": "f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1", "event_type": "link-disconnected", "event_created_at": "2022-08-25T09:31:00.000000Z", "link_id": "d39d86dcc20c46e0ae75ba9ab1311a21", "product": "income", "data_source": "payroll", "tracking_info": null, "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## link-deleted Fires when personal data and credentials are removed from a Link. ```json theme={null} { "webhook_id": "a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2", "event_type": "link-deleted", "event_created_at": "2022-08-26T10:00:00.000000Z", "link_id": "d39d86dcc20c46e0ae75ba9ab1311a21", "product": "income", "data_source": "payroll", "tracking_info": null, "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` # Retrieve a link token Source: https://docs.truv.com/api-reference/links/link_exchange_token_flow POST /v1/link-access-tokens/ Exchange a bridge public_token for a link access_token. # Retrieve a link Source: https://docs.truv.com/api-reference/links/links-item GET /v1/links/{link_id}/ # List all links Source: https://docs.truv.com/api-reference/links/links-list GET /v1/links/ # The Account Links object Source: https://docs.truv.com/api-reference/links/object Manage Links (persistent connections to user accounts) and refresh their data **Link**s have an ID value and an **access\_token**. Together, these retrieve data from a user's account. Exchange the **public\_token** value during [authentication while implementing Truv Bridge](/developers/integration/bridge-widget/overview). Access tokens are for sensitive operations, such as generating reports. ## Attributes | Attribute | Type | Description | | :----------------- | :----- | :----------------------------------------------------------------------------------------- | | id | string | Unique ID of Link | | created\_at | string | ISO 8601 value for when Link was created | | updated\_at | string | ISO 8601 value for when Link was last updated | | tracking\_info | string | Optional tracking information provided by a partner | | status | string | Status from [Connection Lifecycle](/api-reference/tasks/lifecycle) related to account Link | | user\_external\_id | string | External ID of user provided by a partner | | provider\_id | string | Data provider ID | | link\_hash | string | Unique hash for user credentials when creating link | *** ## Example response ```json theme={null} { "id": "48427a36d43c4d5aa6324bc06c692456", "created_at": "2022-06-07T15:00:00Z", "updated_at": "2022-06-30T15:00:00Z", "tracking_info": "user123456", "status": "new", "user_external_id": "user123456", "provider_id": "adp", "link_hash": "bc917458a3da4b2c8cc8282aa1707aaa" } ``` *** ## Endpoints * [List all links](/api-reference/links/links-list) * [Retrieve a link](/api-reference/links/links-item) * [Retrieve a link token](/api-reference/links/link_exchange_token_flow) * [Delete a link](/api-reference/links/delete_link_by_link_id) # OpenAPI Spec Source: https://docs.truv.com/api-reference/openapi Truv OpenAPI specification in YAML format [Open the Truv OpenAPI specification (YAML)](/openapi.yaml) to use with code generators, API explorers, or validation tools. # Order Webhook Events Source: https://docs.truv.com/api-reference/orders/events Webhook events for Order status changes and refresh failures Subscribe to these events via [Webhooks](/api-reference/webhooks) to track Order progress in real time. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Order events on this page also include these fields: | Field | Description | | -------------- | --------------------------------------------- | | `order_id` | The Order identifier | | `order_number` | Human-readable order number (nullable) | | `template_id` | Associated template, if applicable (nullable) | | `updated_at` | Time event occurred | The following fields appear only in `order-created`, `order-status-updated`, and `order-refresh-failed`: | Field | Description | | ------------- | ----------------------------------------------------------------------------------------- | | `status` | Current status of the event | | `employer_id` | Associated employer (nullable) | | `link_id` | Identifier of the Link associated with the Task (nullable) | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` (nullable) | *** ## order-created Fires when an order is created, before any status transitions happen. The `link_id`, `data_source`, and `employer_id` fields are always `null` since the order hasn't been linked yet, and `status` is always `pending`. ```json theme={null} { "webhook_id": "0aac461e7b774a38a72fd9c7c0eef8ee", "event_type": "order-created", "event_created_at": "2024-07-11T21:40:48.424610Z", "updated_at": "2024-07-11T21:40:48.424655+00:00", "product": "income", "link_id": null, "user_id": "adbe707dddee4334bffaeb5866272740", "data_source": null, "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "4138538", "employer_id": null, "status": "pending", "template_id": null } ``` *** ## order-status-updated Fires each time a suborder — a single employer or financial account — changes status. Unlike `task-status-updated`, it does not fire on individual login attempts. `order-status-updated` tracks suborder status changes, not individual login attempts. To capture every connection attempt in real time, including failures, subscribe to [`task-status-updated`](/api-reference/tasks/events#task-status-updated) events where the `tracking_info` field matches the `employer_id` from the Order. A new VOIE or VOA report ID is generated after every additional connection reaches `completed` status. ```json theme={null} { "webhook_id": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6", "event_type": "order-status-updated", "event_created_at": "2022-08-24T14:00:00.000000Z", "updated_at": "2022-08-24T14:00:00.000000+00:00", "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "ORD-2024-001", "employer_id": "31e2fdc5bf0c42d4bd2eb16f49066b0d", "status": "completed", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc", "template_id": null, "product": "income", "link_id": null, "data_source": null } ``` *** ## order-refresh-failed Fires when a refresh task fails for an Order. Use this to detect refresh failures. Unlike `link-disconnected`, this fires per-order and includes order context. ```json theme={null} { "webhook_id": "d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9", "event_type": "order-refresh-failed", "event_created_at": "2022-08-25T09:30:00.000000Z", "updated_at": "2022-08-25T09:30:00.000000+00:00", "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "ORD-2024-001", "employer_id": "31e2fdc5bf0c42d4bd2eb16f49066b0d", "status": "login_error", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc", "template_id": null, "product": "income", "link_id": null, "data_source": null } ``` *** ## order-finalized Fires when an order group reaches its terminal state and is marked final. No further data collection or refresh occurs. ```json theme={null} { "webhook_id": "0aac461e7b774a38a72fd9c7c0eef8ee", "event_type": "order-finalized", "event_created_at": "2024-07-11T21:40:48.424610Z", "user_id": "adbe707dddee4334bffaeb5866272740", "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "4138538", "template_id": "c41bec89-5d88-4d96-945f-92a9a3176cdb", "updated_at": "2024-07-11T21:40:48.424655+00:00" } ``` *** ## certification-completed Fires when an applicant submits their income self-certification, confirming which bank transactions or employment records represent the data for their order. ```json theme={null} { "webhook_id": "0aac461e7b774a38a72fd9c7c0eef8ee", "event_type": "certification-completed", "event_created_at": "2024-07-11T21:40:48.424610Z", "user_id": "adbe707dddee4334bffaeb5866272740", "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "4138538", "template_id": "c41bec89-5d88-4d96-945f-92a9a3176cdb", "updated_at": "2024-07-11T21:40:48.424655+00:00" } ``` # The Orders object Source: https://docs.truv.com/api-reference/orders/object Create verification requests, generate bridge tokens, and manage the full order lifecycle An **Order** is the starting point for every verification. When you create an Order, Truv automatically creates a [User](/api-reference/users/object), generates a [Bridge Token](/api-reference/bridge-token/object), and produces a personalized landing page for the user to connect their account. The following diagram illustrates the Order lifecycle. ```mermaid theme={null} sequenceDiagram participant Client participant API as Truv API participant User participant Bridge as Truv Bridge participant Server as Your Server Client->>API: POST /v1/orders/ API-->>Client: Order object (bridge_token) User->>Bridge: Complete verification API-->>Server: Webhook events Client->>API: GET /v1/orders/{id} ``` **Orders handle everything to get started**: creating an Order is all you need to initiate a verification. The Order creates the User, generates the Bridge Token, and tracks the entire lifecycle from creation to completion. ### What happens when you create an Order 1. **User is created** automatically from the provided applicant details 2. **Bridge Token is generated** for the Order 3. **Landing page is created** with a unique `share_url` for the user 4. **Invite is sent** (optional) via email, SMS, or both, or you can share the `share_url` directly 5. **User connects** through [Truv Bridge](/developers/integration/bridge-widget/overview) on the landing page 6. **Data is retrieved** and the Order status updates as Tasks complete ### Order lifecycle and webhooks Orders are **asynchronous**. The typical flow is: 1. You create an Order via the API or Dashboard. 2. The user authenticates with one or more employers through Truv Bridge. 3. Truv retrieves the data and fires a `task-status-updated` webhook for each employer/account as it completes. 4. Truv fires an `order-status-updated` webhook each time a suborder — an employer or financial account — changes status, for example as each connection resolves. 5. You retrieve the verification data from the [Retrieve an order](/api-reference/orders/orders_read) endpoint. 6. Truv fires an `order-finalized` webhook once the order reaches its terminal state — no further data collection or refresh occurs. | Webhook | Scope | Use for | | ---------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------- | | `task-status-updated` | Per employer/account connection | Monitoring individual connection progress, processing data as it arrives | | `order-status-updated` | Per suborder (employer/financial account) | Suborder progress; fires on status changes, not on login attempts | | `order-finalized` | Entire order group | Knowing the order is permanently final, with no further data collection or refresh | In a multi-employer order, `task-status-updated` fires for every connection attempt, including failed logins. `order-status-updated` fires whenever a suborder — an employer or financial account — changes status, but not on individual login attempts. Use `task-status-updated` for fine-grained, real-time progress; use `order-status-updated` to track suborder status changes. The `no_data` status means the user successfully connected to the provider, but the provider returned zero records. This is distinct from an `error` status, which indicates a connection failure. A `no_data` result typically means the provider has no history for the applicant, not that the connection failed. ### Create orders Create Orders through the [Truv Dashboard](https://dashboard.truv.com/app/orders) or programmatically via the [Create an Order](/api-reference/orders/orders_create) endpoint. Orders are customizable for these components: * Landing page * Text message (optional) * Email (optional) ## Attributes The attributes of Orders are below. **Report limits:** A single VOIE order supports a maximum of 5 employers, and a single VOA order supports a maximum of 5 financial institutions. If you need to verify more, create additional orders for the same user. | Attribute | Type | Description | | :--------------------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | id | string | Unique ID of order | | products | array | List of products selected for Order | | source | string | Type of platform: `floify`, `besmartee`, `lenderlogix`, `encompass_consumer_connect`, `byte`, `core_logic`, `xactus`, `constellation`, `banno`, `mx`, `q2`, `clutch`, `accio`, `encompass`, `tpo_connect`, `darkmatter`, `tazworks`, `internal`, `simplenexus`, `alkami`, `blue_sage`, `lodasoft`, `blend`, `tidalwave`, `external_webpage` | | order\_number | string | External ID from client | | custom\_field | string | Client-provided custom field for use in email, SMS, or landing page. *NOTE: Enable this field in the dashboard customization section.* | | client\_name | string | Client name displayed on the order page | | first\_name | string | First name | | last\_name | string | Last name | | user\_id | string | Unique ID of user | | bridge\_token | string | UUID value of bridge token for the Order | | share\_url | string | Landing page URL to share | | short\_share\_url | string | Shortened verification URL to share | | created\_at | string | ISO 8601 value for when Order was created | | updated\_at | string | ISO 8601 value for when Order was last updated | | completed\_at | string | ISO 8601 value for when Order was successfully completed | | canceled\_at | string | ISO 8601 value for when Order was canceled | | expired\_at | string | ISO 8601 value for Order expiration | | is\_expired | boolean | Status of Order expiration | | user\_consent\_at | string, null | ISO 8601 time when the user first gave consent. | | initial\_order | string | ID of origin Order, from Order data refresh action | | refresh\_order | string | ID of last refresh Order created by Order data refresh action | | employers | array of objects | List of user employers, see [Employers object](#employers-object) | | insurance | object | Insurance verification metadata, see [Insurance object](#insurance-object) | | financial\_accounts | array of objects | Financial accounts metadata, see [Financial accounts object](#financial-accounts-object) | | manager | object | Associated Order manager info, see [Manager object](#manager-object) | | loan | object | Loan information, see [Loan object](#loan-object) | | cc\_emails | array of strings | Email addresses for CC on order status updates (max 15) | | notes | string | Free text field for notes (max 2000 characters) | | template\_id | string | ID of template | | voie\_report\_id | string | Income and employment verification report ID (accepted by Fannie Mae DU and Freddie Mac LPA) | | voa\_report\_id | string | Asset verification report ID | | income\_insights\_report\_id | string | Income Insights report ID | | aim\_check\_report\_id | string | AIM check report ID for income calculation based on uploaded documents | To get a PDF version of the report please use the corresponding report\_id along with the GET endpoint in the User Reports section. **voie\_report\_id auto-population:** The `voie_report_id` field is only populated automatically when an account-level setting is enabled. This setting generates a Fannie Mae DU / Freddie Mac LPA compatible report ID upon order completion. Contact [Truv support](mailto:support@truv.com) to enable this feature for your account. ### Company address object The values in this table are for the address object of the company. | Attribute | Type | Description | | :-------- | :----- | :---------- | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip | | country | string | Country | ### Employers object View information for employer object field data below. | Attribute | Type | Description | | :--------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique ID | | product\_type | string | Type of product, see values below: `income`, `employment`, `deposit_switch`, `pll` | | status | string | Order status, see values below: `pending`, `sent`, `completed`, `error`, `canceled`, `expired`, `no_data`, `skipped` | | suborder\_number | string | External ID | | created\_at | string | Date and time when Order was created | | bridge\_token | string | UUID value of **bridge\_token** | | link\_id | string | Link ID for connected account | | access\_token | string, null | Access token to perform data refresh | | pdf\_report | uri, null | Verification report in PDF format | | data\_source | string | Source of data, see values below: `payroll` - Payroll provider parsing, `docs` - User uploaded documents, `insurance` - Insurance data, `financial_accounts` - Bank data, `tax` - Tax documents, `scoring_attributes` - Transactions scoring attributes report | | provider | object | see [Provider object](#provider-object) | | is\_suspicious | boolean | Status of data from source marked as suspicious, such as if detecting fraud in uploaded documents or user SSN does not match data | | start\_date | string | Employment start date | | end\_date | string | Employment end date | | company\_name | string | Company name | | company\_address | object | Company address, see [Company address object](#company-address-object) | | company\_logo | uri | Company logo URL | | company\_domain | string | Company website domain | | employments | array of objects | List of employments, see [Employments object](#employments-object) | #### Provider object This table contains data for the provider object. | Attribute | Type | Description | | :-------- | :----- | :----------------- | | id | string | Provider unique ID | | name | string | Provider name | | logo\_url | uri | Provider logo URL | #### Employments object The Employments object contains the values and descriptions below. | Attribute | Type | Description | | :---------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | income | string | Income amount not including commission or bonuses, only for income product. Null for employment product | | income\_unit | string | Pay interval for income field, only for income product. `YEARLY` - Annual income, `MONTHLY` - Monthly income, `WEEKLY` - Weekly income, `DAILY` - Daily income, `HOURLY` - Hourly income. Null for employment product | | pay\_rate | string | Payment rate per pay cycle, only for income product. Null for employment product | | pay\_frequency | string | Pay frequency, only for income product. `M` - Monthly, `SM` - Semi-Monthly, `W` - Weekly, `BW` - Bi-Weekly, `A` - Annually, `SA` - Semiannually, `C` - Commission. Null for employment product | | statements | array of objects | List of Paystubs received from a payroll provider, only for income product, see [Statements object](#statements-object). Null for employment product | | annual\_income\_summary | array of objects | Annual income summary by years, only for income product, see [Annual income summary object](#annual-income-summary-object). Null for employment product | | bank\_accounts | array of objects | List of bank accounts linked to employment, only for income product, see [Bank accounts object](#bank-accounts-object). Null for employment product | | w2s | array of objects | List of W-2 forms linked to employment, only for income product, see [W2s object](#w2s-object). Null for employment product | | id | string | Unique ID | | is\_active | boolean | Status of active employment | | job\_title | string | Employee's job title | | job\_type | string | Employee's job type. `F` - Full Time, `P` - Part Time, `S` - Seasonal, `D` - Daily (per diem), `C` - Contract | | start\_date | date | Employee's hire date | | original\_hire\_date | date | Original hire date | | end\_date | date | Employee's end date | | external\_last\_updated | date | Indicates date of last updated employment data from Payroll Provider | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | | manager\_name | string, null | Supervisor's name | | profile | object | Person's identity information | | company | object | [Company object](#company-object) | | gse\_accepted | boolean | Status of provider eligibility from Fannie Mae Desktop Underwriter | #### Statements object View the table below for information from the Statements object. | Attribute | Type | Description | | :-------------------- | :--------------- | :--------------------------------------------------------------------------------- | | id | string | Unique ID | | check\_number | string | External ID of pay stub from payroll provider | | pay\_date | date | Pay date | | net\_pay | string | Net pay | | net\_pay\_ytd | string | Net pay year to date | | gross\_pay | string | Gross pay | | gross\_pay\_ytd | string | Gross pay year to date | | bonus | string | Bonus | | commission | string | Commission | | hours | string | Work hours during pay period | | basis\_of\_pay | string | Basis of pay. `S` - Salary, `H` - Hourly, `D` - Daily, `W` - Weekly, `M` - Monthly | | period\_start | date | Period start | | period\_end | date | Period end | | regular | string | Regular pay | | regular\_ytd | string | Regular salary year to date | | other\_pay\_ytd | string | All other payment year to date | | bonus\_ytd | string | Bonus year to date | | commission\_ytd | string | Commission year to date | | overtime | string | Overtime pay | | overtime\_ytd | string | Overtime pay year to date | | other\_pay | string | All other payment | | earnings | array of objects | Earnings for this pay cycle by type | | earnings\_ytd | array of objects | Earnings year to date by type | | deductions | array of objects | Deductions for pay cycle by type | | deductions\_ytd | array of objects | Deductions year to date by type | | md5sum | string | MD5 hash value computed based on file content | | file | uri | Link to pay stub file, format is specified in the content-type | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | #### Annual income summary object Find information for the attributes and values of the annual income summary object. | Attribute | Type | Description | | :--------- | :------ | :---------------------- | | id | string | Unique ID | | year | integer | Income report year | | regular | string | Regular salary | | bonus | string | Bonus | | commission | string | Commission | | overtime | string | Overtime pay | | other\_pay | string | All other payment forms | | net\_pay | string | Net pay | | gross\_pay | string | Gross pay | #### Bank accounts object The table below covers the attributes within the bank accounts object. | Attribute | Type | Description | | :-------------- | :----- | :---------------------------------------------------------------------------------------------------------- | | account\_number | string | Account number | | routing\_number | string | Routing number | | account\_name | string | User friendly account name | | account\_type | string | Account type. `C` - Checking account, `S` - Savings account | | deposit\_type | string | Deposit type. `E` - Entire paycheck, `P` - Percentage of the paycheck, `A` - Fixed amount from the paycheck | | deposit\_value | string | Deposit value | | bank\_name | string | Bank name | #### W2s object The values in this table are for the W-2s object field. | Attribute | Type | Description | | :---------------------- | :------ | :-------------------------------------------------------------- | | file | uri | Link to W2 report file, format is specified in the content-type | | md5sum | string | MD5 hash value computed based on file content | | year | integer | Year | | wages | string | Wages, tips, other compensation (Section 1) | | federal\_tax | string | Federal income tax withheld (Section 2) | | social\_security\_wages | string | Social security wages (Section 3) | | social\_security\_tax | string | Social security tax withheld (Section 4) | | medicare\_wages | string | Medicare wages (Section 5) | | medicare\_tax | string | Medicare tax withheld (Section 6) | | gross\_pay | string | Gross pay | #### Company object This table covers values within the company object. | Attribute | Type | Description | | :-------- | :----- | :-------------------------------- | | name | string | Company name | | address | object | [Address object](#address-object) | | phone | string | Company phone number | | ein | string | Employer Identification Number | #### Address object The values in this table are for the address object of the company. | Attribute | Type | Description | | :-------- | :----- | :---------- | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip | | country | string | Country | ### Insurance object This table's values contain information for the insurance object. | Attribute | Type | Description | | :--------------- | :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique ID | | product\_type | string | Type of product | | status | string | Order status | | suborder\_number | string | External ID | | created\_at | string | Date and time when Order was created | | bridge\_token | string | UUID value of **bridge\_token** | | link\_id | string | Link ID for connected account | | access\_token | string, null | Access token to perform data refresh | | pdf\_report | uri, null | Verification report file as a PDF | | data\_source | string | Source of data, see values below: `payroll` - Payroll provider parsing, `docs` - User uploaded documents, `insurance` - Insurance data, `financial_accounts` - Bank data, `tax` - Tax documents, `scoring_attributes` - Transactions scoring attributes report | | provider | object | see [Provider object](#provider-object) | | is\_suspicious | boolean | Status of data from source marked as suspicious, such as if detecting fraud in uploaded documents or user SSN does not match data | | provider\_id | string | Pre-selected ID of insurance provider | ### Financial accounts object The financial accounts object attributes below have type information and descriptions. | Attribute | Type | Description | | :--------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique ID | | product\_type | string | Type of product | | status | string | Order status | | suborder\_number | string | External ID | | created\_at | string | Date and time when Order was created | | bridge\_token | string | UUID value of **bridge\_token** | | link\_id | string | Link ID for connected account | | access\_token | string, null | Access token to perform data refresh | | pdf\_report | uri, null | Verification report file as a PDF | | data\_source | string | Source of data, see values below: `payroll` - Payroll provider parsing, `docs` - User uploaded documents, `insurance` - Insurance data, `financial_accounts` - Bank data, `tax` - Tax documents, `scoring_attributes` - Transactions scoring attributes report | | provider | object | see [Provider object](#provider-object) | | is\_suspicious | boolean | Status of data from source marked as suspicious, such as if detecting fraud in uploaded documents or user SSN does not match data | | accounts | array of objects | List of connected accounts, see [Accounts object](#accounts-object) | #### Accounts object | Attribute | Type | Description | | :-------- | :----- | :--------------------------------------------------- | | id | string | Unique identifier of account | | type | string | Parent type of account, e.g. `CHECKING` or `SAVINGS` | | subtype | string | Account subtype, e.g. `MONEY_MARKET`, `HOME_EQUITY` | | mask | string | Last 4 digits of the account number | ### Manager object The manager object attributes below have information on type and description. | Attribute | Type | Description | | :-------- | :----- | :--------------------- | | email | string | Email of Order manager | | name | string | Name of Order manager | ### Loan object View the table below for type and description of the attributes in the loan object. | Attribute | Type | Description | | :--------------------- | :----- | :------------------------------- | | loan\_number | string | Loan identifier | | external\_id | string | External loan ID (e.g. from POS) | | originator\_name | string | Name of loan originator | | originator\_email | string | Email of loan originator | | loan\_processor\_name | string | Name of the loan processor | | loan\_processor\_email | string | Email of the loan processor | *** ## Endpoints The list below are the available endpoints for Orders. * [Create an order](/api-reference/orders/orders_create) * [Retrieve an order](/api-reference/orders/orders_read) * [Create a data refresh order](/api-reference/orders/orders_create_refresh_order) * [Update an order](/api-reference/orders/orders_partial_update) * [Cancel an order](/api-reference/orders/orders_cancel_create) * [Get list of orders by SSN](/api-reference/orders/orders_list_lookup) * [Add new employer to existing order](/api-reference/orders/order-add-new-employer) * [Retrieve an order invoice](/api-reference/orders/order_group_invoice_detail) * [Retrieve events for an order](/api-reference/orders/orders_events_list) * [Retrieve self-certification results](/api-reference/orders/orders_certifications_results) *** ## Example response The JSON object below is a sample response. ```json theme={null} { "id": "39aa1486ccca4bc19cda071ffc1ba392", "products": [ "income" ], "source": "floify", "order_number": "1534332", "custom_field": "string", "client_name": "Unnamed Verifications Inc.", "first_name": "John", "last_name": "Doe", "user_id": "99dd17074ac94aa9ace2621d657c7610", "bridge_token": "e4100fccdae94691b4414c7306220c06", "share_url": "https://cdn.truv.com/employment.html?bridge_token=63b4af88facb40e48f517c1e8c7abdf4&order_group_id=39aa1486ccca4bc19cda071ffc1ba392", "short_share_url": "https://truv.com/s/BIlEyh1A", "created_at": "2021-04-21T21:45:14.418542Z", "updated_at": "2021-04-21T21:45:14.418542Z", "canceled_at": "2021-04-22T21:45:14.418542Z", "completed_at": "2021-04-22T21:45:14.418542Z", "expired_at": "2021-04-24T21:45:14.418542Z", "is_expired": true, "user_consent_at": "2021-04-21T21:45:14.418542Z", "initial_order": "f5dc0239e2094dbc90ab2edc1918a9df", "refresh_order": "9b96606355b94e8abff8ed8d75aa2027", "employers": [ { "id": "ad9f14440d624ec3b0f66e81e44518c7", "product_type": "income", "status": "pending", "suborder_number": "133982343355", "created_at": "2021-04-21T22:12:59.346109Z", "bridge_token": "e4100fccdae94691b4414c7306220c06", "link_id": "e4100fccdae94691b4414c7306220c06", "access_token": "e4100fccdae94691b4414c7306220c06", "pdf_report": "https://cdn.truv.com/report.pdf", "data_source": "payroll", "provider": { "id": "truv_api", "name": "Sandbox Provider", "logo_url": "https://cdn.truv.com/providers/truv-blue.svg" }, "is_suspicious": true, "start_date": "2019-08-24", "end_date": "2019-11-27", "company_name": "Facebook Demo", "company_address": { "street": "1 Hacker Way", "city": "Menlo Park", "state": "CA", "zip": "94025" }, "company_logo": "https://cdn.truv.com/logos/facebook.svg", "company_domain": "facebook.com", "employments": [ { "income": "70000.00", "income_unit": "YEARLY", "pay_rate": "6500.00", "pay_frequency": "M", "statements": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "check_number": "29205182", "pay_date": "2018-05-15", "net_pay": "11500.32", "net_pay_ytd": "31980.64", "gross_pay": "13900.11", "gross_pay_ytd": "49200.00", "bonus": "100.00", "commission": "12000.00", "hours": "40.00", "basis_of_pay": "S", "period_start": "2018-05-01", "period_end": "2018-05-15", "regular": "1695.11", "regular_ytd": "23000.00", "other_pay_ytd": "700.00", "bonus_ytd": "1000.00", "commission_ytd": "24000.00", "overtime": "45.00", "overtime_ytd": "500.00", "other_pay": "60.00", "earnings": [ { "name": "Regular", "amount": "1935.77", "category": "regular", "rate": null, "units": null }, { "name": "Overtime", "amount": "60.58", "category": "overtime", "rate": "30.29", "units": "2" } ], "earnings_ytd": [ { "name": "Regular", "amount": "1935.77", "category": "regular", "rate": null, "units": null }, { "name": "Overtime", "amount": "60.58", "category": "overtime", "rate": "30.29", "units": "2" } ], "deductions": [ { "name": "Social Security Tax", "amount": "127.01", "category": "socialsec" }, { "name": "VA State Income Tax", "amount": "46.23", "category": "state" }, { "name": "Medicare Tax", "amount": "29.7", "category": "medicare" } ], "deductions_ytd": [ { "name": "Social Security Tax", "amount": "127.01", "category": "socialsec" }, { "name": "VA State Income Tax", "amount": "46.23", "category": "state" }, { "name": "Medicare Tax", "amount": "29.7", "category": "medicare" } ], "md5sum": "03639d6a6624f69a54a88ea90bd25e9d", "file": "https://cdn.truv.com/paystub_sample.pdf", "derived_fields": [ "basis_of_pay" ], "missing_data_fields": [ "earnings_ytd" ] } ], "annual_income_summary": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "year": 2018, "regular": "23000.00", "bonus": "1000.00", "commission": "24000.00", "overtime": "500.00", "other_pay": "700.00", "net_pay": "31980.64", "gross_pay": "49200.00" } ], "bank_accounts": [ { "account_number": "1234567890", "routing_number": "123456789", "account_name": "My Bank", "account_type": "C", "deposit_type": "A", "deposit_value": "200.00", "bank_name": "TD Bank" } ], "w2s": [ { "file": "https://cdn.truv.com/W2_sample.pdf", "md5sum": "f65e30c39124ad707ac4b3aeaee923a7", "year": 2020, "wages": "900.50", "federal_tax": "75.01", "social_security_wages": "900.50", "social_security_tax": "56.30", "medicare_wages": "900.50", "medicare_tax": "13.15", "gross_pay": "18211.48" } ], "id": "24d7e80942ce4ad58a93f70ce4115f5c", "is_active": false, "job_title": "PR associate", "job_type": "F", "start_date": "2018-01-01", "original_hire_date": "2017-06-21", "end_date": "2025-03-13", "external_last_updated": "2025-03-13", "dates_from_statements": false, "derived_fields": [ "is_active" ], "missing_data_fields": [ "w2s" ], "manager_name": "Jenny McDouglas", "profile": { "id": "48427a36d43c4d5aa6324bc06c692456", "created_at": "2022-06-07T15:00:00Z", "updated_at": "2022-06-31T15:00:00Z", "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "middle_initials": "K", "email": "john.doe@example.com", "ssn": "123456789", "date_of_birth": "1992-03-03", "home_address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" } }, "company": { "name": "Facebook Demo", "address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" }, "phone": "6503087300", "ein": "12-345678" } } ] } ], "insurance": { "id": "ad9f14440d624ec3b0f66e81e44518c7", "product_type": "insurance", "status": "pending", "suborder_number": "133982343355", "created_at": "2021-04-21T22:12:59.346109Z", "bridge_token": "e4100fccdae94691b4414c7306220c06", "link_id": "e4100fccdae94691b4414c7306220c06", "access_token": "e4100fccdae94691b4414c7306220c06", "pdf_report": "https://cdn.truv.com/report.pdf", "data_source": "insurance", "provider": { "id": "truv_api", "name": "Sandbox Provider", "logo_url": "https://cdn.truv.com/providers/truv-blue.svg" }, "is_suspicious": true, "provider_id": "geico" }, "manager": { "email": "john.doe@example.com", "name": "John Doe" }, "financial_accounts": [ { "id": "ad9f14440d624ec3b0f66e81e44518c7", "product_type": "transactions", "status": "pending", "suborder_number": "133982343355", "created_at": "2021-04-21T22:12:59.346109Z", "bridge_token": "e4100fccdae94691b4414c7306220c06", "link_id": "e4100fccdae94691b4414c7306220c06", "access_token": "e4100fccdae94691b4414c7306220c06", "pdf_report": "https://cdn.truv.com/report.pdf", "data_source": "financial_accounts", "provider": { "id": "truv_api", "name": "Sandbox Provider", "logo_url": "https://cdn.truv.com/providers/truv-blue.svg" }, "is_suspicious": true, "accounts": [ { "id": "3aed25abdbc246138b84a2afd46cb05b", "type": "CHECKING", "subtype": null, "mask": "6789" } ] } ], "loan": { "loan_number": "MUUT220700012", "originator_name": "John Doe", "originator_email": "john@example.com", "loan_processor_name": "John Doe", "loan_processor_email": "john@doe.com", "external_id": "c505e0f1-b413-4fdc-853f-c87e7d2cc4a5" }, "template_id": "9b96606355b94e8abff8ed8d75aa2027", "cc_emails": [ "user@example.com" ], "notes": "string", "voie_report_id": "b19c454a98594b4084b71e3b62873d29", "voa_report_id": "b19c454a98594b4084b71e3b62873d29", "income_insights_report_id": "b19c454a98594b4084b71e3b62873d29", "aim_check_report_id": "FM-1234-39aa1486ccca4bc19cda071ffc1ba392" } ``` # Add new employer to the existing order Source: https://docs.truv.com/api-reference/orders/order-add-new-employer POST /v1/orders/{id}/employers/ The endpoint allows to add new employer to the existing order. The order should not be expired or canceled. # Retrieve an order invoice Source: https://docs.truv.com/api-reference/orders/order_group_invoice_detail GET /v1/orders/{id}/invoice/ The endpoint returns an order invoice. # Cancel an order Source: https://docs.truv.com/api-reference/orders/orders_cancel_create POST /v1/orders/{id}/cancel/ The endpoint cancels the order. # Retrieve self-certification results for an order Source: https://docs.truv.com/api-reference/orders/orders_certifications_results GET /v1/orders/{id}/certifications/ The endpoint returns self-certification results for employments and accounts that have been reviewed and certified by the user. # Create an order Source: https://docs.truv.com/api-reference/orders/orders_create POST /v1/orders/ The endpoint creates an order # Create a data refresh order Source: https://docs.truv.com/api-reference/orders/orders_create_refresh_order POST /v1/orders/{id}/ The endpoint creates the new order with data populated from the existing order. # Retrieve events for an order Source: https://docs.truv.com/api-reference/orders/orders_events_list GET /v1/orders/{id}/events/ Returns a list of events for the specified order. # List orders Source: https://docs.truv.com/api-reference/orders/orders_list GET /v1/orders/ The endpoint returns a list of orders. # Get list of orders by SSN Source: https://docs.truv.com/api-reference/orders/orders_list_lookup POST /v1/orders/lookup/ The endpoint returns a list of orders by an applicant SSN # Update an order Source: https://docs.truv.com/api-reference/orders/orders_partial_update PATCH /v1/orders/{id}/ The endpoint updates the order. Update only available if all employers in one of statuses: pending, sent. # Retrieve an order Source: https://docs.truv.com/api-reference/orders/orders_read GET /v1/orders/{id}/ The endpoint returns the order. # List all parsed documents Source: https://docs.truv.com/api-reference/parsed-documents/list-parsed-documents GET /v1/links/{link_id}/parsed-documents/ The endpoint returns a list of parsed documents. Parsed documents contain structured data extracted from uploaded documents. **Note:** Currently, only volunteer letters are available through this endpoint. Support for additional document types (paystubs, etc.) will be added in future releases. You can filter, order, and paginate results using query parameters. # The Parsed Documents object Source: https://docs.truv.com/api-reference/parsed-documents/object Access parsed document data retrieved through Truv Bridge connections. Parsed Documents contain structured data extracted from documents uploaded and processed through Truv Bridge. Currently, only **volunteer letters** (`VOLUNTEER_LETTER`) are available through this endpoint; support for additional document types such as paystubs will be added in future releases. # Attributes The table below covers the fields in a parsed document. | Attribute | Type | Description | | :---------------- | :----------- | :--------------------------------------------------------------------- | | id | string | Parsed document ID | | document\_type | string | Document type. Currently only `VOLUNTEER_LETTER` is supported. | | document\_subtype | string, null | Document subtype, valid values below `VOL_TRANSCRIPT`, `VOL_HOURS_LOG` | | file | uri, null | Parsed document file link | | md5sum | string | Parsed document MD5 checksum | # Endpoints Use the endpoints below to get information on parsed documents. * [List parsed documents](/api-reference/parsed-documents/list-parsed-documents) * [Retrieve parsed document](/api-reference/parsed-documents/retrieve-parsed-document) # Example response The sample below is a JSON response for the List endpoint. ```json theme={null} { "count": 1, "next": null, "previous": null, "results": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "document_type": "VOLUNTEER_LETTER", "document_subtype": "VOL_TRANSCRIPT", "file": "https://cdn.truv.com/files_examples/VOLUNTEER_LETTER.pdf", "md5sum": "24d7e80942ce4ad58a93f70ce4115f5c" } ] } ``` # Retrieve parsed document Source: https://docs.truv.com/api-reference/parsed-documents/retrieve-parsed-document GET /v1/links/{link_id}/parsed-documents/{doc_id}/ The endpoint returns a parsed document with its extracted data. The `parsed_data` field contains structured information extracted from the document. **Note:** Currently, only volunteer letters are available through this endpoint. For volunteer letters, the `parsed_data` includes volunteer information such as total hours, dates (start_date, end_date), position title, and optionally detailed hour entries with dates, hours, and descriptions for each volunteer activity. # Postman Collection Source: https://docs.truv.com/api-reference/postman Get started with Truv APIs using the Postman collection The Truv Postman Collection lets you get started with your integration with little to no code. It includes pre-configured requests, environment variables, and sample workflows. Run in Postman *** ## Set up Postman Download and install [Postman](https://www.postman.com/downloads/). Click the **Run in Postman** button above to fork the Truv API collection into your workspace. This imports both the collection and the Sandbox environment. *** ## Configure Postman The Truv Postman collection uses [Postman environment variables](https://learning.postman.com/docs/sending-requests/variables/managing-environments/) to simplify each API request. In the top right corner of Postman, select the **Sandbox** environment. Click the eye icon to open the environment settings. Copy your Truv API keys from the [Dashboard API Keys page](https://dashboard.truv.com/app/development/keys) into the environment variables: * `client_id`: your Client ID * `access_key`: your Access Secret Save your changes and start making API requests. *** ## Sample workflow Requests have pre-configured pre-request and post-response scripts that pass data between steps automatically. ### VOIE verification Run **Create an Order - VOIE (Basic)**. In the response body, click the `shareURL` to complete the order in Truv Bridge. Run **Get an Order by ID**. The `orderId` from step 1 is stored as a variable and passed through automatically. Run **Get a VOIE Report by ID**. The `user_id` and `voie_report_id` variables from the prior response are stored and passed through automatically. # Retrieve recurring transactions (inflows and outflows) for a user Source: https://docs.truv.com/api-reference/recurring-transactions/applicant-recurring-transactions GET /v1/users/{user_id}/transactions/recurring/ Returns recurring transaction patterns detected across the user's linked bank accounts, split into recurring outflows (subscriptions, bills, and other recurring expenses) and recurring inflows (salary, benefits, and other recurring income sources). # The Task Refresh object Source: https://docs.truv.com/api-reference/refresh/object View information about data refresh endpoints for Links. Refresh data from an existing **Link** with the data refresh endpoints. These let the user bypass entering their payroll credentials a second time. ## Perform a data refresh Follow the steps below to perform a data refresh. 1. \[Optional] Subscribe to Webhooks for completed **Task**s with `done` status. Pull payroll data for the data refresh information. 2. Use the [Create a data refresh task](/api-reference/refresh/refresh_task_create) endpoint with the **access\_token** from the original connection. 3. Use webhooks, the [Retrieve a data refresh status](/api-reference/refresh/refresh_task) endpoint, or both to check the status of the refresh. Each data refresh **Task** is billed individually as a separate verification. ## Authorization validity The success of a refresh depends on whether the original connection is still authorized: | Connection type | Typical validity | Notes | | ------------------------------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------- | | OAuth-based (e.g., most payroll providers) | \~180 days | Token expires after roughly 6 months. After expiration, the user must re-authenticate through Truv Bridge. | | Session-based | Varies by provider | Some providers maintain sessions for weeks, others for months. No fixed guarantee. | For programs with **quarterly review cycles**, refresh success rates are high because most connections remain active within the 180-day window. For **annual review cycles**, expect most connections to have expired, requiring the user to re-authenticate. ## VOA refreshes from POS integrations If the initial VOA verification was completed through a point-of-sale integration (e.g., SimpleNexus, Blend), the refresh still works via the Order Refresh API as long as the original connection is active. Use the `access_token` from the initial order to create the refresh task. ## Refresh rate limits Truv has rate limits on each **access\_token** value. Within a 24-hour period, only an initial request and 3 refreshes are allowed. The `Refresh limit for the access_token exceeded` error occurs for any requests outside of the interval and limit. ## Attributes The sections below cover values from Data Refresh endpoints. ### Data refresh task The information below is for the response from data refresh tasks for a Link. | Attribute | Type | Description | | :-------- | :----- | :----------------------------------- | | task\_id | string | Unique ID for Link data refresh task | ### Data refresh status The values in the table below are for the status of a data refresh. | Attribute | Type | Description | | :------------ | :----- | :----------------------------------------------------------------- | | id | string | Unique refresh task ID | | created\_at | string | Time when refresh task was created | | refresh\_date | string | ~~Date of data refresh~~ **(Deprecated, invalid datetime format)** | | status | string | Data refresh task status | *** ## Endpoints These endpoints are from the Data refresh API. * [Create a data refresh task](/api-reference/refresh/refresh_task_create) * [Retrieve a data refresh status](/api-reference/refresh/refresh_task) *** ## Example responses The JSON objects below are sample responses for the endpoints. **Create a data refresh** ```json theme={null} { "task_id": "48427a36d43c4d5aa6324bc06c692456" } ``` **Retrieve a data refresh** ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "created_at": "2021-04-06T11:30:00Z", "refresh_date": "2020-03-10", "status": "new" } ``` # Retrieve a data refresh status Source: https://docs.truv.com/api-reference/refresh/refresh_task GET /v1/refresh/tasks/{task_id}/ The endpoint returns the refresh task status. # Create a data refresh task Source: https://docs.truv.com/api-reference/refresh/refresh_task_create POST /v1/refresh/tasks/ The endpoint creates a link data refresh task. # Report Sizes Source: https://docs.truv.com/api-reference/report-sizes Typical and long-tail payload sizes for Truv reports, so you can plan storage, request timeouts, and bandwidth. Use this page to size storage, request timeouts, and ingestion buffers for Truv report endpoints. PDFs are predictable and bounded. JSON payloads — especially for assets and AIM — tail to **multiple megabytes** at the long tail. Size your reads accordingly. *** ## Sizes by report Tap a report to see size distributions for each format it returns. Use the **max** and **p99** columns to drive buffer and timeout sizing for the formats you fetch. Returned by [VOIE report retrieve](/api-reference/user-income-and-employment-reports/users_get_report). | Format | p50 | p90 | p95 | p99 | max | | :----- | :------ | :------- | :------- | :------ | :------ | | pdf | 17.2 KB | 19.5 KB | 21.9 KB | 26.3 KB | 40.3 KB | | json | 46.7 KB | 661.9 KB | 801.7 KB | 1.2 MB | 1.3 MB | Returned by [Assets report retrieve](/api-reference/user-asset-verification-reports/assets-report-retrieve). | Format | p50 | p90 | p95 | p99 | max | | :----- | :------- | :------- | :------- | :------- | :------- | | pdf | 39.4 KB | 87.4 KB | 167.9 KB | 298.4 KB | 306.8 KB | | json | 131.6 KB | 599.3 KB | 1.4 MB | 2.9 MB | 3.4 MB | Returned by [Assets report retrieve](/api-reference/user-asset-verification-reports/assets-report-retrieve). The raw JSON variant carries account-level detail and is the largest format Truv produces — start your buffer and timeout sizing here. | Format | p50 | p90 | p95 | p99 | max | | :------- | :------- | :------ | :------ | :--------- | :---------- | | pdf | 24.2 KB | 24.5 KB | 24.6 KB | 24.7 KB | 24.7 KB | | json | 33.9 KB | 34.8 KB | 34.9 KB | 35.4 KB | 35.4 KB | | raw json | 463.5 KB | 2.4 MB | 4.1 MB | **9.9 MB** | **10.9 MB** | Returned by [Assets report retrieve](/api-reference/user-asset-verification-reports/assets-report-retrieve). Multi-megabyte even at the median. | Format | p50 | p90 | p95 | p99 | max | | :----- | :------- | :----- | :----- | :----- | :----- | | json | 784.7 KB | 2.7 MB | 3.5 MB | 6.1 MB | 6.4 MB | Returned by [Assets report retrieve](/api-reference/user-asset-verification-reports/assets-report-retrieve). Typical payload is small, but the long tail reaches >1 MB on borrowers with deep transaction history. | Format | p50 | p90 | p95 | p99 | max | | :----- | :----- | :----- | :----- | :------- | :----- | | json | 3.0 KB | 5.5 KB | 9.0 KB | 512.8 KB | 1.6 MB | Returned by [Income Insights retrieve](/api-reference/income-insights/income-insights-report-retrieve). Single-link income summary. | Format | p50 | p90 | p95 | p99 | max | | :----- | :------ | :------ | :------ | :------ | :------ | | pdf | 24.9 KB | 34.3 KB | 34.4 KB | 39.5 KB | 42.8 KB | Returned by [Assets report retrieve](/api-reference/user-asset-verification-reports/assets-report-retrieve). Verifies employment from deposit patterns when a direct payroll connection isn't available. | Format | p50 | p90 | p95 | p99 | max | | :----- | :------ | :------- | :------- | :------- | :------ | | pdf | 20.0 KB | 32.0 KB | 36.3 KB | 45.8 KB | 77.3 KB | | json | 62.7 KB | 213.8 KB | 267.2 KB | 722.3 KB | 1.8 MB | *** ## Planning guidance **Buffers.** Most clients default to a 1 MB or 5 MB response buffer. The JSON payloads for Freddie AIM Check (raw), Freddie Mac VOA Submission, and the VOA Report regularly exceed those at p95+. Set client read buffers to at least **16 MB** for the AIM raw JSON and **8 MB** for the VOA and Freddie VOA JSON to avoid truncation under the long tail. **Timeouts.** Default HTTP client timeouts of 10–15 seconds can truncate raw-JSON downloads on slower connections. For the multi-megabyte JSON payloads above, set a request timeout of at least **60 seconds** (longer if your client runs from a constrained network). PDFs and the smaller JSON variants are well-served by default timeouts. For capacity planning, multiply your monthly report volume by the per-report average. The four heaviest payloads: Freddie Mac VOA Submission JSON \~1.2 MB, Freddie AIM Check raw JSON \~1.1 MB, VOA Report JSON \~306 KB, VOIE Report JSON \~192 KB. Every other format averages under 60 KB. Across all formats the cross-cutting average is \~255 KB per report. A workflow that pulls VOIE JSON + VOIE PDF + AIM raw JSON + Freddie VOA JSON averages \~2.5 MB per completed verification. The Freddie AIM Check raw JSON has a >1 MB average and a 10.9 MB max. If you only need the AIM check decision and not the raw account-level detail, download the standard JSON variant of the AIM Check instead — it is \~30× smaller and bounded around 35 KB. PDFs are uniformly small and predictable (typically under 100 KB). JSON formats carry transaction-level data, which scales with `days_requested` and account count. If you only need a human-readable artifact, request the PDF format to avoid the JSON tail. *** ## Next steps Retrieval patterns and Encompass field mappings Get notified when a report is ready instead of polling How Truv assembles report data Connect the Truv MCP server to your AI tooling # The Scoring Attributes Report object Source: https://docs.truv.com/api-reference/scoring-attributes/object View more information about scoring attribute reports. Scoring Attributes reports provide cash-flow metrics, derived income streams, and risk scores based on a consumer's bank transaction history. Use these reports for credit decisioning, underwriting verifications, and retroactive analytics. ## Attributes The report response includes the following attributes. | Attribute | Type | Description | | :------------------- | :--------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | report\_id | string | Unique guid generated by scoring attributes API for identifying report | | source\_guid | string | Only applicable for refresh reports and existing customer refresh reports, new customer reports return `null`, unique guid of prior Scoring Attributes report for customer, returns most recent successful report for customers with multiple reports, the Refresh Report endpoint uses this report's transactions as starting point | | refresh | Boolean | Status of refresh report | | lender\_reference | string | Value for lender to identify report request, e.g. loan application number | | customer\_identifier | string | Customer-level unique identifier, *NOTE: Do not use personally identifiable information such as SSN or government ID numbers.* | | purpose | string | Purpose of report, valid values are below:
`decisioning` - FCRA credit decisioning
`verification` - Non-FCRA underwriting verifications
`analytics` - Retroactive reports for analytical purposes only | | status | string | Terminal statuses are:
`success`, `failed`, `data_import_error`
A status of `processing` indicates that the report is still being processed. An additional call should be made to the GET endpoint until a terminal status is returned. | | cutoff\_date | string | Latest date of financial activity included in report, typically set to current date or application date, date is in the past for retro-scored reports | | created\_at | string | Date and time of report request | | updated\_at | string | Date and time of report update | | alerts | array of objects | Values present when notifying lender of specific conditions, conditions do not prevent report completion, see [Alerts object](#alerts-object) | | scores | array of objects | Generic or custom scores, only report purpose-applicable scores are returned, see [Scores object](#scores-object) | | metrics | array of objects | See [Metrics object](#metrics-object) | | derived\_incomes | array of objects | See [Derived Incomes object](#derived-incomes-object) | *** ## Alerts object Each alert includes the following fields. | Attribute | Type | Description | | :---------- | :------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | alert\_code | integer | Integer indicating alert type, see message field for valid values | | message | string | Message describing alert condition, valid values and alert codes below
`1` - No consistent income sources present
`2` - No consistent payment streams present
`3` - Short transaction history
`4` - Low transaction activity
`5` - Unable to calculate daily balances for all accounts
`6` - Accounts with stale ending balances are present
`7` - Low ratio of debit activity | *** ## Scores object Each score includes the following fields. | Attribute | Type | Description | | :-------- | :------ | :----------------- | | name | string | Model name | | version | float | Model version | | value | integer | Scaled score value | *** ## Metrics object Each metric includes the following fields. | Attribute | Type | Description | | :----------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | name | string | Metric name, not including period of time | | time\_period | string | Abbreviation for time period of metric, valid values below:
`1m_l0` - Last month
`2m_l0` - Last 2 months
`3m_l0` - Last 3 months
`4m_l0` - Last 4 months
`6m_l0` - Last 6 months
`1w_l0` - Last week
`2w_l0` - Last 2 weeks
`2m_l2` - 2 months (2 month delay)
`2m_l4` - 2 months (4 month delay)
`4m_l2` - 4 months (2 month delay)
`1m_l1` - 1 month (1 month delay)
`2w_l2` - 2 weeks (2 week delay)
`0m_l0` - Current snapshot
`0m_l2` - Snapshot from 2 months ago
`0m_l4` - Snapshot from 4 months ago
`lftm` - Lifetime
`2m_to_1m` - Change from 2 months ago to current month
`3m_to_1m` - Change from 3 months ago to current month | | short\_name | string | Abbreviated form of metric name combined with time period | | unit | string | Measurement type for metric, valid fields `dollars`, `percent`, `boolean`, `count` | | value | number | Numeric value of metric, can contain null values, `null` is not `0` and must be properly parsed
For amounts, returns dollar value with decimals indicating cents, such as `2.99`
For percentages, returns an integer, for example 5% is `5`
For Booleans, `True` is represented as `1` and `False` is represented as `0`
For `counts` such as number of consistent payments, returns integers | *** ## Derived incomes object Each derived income stream includes the following fields. | Attribute | Type | Description | | :------------------- | :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | description | string | Normalized description for derived income stream, for sensitive information within description, such as health information, description returns as `REDACTED` | | frequency | string | Frequency of income stream, possible values are `monthly`, `semi_monthly`, `bi_weekly`, `weekly` | | days | array | Day or days of week or month for recurring deposits
For `monthly` and `semi-monthly` frequencies, returns day of the month and `-1` indicates end of month
For `weekly` and `bi_weekly` frequencies, returns day of week where `1` indicates Monday and `7` indicates Sunday | | formatted\_frequency | string | Frequency combined with recurrence days | | months | number | Longest period income stream has been recurring from report date
Income streams are only evaluated on whole months and 2, 3, 4 and 6 month intervals | | average\_amount | double | Average amount of each deposit in covered monthly interval | | monthly\_amount | double | Projected monthly amount based on average amount and occurrence frequency | *** ## Endpoints Use the endpoints below to get information on reports for scoring attributes. * [Create a scoring attributes report](/api-reference/scoring-attributes/scoring-attributes-report-create) * [Retrieve a scoring attributes report](/api-reference/scoring-attributes/scoring-attributes-report-retrieve) *** ## Example response ```json theme={null} { "report_id": "string", "source_guid": "2f918810e4b911edb5ea0242ac120002", "refresh": true, "lender_reference": "appl-1234", "customer_identifier": "cust-9999", "purpose": "decisioning", "status": "success", "cutoff_date": "2021-03-31", "created_at": "2022-03-16 12:56:15 -0700", "updated_at": "2022-03-16 12:56:17 -0700", "alerts": [ { "alert_code": 1, "message": "No consistent income sources present" } ], "scores": [ { "name": "Overdraft Risk Score", "version": 1, "value": 750 } ], "metrics": [ { "name": "derived_nsf_fee_amount", "time_period": "2m_l0", "short_name": "drvd_nsf_fee_amt_2m_l0", "unit": "dollars", "value": 23.99 } ], "derived_incomes": [ { "description": "direct deposit from xyz company", "frequency": "semi_monthly", "days": [15, -1], "formatted_frequency": "Semi-Monthly (15, eom)", "months": 3, "average_amount": 475.99, "monthly_amount": 1003.21 } ] } ``` # Create a scoring attributes report Source: https://docs.truv.com/api-reference/scoring-attributes/scoring-attributes-report-create POST /v1/scoring_attributes/reports # Retrieve a scoring attributes report Source: https://docs.truv.com/api-reference/scoring-attributes/scoring-attributes-report-retrieve GET /v1/scoring_attributes/reports/{report_id} # Security Source: https://docs.truv.com/api-reference/security Overview of Truv security, privacy, compliance, webhook security, and mTLS Truv supports security controls for regulated integrations, including webhook signature verification, mutual TLS (mTLS) for APIs and webhooks, and additional authentication options for webhook delivery. User consent, secure transport, compliance materials, and where to request documentation. Signature verification, delivery timing, retries, and webhook allowlisting guidance. Mutual TLS for Truv APIs and webhook delivery, including certificate setup paths. Current security documents, reports, and questionnaires. *** ## Webhook signature verification Every webhook request from Truv includes an `X-WEBHOOK-SIGN` header. Validate that signature against the raw request body with your Access Secret before you process the event. Use [Webhook Security](/api-reference/webhooks#security) for verification examples, retry behavior, IP allowlisting, and handling guidance. *** ## mTLS API endpoints Mutual TLS (mTLS) enhances standard TLS by requiring both the client and the server to authenticate each other using digital certificates. This ensures only trusted parties can establish communication with Truv's API. | Environment | Endpoint | | -------------- | --------------------------- | | **Production** | `api-mtls.truv.com` | | **Sandbox** | `api-sandbox-mtls.truv.com` | *** ## Set up mTLS for APIs Create a Certificate Signing Request using X.509v3 format with RSA or ECDSA keys and SHA256: ``` CN: api-mtls..truv.com O: Truv Inc L: Miami ST: Florida C: US ``` Truv will issue a signed certificate valid for one year. ```bash theme={null} curl --cert $CERT.pem --key $PRIVATE_KEY.key https://api-mtls.truv.com/v1/orders/ ``` Allow Truv's IP addresses through your firewall: **Production:** `35.167.32.174`, `35.165.53.192`, `54.71.147.242` **Sandbox:** `44.235.37.104`, `35.83.220.165`, `52.38.209.190` Work with Truv Support to enable mTLS on your account. *** ## mTLS for webhooks Truv supports mTLS for webhook communication. The following authentication approaches are available: ### Truv's signed certificate Configure the public certificate from `mtls-prod.truv.com` on your webhook endpoint to verify that requests originate from Truv. ### Client-signed certificate Truv submits a CSR and you issue a signed certificate. Truv then uses your certificate when delivering webhooks to your endpoint. ### OAuth 2.0 (optional) Truv supports OAuth 2.0 authentication when invoking webhooks. Truv obtains access tokens for secure webhook delivery. Contact Truv Support to configure OAuth settings. ### Custom headers You can configure custom headers (Client ID and Client Secret) on webhook deliveries for an additional authentication layer. Work with Truv Support to configure. For the source IP addresses Truv uses to deliver webhooks, see [Webhook Security](/api-reference/webhooks#originating-ip-addresses). *** ## Privacy and compliance Truv's privacy and compliance documentation centers on three practical areas: * explicit end-user consent before data access * secure transport for all API communication * current audit reports, questionnaires, and supporting materials through the Trust Center and compliance contacts ### User consent Access to end-user data requires explicit user consent through the Truv connection flow. Users authenticate directly with their provider and authorize access to the requested data before Truv returns verification results. Use your implementation to make that consent flow clear to end users and request only the data required for your use case. ### Secure transport All API traffic must use HTTPS with TLS 1.2 or higher. For integrations with stricter authentication requirements, Truv also supports [mTLS](#mtls-api-endpoints) for public API traffic and webhook delivery. ### Data handling expectations Use the same controls you would apply to other sensitive verification data: * keep API credentials in environment variables or a secrets manager * restrict access to verification data to the systems and roles that need it * define retention windows that match your business and regulatory requirements * log access to sensitive data and security-relevant events for auditability Implementation details for credential handling and webhook verification live in [Webhook Security](/api-reference/webhooks#security). ### Compliance highlights * SOC 2 Type II certified with continuous monitoring * Regular internal and external network penetration testing and third-party code reviews * Role-based access controls enforced at each layer of infrastructure * Multi-factor authentication required for access to Truv infrastructure * All application and user access logs stored centrally and monitored * Sensitive data encrypted with an additional layer beyond standard TLS ### Compliance materials For current security documents, questionnaires, and supporting materials, use the [Truv Trust Center](https://trust.truv.com/) or contact the Truv compliance team at [compliance@truv.com](mailto:compliance@truv.com). *** ## Contact [security@truv.com](mailto:security@truv.com) [compliance@truv.com](mailto:compliance@truv.com) # Shift Webhook Events Source: https://docs.truv.com/api-reference/shifts/events Webhook events for shift data creation and updates. Subscribe to these events via [Webhooks](/api-reference/webhooks) to receive notifications when shift data becomes available or changes during a refresh. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Shift events on this page also include these fields: | Field | Description | | --------------- | ------------------------------------------------------------------------------ | | `link_id` | Identifier of the Link | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | | `task_id` | The associated Task | | `employment_id` | The associated employment record | | `objects_count` | Number of shifts retrieved | *** ## shifts-created Fires when shift data has been extracted. This occurs for any successful non-refresh [Task](/api-reference/tasks/object). Multiple responses are sent when additional shifts are found. ```json theme={null} { "webhook_id": "f82ab0a92ddd4bb7b6117635159b366a", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "shifts-created", "event_created_at": "2022-08-23T17:32:24.812306Z", "objects_count": 1, "employment_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## shifts-updated Fires when the shift count changes during a refresh Task. For example, if a person had 8 shifts and now has 9. ```json theme={null} { "webhook_id": "f82ab0a92ddd4bb7b6117635159b366a", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "shifts-updated", "event_created_at": "2022-08-23T17:32:24.812306Z", "objects_count": 1, "employment_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` # List all shifts Source: https://docs.truv.com/api-reference/shifts/link-shifts GET /v1/links/{link_id}/shifts/ The endpoint returns ongoing and completed work shifts. It includes time entries (clock in/clock out), the type of work, and earnings. # The Shifts object Source: https://docs.truv.com/api-reference/shifts/object Learn more about information related to ongoing and completed work shifts. The Shifts endpoint includes time entries such as clock in and clock out, the type of work, and earnings. Shifts is related to the `link_id` from Truv's Income and Employment API. ## Attributes The values in the table below cover attributes of Shifts. | Attribute | Type | Description | | :---------------------------- | :--------------------- | :------------------------------------------------------------------------------------------------- | | count | integer | Total number of results | | next | string, null | Link to next page | | previous | string, null | Link to previous page | | results | array of objects | List of shifts | | id | string | Unique ID of shifts | | external\_id | string | External ID of selected shifts | | created\_at | string | Shift creation timestamp | | updated\_at | string | Shift update timestamp | | start\_date | string | Shift start date | | end\_date | string | Shift end date | | time\_entries | array of objects | List of shift-related time entries | | time\_entries\[].id | string | Unique time entry ID | | time\_entries\[].external\_id | string | Time entry external ID | | time\_entries\[].created\_at | string | Time entry creation timestamp | | time\_entries\[].updated\_at | string | Time entry update timestamp | | time\_entries\[].entry\_date | string | Entry date of event in time tracking system | | time\_entries\[].start | string | Date and time when work shift started | | time\_entries\[].end | string | Date and time when work shift ended | | earnings | array of objects | Aggregated earnings for shift | | earnings\[].name | string | Name of earnings (required) | | earnings\[].amount | string (decimal) | Amount of earnings (required) | | earnings\[].category | string | Category of earnings (required), one of: `regular`, `overtime`, `bonus`, `commission`, `other_pay` | | earnings\[].rate | string (decimal), null | Rate of earnings | | earnings\[].units | string (decimal), null | Units of earnings | | type | string | Type of shift, four types of shifts available: `other`, `delivery`, `rideshare`, `shift` | *** ## Endpoint The item below is the available endpoint for Shifts. * [List all shifts](/api-reference/shifts/link-shifts) *** ## Example response The response object below is the returned JSON value. ```json theme={null} { "count": 0, "next": null, "previous": null, "results": [] } ``` # Pay Statement Webhook Events Source: https://docs.truv.com/api-reference/statements/events Webhook events for pay statement creation and updates. Subscribe to these events via [Webhooks](/api-reference/webhooks) to receive notifications when pay statements become available or change during a refresh. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Pay Statement events on this page also include these fields: | Field | Description | | --------------- | ------------------------------------------------------------------------------ | | `link_id` | Identifier of the Link | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | | `task_id` | The associated Task | | `employment_id` | The associated employment record | | `objects_count` | Number of statements retrieved | *** ## statements-created Fires when pay statements have been retrieved. This occurs once per [Link](/api-reference/links/object) for each non-refresh [Task](/api-reference/tasks/object) completion. ```json theme={null} { "webhook_id": "f82ab0a92ddd4bb7b6117635159b366a", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "statements-created", "event_created_at": "2022-08-23T17:32:24.812306Z", "objects_count": 9, "employment_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` *** ## statements-updated Fires when the statement count changes during a refresh Task. For example, if a person had 31 pay stubs and now has 32. ```json theme={null} { "webhook_id": "f82ab0a92ddd4bb7b6117635159b366a", "task_id": "c32fb957ec7246828da56be7516da765", "link_id": "9915c50cc047413bb810767f218390f8", "product": "employment", "data_source": "payroll", "tracking_info": null, "event_type": "statements-updated", "event_created_at": "2022-08-23T17:32:24.812306Z", "objects_count": 10, "employment_id": "427abebd8590457e8332fdff77fc412f", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc" } ``` # List all statements Source: https://docs.truv.com/api-reference/statements/link-statements GET /v1/links/{link_id}/statements/ The endpoint returns a list of pay statements with dates, gross pay, net pay and earnings with deductions breakdown. # The Pay Statements object Source: https://docs.truv.com/api-reference/statements/object View information from pay statements such as dates, gross pay, net pay, and earnings with deductions. The pay statement endpoints return a list of pay statements with attribute object breakdowns. The statement is related to the `link_id` from Truv's Income and Employment API. ## Attributes The table below covers the values for pay statements. | Attribute | Type | Description | | :-------------------- | :--------------- | :--------------------------------------------------------------------------------- | | id | string | Unique ID of selected statement | | check\_number | string | External ID of pay stub from payroll provider | | pay\_date | date | Pay date | | net\_pay | string | Net pay | | net\_pay\_ytd | string | Net pay year to date | | gross\_pay | string | Gross pay | | gross\_pay\_ytd | string | Gross pay year to date | | bonus | string | Bonus amount | | commission | string | Commission amount | | hours | string | Total work hours during a pay period | | basis\_of\_pay | string | Basis of pay: `S` - Salary, `H` - Hourly, `D` - Daily, `W` - Weekly, `M` - Monthly | | period\_start | date | Pay period start | | period\_end | date | Pay period end | | regular | string | Regular salary | | regular\_ytd | string | Regular salary year to date | | other\_pay\_ytd | string | All other pay forms year to date | | bonus\_ytd | string | Bonus year to date | | commission\_ytd | string | Commission year to date | | overtime | string | Overtime pay | | overtime\_ytd | string | Overtime pay year to date | | other\_pay | string | Other pay | | earnings | array of objects | Earnings for pay cycle by type | | earnings\_ytd | array of objects | Earnings year to date | | deductions | array of objects | Deductions for the pay cycle by type | | deductions\_ytd | array of objects | Deductions by type year to date | | md5sum | string | MD5 hash value computed based on file content | | file | url | Link to pay stub file (up to 2048 characters long) | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | ### Earnings object Each item in `earnings` and `earnings_ytd` has this shape. | Attribute | Type | Description | | :-------- | :----- | :---------------------------------------------------------------- | | name | string | Name of the earning | | amount | string | Amount of the earning | | category | string | One of: `regular`, `overtime`, `bonus`, `commission`, `other_pay` | | rate | string | Rate of the earning (nullable) | | units | string | Units for the earning (nullable) | ### Deductions object Each item in `deductions` and `deductions_ytd` has this shape. | Attribute | Type | Description | | :-------- | :----- | :-------------------------------------------------------------------------------------------------------------------- | | name | string | Name of the deduction | | amount | string | Amount of the deduction | | category | string | One of: `memo`, `medicare`, `retirement`, `socialsec`, `federal`, `state`, `benefit`, `garnishment`, `local`, `other` | *** ## Endpoints View the available endpoints for pay statements below. * [List all statements](/api-reference/statements/link-statements) * [Retrieve a statement](/api-reference/statements/retrieve-statement) *** ## Example response The JSON below is a sample response from the endpoint. ```json theme={null} { "id": "970c13c479b14f41b0b6a991ee8819f6", "pay_date": "2021-10-22", "net_pay": "1515.61", "net_pay_ytd": "35398.31", "gross_pay": "2153.85", "gross_pay_ytd": "45500.00", "bonus": null, "commission": null, "hours": "80.00", "basis_of_pay": "S", "period_start": "2021-10-03", "period_end": "2021-10-16", "regular": "2153.85", "regular_ytd": "42000.00", "bonus_ytd": "500.00", "commission_ytd": null, "overtime": null, "overtime_ytd": null, "other_pay": null, "other_pay_ytd": "3000.00", "earnings": [ { "name": "Regular", "category": "regular", "amount": "2153.85", "rate": "2153.85", "units": "72.00" } ], "earnings_ytd": [ { "name": "Regular", "category": "regular", "amount": "42000.00", "rate": null, "units": null }, { "name": "Spot Award", "category": "other_pay", "amount": "3000.00", "rate": null, "units": null }, { "name": "Bonus", "category": "bonus", "amount": "500.00", "rate": null, "units": null } ], "deductions": [ { "name": "Blue Ash Income Tax", "amount": "-26.94", "category": "local" }, { "name": "Medicare Tax", "amount": "-31.25", "category": "medicare" }, { "name": "CA State Income Tax", "amount": "-54.68", "category": "state" }, { "name": "Social Security Tax", "amount": "-133.63", "category": "socialsec" }, { "name": "Federal Income Tax", "amount": "-154.37", "category": "federal" }, { "name": "401K Dollars", "amount": "-237.37", "category": "retirement" } ], "deductions_ytd": [ { "name": "Federal Income Tax", "amount": "3639.64", "category": "federal" }, { "name": "Social Security Tax", "amount": "3090.03", "category": "socialsec" }, { "name": "401K Dollars", "amount": "2148.46", "category": "retirement" }, { "name": "CA State Income Tax", "amount": "1275.75", "category": "state" }, { "name": "Medicare Tax", "amount": "722.67", "category": "medicare" }, { "name": "Blue Ash Income Tax", "amount": "623.01", "category": "local" }, { "name": "Exp Repay", "amount": "-1397.87", "category": "benefit" } ], "md5sum": null, "file": null, "derived_fields": [], "missing_data_fields": [], "check_number": null } ``` # Retrieve a statement Source: https://docs.truv.com/api-reference/statements/retrieve-statement GET /v1/links/{link_id}/statements/{statement_id}/ Get the pay statement # Task Webhook Events Source: https://docs.truv.com/api-reference/tasks/events Webhook events for Task status changes and data object creation and updates Subscribe to these events via [Webhooks](/api-reference/webhooks) to track Task progress and data availability in real time. All webhook payloads include these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | All Task events on this page also include these fields: | Field | Description | | --------------- | -------------------------------------------------------------------------------- | | `task_id` | The Task identifier | | `link_id` | Account connection ID (use to retrieve `access_token`) | | `product` | The product the event relates to, such as `income`, `employment`, or `assets` | | `data_source` | Source of data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | `tracking_info` | Custom metadata passed via `bridge_token` (nullable) | | `status` | Current task status (see [Connection Lifecycle](/api-reference/tasks/lifecycle)) | | `updated_at` | Time event occurred | | `template_id` | Associated template, if applicable (nullable) | *** ## task-status-updated Fires for each Task status change during the connection lifecycle. This is the primary event for tracking verification progress. ```json theme={null} { "webhook_id": "488f424096d3461aa0e4cf11a985f6df", "task_id": "521442a087604e599c637db310d07402", "link_id": "d39d86dcc20c46e0ae75ba9ab1311a21", "product": "income", "data_source": "payroll", "tracking_info": null, "event_type": "task-status-updated", "event_created_at": "2022-08-24T13:55:12.845645Z", "updated_at": "2022-08-24T13:55:12.845666+00:00", "status": "done", "user_id": "88fef4cea64c40b5ad6727cc9b0b9fdc", "template_id": null } ``` When `status` is `done`, all data has been downloaded and processed. This is when you should fetch verification reports. # Task Lifecycle Source: https://docs.truv.com/api-reference/tasks/lifecycle How tasks progress through the flow: statuses, errors, and processing timelines When a user authenticates through [Truv Bridge](/developers/integration/bridge-widget/overview), the system creates a **Link**, a persistent connection to their payroll provider or bank. Each Link has a unique `access_token` that enables all subsequent data retrieval and modifications. **Tasks** are the individual actions performed through Links (e.g., fetching income data, switching direct deposits). Each task progresses through a defined status lifecycle. *** ## Task status flow Every task authenticates through the Link first, then follows one of two paths depending on its type. A task may skip `mfa` when the provider doesn't require multi-factor authentication. ### Standard tasks A standard task collects data from the connected account: ``` new → login → mfa → parse → full_parse → done ``` ```mermaid theme={null} flowchart TD N[new] --> LG[login] LG -->|login_error| E[error] LG --> MFA[mfa] LG -->|no MFA required| P[parse] MFA -->|mfa_error| E MFA --> P P -->|error| E P --> FP[full_parse] FP --> D[done] classDef active fill:#2C64E3,stroke:#1E4BB8,color:#FFFFFF classDef error fill:#DC2626,stroke:#B91C1C,color:#FFFFFF class N,LG,MFA,P,FP,D active class E error ``` ### DDS tasks A Direct Deposit Switch task replaces `parse` and `full_parse` with `switch_deposit`: ``` new → login → mfa → switch_deposit → done ``` ```mermaid theme={null} flowchart TD N[new] --> LG[login] LG -->|login_error| E[error] LG --> MFA[mfa] LG -->|no MFA required| SD[switch_deposit] MFA -->|mfa_error| E MFA --> SD SD -->|error| E SD --> D[done] classDef active fill:#2C64E3,stroke:#1E4BB8,color:#FFFFFF classDef error fill:#DC2626,stroke:#B91C1C,color:#FFFFFF class N,LG,MFA,SD,D active class E error ``` *** ## Status definitions | Status | Description | | ------------------- | --------------------------------------------------------------------------------------------- | | **new** | Task initiated, queued for processing | | **login** | Attempting to log into the payroll provider or bank | | **mfa** | Completing multi-factor authentication | | **parse** | Collecting identity, employment, and paystub data | | **full\_parse** | Initial parse complete; downloading and parsing paystubs, W-2s, and additional income sources | | **switch\_deposit** | Processing direct deposit allocation changes (DDS tasks only) | | **done** | Task completed successfully | *** ## Error states Tasks may enter an error state at any point in the lifecycle: | Error status | Description | Recommended action | | --------------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **login\_error** | Authentication failed: incorrect credentials | Prompt the user to re-authenticate via [Bridge Update Mode](/developers/integration/bridge-widget/returning-user) | | **mfa\_error** | Multi-factor authentication was not completed | Prompt the user to retry, or offer document upload as fallback | | **config\_error** | Provider integration or configuration issue. Also raised when uploaded documents fail fraud/tampering checks. | Fetch the task record for the specific `error_message`. For document tampering, see [Fraud & Manual Review](/developers/fraud-and-manual-review). | | **account\_locked** | The payroll or bank account is locked | Ask the user to unlock their account directly with the provider before retrying | | **unable\_to\_reset** | Failed to reset credentials at the provider | Route the user to manual verification | | **no\_data** | Provider connected successfully but returned no data | Offer document upload as fallback. Do not treat as verified \$0 income. | | **unavailable** | Provider service is temporarily inaccessible | Retry later or route to document upload. Not user-fixable. | | **not\_supported** | Provider or HRIS system is not supported | Inform the user and offer document upload | | **error** | Generic connection failure | Log the `task_id` and contact support if the error persists | Subscribe to [`task-status-updated` webhooks](/api-reference/webhooks) to receive error states in real time. See [Task Webhook Events](/api-reference/tasks/events) for the full list of task events. *** ## Data processing See [Data Processing](/api-reference/data-processing) for stage timing, median durations, data availability at each stage, and typical processing times. *** ## Relationship to Orders [Orders](/api-reference/orders/object) are the top-level containers for verification requests. When a user completes an Order: 1. The user authenticates through Bridge, creating a **Link** 2. A **Task** is created on that Link to retrieve the requested data 3. The Task progresses through the status lifecycle 4. On completion, data is available via the API and the order status updates A single Order can have multiple connections (e.g., a borrower connecting two employers), each with their own Link and Tasks. *** ## Monitor tasks ### Dashboard View task details in the Dashboard under **Activity > Tasks**. Filter by status, date, and provider. ### API Retrieve task status programmatically: ```bash theme={null} curl -X GET "https://prod.truv.com/v1/tasks/?query={link_id}" \ -H "X-Access-Client-Id: your_client_id" \ -H "X-Access-Secret: your_secret" ``` ### Webhooks Subscribe to task events for real-time monitoring: * `task-status-updated` with `status: done`: task finished successfully * `task-status-updated` with an error status: task encountered an error # The Tasks object Source: https://docs.truv.com/api-reference/tasks/object A job created on a Link to pull, refresh, or update data in the linked account. A Task is a job created for a specific Link to pull, refresh, or update data in the linked account. Each task records its product type, data source, provider, and current processing status, and moves through the [task lifecycle](/api-reference/tasks/lifecycle). ## Attributes The attributes of Tasks are below. | Attribute | Type | Description | | :------------- | :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique ID of the task | | status | string | Current status of the task. See [Task Lifecycle](/api-reference/tasks/lifecycle) for all status values, error states, and recommended actions. | | product\_type | string | Type of data product being processed: `income`, `employment`, `deposit_switch`, `pll`, `insurance`, `transactions`, or `assets` | | provider | object | Data provider that served this task (see [Provider object](#provider-object)) | | created\_at | datetime | Timestamp when the task was created | | updated\_at | datetime | Timestamp when the task was last updated | | error\_message | string, null | Error details if task failed | | tracking\_info | string, null | Optional tracking information provided by partner | | bridge\_token | string, null | Bridge token used for authentication | | data\_source | string | Source of the verification data: `payroll`, `docs`, `insurance`, `financial_accounts`, or `tax` | | link\_id | string | ID of the associated Link (connection) | | is\_suspicious | boolean | Whether the task or link is flagged as suspicious | | user\_id | string | ID of the user associated with this task | | order\_id | string, null | ID of the order associated with this task | ### Provider object | Attribute | Type | Description | | :-------- | :----------- | :----------------------- | | id | string | Data provider ID | | name | string | Data provider name | | logo\_url | string (uri) | Data provider logo image | *** ## Endpoints The list below contains available endpoints for task management. * [List tasks](/api-reference/tasks/tasks_list) * [Retrieve a task](/api-reference/tasks/tasks_read) # List all tasks Source: https://docs.truv.com/api-reference/tasks/tasks_list GET /v1/tasks/ The endpoint returns a list of Tasks. # Retrieve a task Source: https://docs.truv.com/api-reference/tasks/tasks_read GET /v1/tasks/{id}/ The endpoint returns a Task. # The Tax Documents object Source: https://docs.truv.com/api-reference/tax/object Learn more about the reference information for Tax Documents. # Attributes The table below has the values for Tax Document fields. | Attribute | Type | Description | | :---------------- | :----------- | :---------------------------------------------------------------------------------------------------------------------- | | id | string | Unique identifier | | document\_type | string | Type of document. One of: W2, F1099, F1040 | | document\_subtype | string, null | Subtype of document (nullable). One of: F1099\_DIV, F1099\_G, F1099\_INT, F1099\_MISC, F1099\_NEC, F1099\_R, F\_SSA1099 | | file | uri | Link to tax document file, format is specified in the content-type (up to 2048 characters long) | | md5sum | string | MD5 hash value computed based on file content | | year | integer | Tax document year | | fields | object | Additional metadata for a specific document type | # Endpoint The link below is the reference for the available Tax Document endpoint. * [List all tax documents](/api-reference/tax/tax-documents) * [Retrieve a tax document](/api-reference/tax/tax-document) # Example responses The sample below is a JSON response for the endpoint. The sections below have different document type examples. ```json theme={null} [ { "id": "string", "document_type": "W2", "document_subtype": null, "file": "string", "md5sum": "string", "year": 2024, "fields": {...} // see below by form type } ] ``` ## W2 This payload response is an example of a W-2 form. ```json theme={null} { "federal_tax": "4102.75", "medicare_tax": "816.43", "medicare_wages": "58805.40", "social_security_tax": "3490.93", "social_security_wages": "58805.40", "wages": "56269.25" } ``` *** ## 1099 For all 1099 forms the year of the document along with user's information is provided. *** ## 1040 The 1040 tax document sample below is the example JSON payload. ```json theme={null} { "total_income": "1000.00" } ``` # Retrieve tax document Source: https://docs.truv.com/api-reference/tax/tax-document GET /v1/links/{link_id}/tax/{tax_id}/ The endpoint returns a tax document. # List all tax documents Source: https://docs.truv.com/api-reference/tax/tax-documents GET /v1/links/{link_id}/tax/ The endpoint returns a list of tax documents. # The Templates object Source: https://docs.truv.com/api-reference/templates/object Customization templates let you configure the design and text of Truv Bridge and your workflow. Find Truv **Templates** within the Customization section of your Dashboard. Configure Truv Bridge and your order flow for your specific product types when creating a customization template. For example, you can apply different branding and language according to your specific client needs. Your template configurations take priority over other settings, such as universal branding or those from **Truv Bridge** and **Order**s. ## Attributes View the payload for retrieving customizable template information. | Attribute | Type | Description | | :--------------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Unique identifier of template | | name | string | Template name | | products | array | List of products with applied customizable templates | | default\_for\_products | boolean | Status of customizable template as product default | | bridge | object | Configuration object for Truv Bridge template | | branding | object | Configuration object for branding template | | orders | object | Configuration object for Orders template | | document\_upload | object | Configuration object for Document upload template. Supported document types include `paystub`, `w2`, `f1099`, `f1040`, `insurance_home_policy`, `insurance_auto_policy`, `volunteer_letter`, `freddie_aim_check`, and `other` | | data | object | Settings for returned documents | | reports | object | Report settings, including Income Insights configuration | | data\_sources\_flow | object | Data source flow configuration | | created\_at | datetime | Timestamp for created customizable template | | updated\_at | datetime | Timestamp for updated customizable template | When the `other` document type is enabled in `document_upload`, end users can upload arbitrary documents that don't fit the other categories. Truv does not parse these documents into structured data (they are captured only) — you can collect the uploaded files through the [Uploaded Documents API](/api-reference/uploaded-documents/object) (`GET /v1/links/{link_id}/documents/`). *** ## Endpoints The table below covers the available endpoints for customizable templates. * [List all customizable templates](/api-reference/templates/templates_list) - GET /v1/templates/ * [Create a customizable template](/api-reference/templates/templates_create) - POST /v1/templates/ * [Retrieve a customizable template](/api-reference/templates/templates_read) - GET /v1/templates/\{template\_id}/ * [Update a customizable template](/api-reference/templates/templates_partial_update) - PATCH /v1/templates/\{template\_id}/ * [Delete a customizable template](/api-reference/templates/templates_delete) - DELETE /v1/templates/\{template\_id}/ *** ## What templates control Templates give you fine-grained control over the verification experience across several areas: | Area | Capabilities | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Bridge UI** | Customize search header and per-product success-screen text, and toggle the Truv logo and support button | | **Branding** | Set company logo, accent and background colors, custom end-user agreement, and privacy policy link | | **Communications** | Customize or suppress Truv-sent email and SMS notifications using `suppress_user_notifications`. Configure reminder timing, subject lines, and message text independently for first-touch and follow-up messages | | **Data & products** | Control which products are available for the template, configure document upload requirements (types, counts, required vs optional), and set report return preferences | | **Order pages** | Customize the hosted order landing page header, body text, FAQ visibility, and the success/expired screen content | To suppress all Truv-sent notifications and handle communications yourself, enable `suppress_user_notifications` in the template's `orders.notification_settings` configuration. Its companion field `first_notification_delay_hours` is ignored when suppression is on. *** ## Example response The `bridge.texts` object is deprecated. Use `bridge.product_settings` instead to configure per-product Bridge text; `texts` will be removed in a future version. View the JSON response example below. ```json theme={null} { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "My template", "products": ["income"], "default_for_products": false, "bridge": { "product_settings": [ { "product_type": "assets", "data_source": "financial_accounts", "texts": { "search_header": "Find your bank", "success_title": "Success!", "success_subtitle": "Your bank account has been connected", "success_cta": "Continue" } } ], "hide_truv_logo": false, "hide_support_button": false }, "branding": { "company_name": "string", "accent_color": "#aabb00", "background_color": "rgba(0, 0, 255, 0.5)", "hide_confetti": false, "custom_end_user_agreement": { "header": "string", "url": "string" } }, "orders": { "link_expiration": "24", "custom_field_title": "string", "support_email": "user@example.com", "first_sms": { "text": "string", "apply_for_reminder": false }, "reminder_sms": { "text": "string" }, "first_email": { "subject": "string", "header": "string", "button": "string", "caption": "string", "apply_for_reminder": false }, "reminder_email": { "subject": "string", "header": "string", "button": "string", "caption": "string" }, "landing": { "header": "string", "body": "string", "hide_faq": false, "success_screen": { "header": "string", "body": "string" }, "expired_screen": { "header": "string", "body": "string" } } }, "document_upload": { "is_enabled": true, "freddie_aim_check": { "is_enabled": true, "seller_id": "00601" }, "paystub": { "is_enabled": true, "is_required": true, "title": "Upload two most recent paystubs", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload two most recent paystubs?", "min_count": 2, "max_count": 5 }, "w2": { "is_enabled": true, "is_required": false, "title": "Upload two most recent W2s", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload two most recent W2s?", "min_count": 2, "max_count": 5 }, "f1099": { "is_enabled": true, "is_required": true, "title": "Upload two most recent 1099s", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload two most recent 1099s?", "min_count": 1, "max_count": 1 }, "f1040": { "is_enabled": true, "is_required": true, "title": "Upload most recent 1040", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload most recent 1040?", "min_count": 1, "max_count": 1 }, "insurance_home_policy": { "is_enabled": true, "is_required": true, "title": "Upload home insurance policy", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload policy?", "min_count": 1, "max_count": 1 }, "insurance_auto_policy": { "is_enabled": true, "is_required": true, "title": "Upload auto insurance policy", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload policy?", "min_count": 1, "max_count": 1 }, "volunteer_letter": { "is_enabled": true, "is_required": true, "title": "Upload volunteer letter and timesheet", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload volunteer letter and timesheet?", "min_count": 1, "max_count": 1 }, "other": { "is_enabled": true, "is_required": false, "title": "Upload supporting documents", "description": "PDF files only under 15 MB.", "button": "Upload", "submit_title": "Did you upload supporting documents?", "min_count": 1, "max_count": 1 } }, "data": { "paystubs_count": 6, "w2_count": 3, "paystubs_ytd_count": 3, "extended_history": { "statements_history_days": 180 } }, "reports": { "hidden_sections": { "deposits": false, "large_deposits": false, "historical_payment_summary": false }, "days_requested": 60, "large_deposit_threshold": 500, "transaction_categories": ["Food & Dining", "Travel", "Shopping"], "transaction_account_types": ["CHECKING", "SAVINGS"], "transaction_account_subtypes": ["FIXED_ANNUITY", "LOCKED_IN_RETIREMENT_ACCOUNT", "PLAN_401_A"], "income_insights": { "days_requested": 60, "consumer_report_permissible_purpose": "WRITTEN_INSTRUCTION_OTHER" } }, "data_sources_flow": { "employment": { "flow": "fallback", "data_sources": ["payroll", "docs"] }, "income": { "flow": "fallback", "data_sources": ["payroll", "financial_accounts"] }, "insurance": { "flow": "fallback", "data_sources": ["insurance", "docs"] } }, "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z" } ``` # Create a customization template Source: https://docs.truv.com/api-reference/templates/templates_create POST /v1/templates/ The endpoint creates a customization template. # Delete a customization template Source: https://docs.truv.com/api-reference/templates/templates_delete DELETE /v1/templates/{template_id}/ The endpoint deletes a customization template. # List all customization templates Source: https://docs.truv.com/api-reference/templates/templates_list GET /v1/templates/ The endpoint returns a list of all customization templates for user. # Update a customization template Source: https://docs.truv.com/api-reference/templates/templates_partial_update PATCH /v1/templates/{template_id}/ The endpoint updates a customization template. # Retrieve a customization template Source: https://docs.truv.com/api-reference/templates/templates_read GET /v1/templates/{template_id}/ This endpoint retrieves a customization template. # List all bank transactions Source: https://docs.truv.com/api-reference/transactions/link-bank-data-transactions GET /v1/links/{link_id}/transactions/ The endpoint allows developers to receive user-authorized transaction data. # The Transactions object Source: https://docs.truv.com/api-reference/transactions/object Transaction history from connected financial accounts. # Attributes The information in this table is for the top-level transactions response. | Attribute | Type | Description | | :----------- | :--------------- | :-------------------------------------------------------------------- | | count | integer | Total number of transactions | | next | uri | URL of the next page of results, `null` if none | | previous | uri | URL of the previous page of results, `null` if none | | accounts | array of objects | List of accounts, see [Accounts object](#accounts-object) | | transactions | array of objects | List of transactions, see [Transactions object](#transactions-object) | ## Accounts object Use the table below for reference to the account object values. | Attribute | Type | Description | | :---------- | :-------- | :----------------------------------------------------------- | | id | string | Unique identifier of account | | created\_at | date-time | Date and time account was created | | updated\_at | date-time | Date and time account was most recently updated | | type | string | Parent type of the account | | subtype | string | Account subtype | | mask | string | Last 4 digits of account number | | nickname | string | Alternate name for account | | balances | object | Balance information, see [Balances object](#balances-object) | ### Balances object Find information about the balances object values in the table below. | Attribute | Type | Description | | :----------------- | :----- | :----------------------- | | currency\_code | string | Currency | | balance | string | Balance amount | | available\_balance | string | Available balance amount | | credit\_limit | string | Credit limit | *** ## Transactions object The values in this table have information from the transactions object. | Attribute | Type | Description | | :----------------------- | :--------------- | :---------------------------------------------------------------------------- | | id | string | Unique identifier of transaction | | created\_at | date-time | Timestamp when transaction was created in Truv | | updated\_at | date-time | Timestamp when transaction was last updated in Truv | | account\_id | string | account\_id | | external\_id | string | External system transaction identifier | | amount | string | Monetary amount of transaction | | currency\_code | string | Three-character ISO 4217 currency code | | check\_number | string | Check number for transaction | | categories | array of strings | List of categories assigned to this transaction | | description | string | Human-readable transaction description | | status | string | Status of transaction, one of `POSTED`, `PENDING`, `AUTHORIZATION`, or `MEMO` | | type | string | Type of transaction, one of `CREDIT`, `DEBIT`, or `MEMO` | | posted\_at | date-time | Timestamp for movement of funds | | transacted\_at | date-time | Timestamp when transaction occurred | | memo | string | Additional descriptive information about transaction | | merchant\_name | string | Merchant name extracted from the transaction description (nullable) | | merchant\_category\_code | number | ISO 18245 category code for transaction | | location | object | Location, see [Location object](#location-object) | ### Location object The two values in this table are for the location object. | Attribute | Type | Description | | :-------- | :---- | :---------- | | latitude | float | Latitude | | longitude | float | Longitude | # Endpoints Use the endpoint below for information about transactions in an account. * [List all bank transactions](/api-reference/transactions/link-bank-data-transactions) # Example response The sample below is a JSON response for the endpoint. ```json theme={null} { "count": 0, "next": "string", "previous": "string", "accounts": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z", "type": "CHECKING", "subtype": "MONEY_MARKET", "mask": "6789", "nickname": "My account", "balances": { "currency_code": "USD", "balance": "100.00", "available_balance": "50.99", "credit_limit": "200.00" } } ], "transactions": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z", "account_id": "68a7e80942ce4ad58a93f70ce411549a", "external_id": "external_key_243901", "amount": "100.00", "currency_code": "USD", "check_number": "123456", "categories": [ "Transfer" ], "description": "Some transaction", "status": "POSTED", "type": "DEBIT", "posted_at": "2022-05-04T11:30:00Z", "transacted_at": "2022-05-04T11:30:00Z", "memo": "", "merchant_name": "Starbucks", "merchant_category_code": 5967, "location": { "latitude": 40.730610, "longitude": -73.935242 } } ] } ``` ## Transaction categories | Category | Subcategories | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Auto & Transport | Auto Insurance, Auto Payment, Gas, Parking, Public Transportation, Service & Parts | | Bills & Utilities | Domain Names, Fraud Protection, Home Phone, Hosting, Internet, Mobile Phone, Television, Utilities | | Business Services | Advertising, Legal, Office Supplies, Printing, Shipping | | Education | Books & Supplies, Student Loan, Tuition | | Entertainment | Amusement, Arts, Movies & DVDs, Music, Newspapers & Magazines | | Fees & Charges | ATM Fee, Banking Fee, Finance Charge, Late Fee, Service Fee, Trade Commissions | | Financial | Financial Advisor, Life Insurance, BNPL, Payday Loan, EWA Lender, Loan Disbursement | | Food & Dining | Alcohol & Bars, Coffee Shops, Fast Food, Groceries, Restaurants | | Gifts & Donations | Charity, Gift | | Health & Fitness | Dentist, Doctor, Eyecare, Gym, Health Insurance, Pharmacy, Sports | | Home | Furnishings, Home Improvement, Home Insurance, Home Services, Home Supplies, Lawn & Garden, Mortgage & Rent | | Income | Bonus, Interest Income, Paycheck, Reimbursement, Rental Income, Returned Purchase, EWA Payroll, Retirement, Government Employment, Government Benefits, Private Benefits, Unemployment, Tax credits, Gig Economy | | Investments | Buy, Deposit, Dividend & Cap Gains, Sell, Withdrawal | | Kids | Allowance, Baby Supplies, Babysitter & Daycare, Child Support, Kids Activities, Toys | | Personal Care | Hair, Laundry, Spa & Massage | | Pets | Pet Food & Supplies, Pet Grooming, Veterinary | | Shopping | Books, Clothing, Hobbies, Sporting Goods | | Taxes | Federal Tax, Local Tax, Property Tax, Sales Tax, State Tax | | Transfer | Credit Card Payment, Transfer for Cash Spending, Mortgage Payment, P2P | | Travel | Air Travel, Hotel, Rental Car & Taxi, Vacation | | Uncategorized | Cash, Check | # List all documents Source: https://docs.truv.com/api-reference/uploaded-documents/list-documents GET /v1/links/{link_id}/documents/ The endpoint returns a list of documents. **Note:** When the `other` document type is enabled in the document upload settings of your customization template, end users can upload arbitrary documents that don't fit the other categories. Truv does not parse these `OTHER` documents into structured data (they are captured only), but you can collect the uploaded files through this Uploaded Documents API. # The Uploaded Documents object Source: https://docs.truv.com/api-reference/uploaded-documents/object Find more information about the responses for uploaded documents. # Attributes The table below covers information from the response for uploaded documents. The response body is an array of objects and can include multiple document values. | Attribute | Type | Description | | :---------- | :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | | id | string | Document ID | | type | string | Document type, valid responses below `PAYSTUB`, `W2`, `F1099`, `F1040`, `VOLUNTEER_LETTER`, `INSURANCE_HOME_POLICY`, `INSURANCE_AUTO_POLICY`, `OTHER` | | subtype | string, null | Document subtype, valid responses below `F1099_DIV`, `F1099_G`, `F1099_INT`, `F1099_MISC`, `F1099_NEC`, `F1099_R`, `F_SSA1099` | | file | uri | Document file link, file may be absent or partially uploaded (up to 2048 characters long) | | filename | string | Document file name | | mimetype | string | Document mimetype | | created\_at | date-time | Date when document was uploaded | | updated\_at | date-time | Date when document was updated | Document file URLs are **temporary pre-signed URLs that expire after 1 hour**. After expiry, the URL returns an access error. To get a fresh URL, make a new API request to the [Retrieve document](/api-reference/uploaded-documents/retrieve-document) endpoint. This does not trigger a data refresh or re-upload — it simply generates a new pre-signed URL for the same file. When the `other` document type is enabled in the document upload settings of your [customization template](/api-reference/templates/object), end users can upload arbitrary documents that don't fit the other categories. Truv does not parse these `OTHER` documents into structured data (they are captured only), but you can collect the uploaded files through this Uploaded Documents API. # Endpoints Use the endpoints below to get information on uploaded documents. * [List all documents](/api-reference/uploaded-documents/list-documents) * [Retrieve document](/api-reference/uploaded-documents/retrieve-document) # Example response The sample below is a JSON response for the endpoint. ```json theme={null} [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "type": "W2", "subtype": null, "file": "https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/w2.pdf", "filename": "most.recent.paystub.pdf", "mimetype": "application/pdf", "created_at": "2023-08-03T23:52:12.751Z", "updated_at": "2023-08-03T23:52:12.751Z" } ] ``` # Retrieve document Source: https://docs.truv.com/api-reference/uploaded-documents/retrieve-document GET /v1/links/{link_id}/documents/{doc_id}/ The endpoint returns a document. # Create an assets report Source: https://docs.truv.com/api-reference/user-asset-verification-reports/assets-report-create POST /v1/users/{user_id}/assets/reports/ The endpoint creates an assets report for the user. # Retrieve an assets report Source: https://docs.truv.com/api-reference/user-asset-verification-reports/assets-report-retrieve GET /v1/users/{user_id}/assets/reports/{report_id}/ The endpoint retrieves an assets report for the user. # The User Asset Reports object Source: https://docs.truv.com/api-reference/user-asset-verification-reports/object User-level Verification of Assets (VOA) reports that aggregate asset and financial account data across all account links. User Reports aggregate asset and financial account data across all of a user's account links into a single report. # Attributes The tables below have the values, format, and descriptions for the responses. | Attribute | Type | Description | | | :------------------------ | :----------------- | :---------------------------------------------------------------------------------------------------------------------------- | -- | | report\_id | string | Unique identifier of the report | | | created\_at | date-time | Timestamp when report was created | | | completed\_at | date-time | Timestamp when report was completed | | | days\_requested | integer | Number of days for requested transactions | | | as\_of\_date | date | End date of the report period. Start date is as\_of\_date minus days\_requested. Defaults to the current date if not provided | \\ | | large\_deposit\_threshold | integer (nullable) | Amount that must be met or exceeded for deposits to be marked as large | | | is\_voe | boolean | Indicates whether the report is a Deposit-based Verification of Employment (DVOE) | | | borrower | object | Borrower information, see [Borrower object](#borrower-object) | | | links | array of objects | List of assets links, see [Links object](#links-object) | | | summary | object | Balance summary information for account, see [Summary object](#summary-object) | | ## Borrower object Information in the table below is for the borrower object. | Attribute | Type | Description | | :----------------- | :-------- | :----------------------------------- | | id | string | Unique ID of user | | external\_user\_id | string | External user ID | | first\_name | string | First name | | last\_name | string | Last name | | email | string | Email address | | phone | string | Phone number | | ssn | string | Social Security Number | | created\_at | date-time | Timestamp when user was created | | updated\_at | date-time | Timestamp when user was last updated | *** ## Links object The information in this table is for values in the Links object. | Attribute | Type | Description | | :------------- | :--------------- | :--------------------------------------------------------------- | | link\_id | string | Unique identifier of the link | | tracking\_info | string | Additional optional identifier passed by user | | provider | string | ID of the financial institution | | provider\_name | string | Name of the financial institution | | accounts | array of objects | List of assets accounts, see [Accounts object](#accounts-object) | ### Accounts object The table below covers values in the accounts object. | Attribute | Type | Description | | :------------------------------ | :--------------- | :-------------------------------------------------------------------------------- | | id | string | Unique identifier of account | | created\_at | date-time | Date and time account was created | | updated\_at | date-time | Date and time account was most recently updated | | type | string | Parent type of the account, example `CHECKING` or `SAVINGS` | | subtype | string | Account's subtype, example `PLAN_401_K`, `MONEY_MARKET`, or `HOME_EQUITY` | | mask | string | Masked banking account number associated with account | | routing\_number | string | Bank routing number associated with the account | | nickname | string | Alternate name for account | | days\_available | integer | Available number of days for transactions from `days_requested` | | balance\_as\_of | date-time | Timestamp for when balance was captured | | balances | object | List of balance information from account, see [Balances object](#balances-object) | | transactions | array of objects | List of transactions for account, see [Transactions object](#transactions-object) | | owners | array of objects | List of owners for account, see [Owners object](#owners-object) | | summary | object | Balance summary information for account, see [Summary object](#summary-object) | | same\_owner\_as\_requested | boolean | Whether account owner matches the requested user | | direct\_deposit\_from\_employer | boolean | Whether account has direct deposit from employer | | nsf | integer | NSF (Non-sufficient funds) count | #### Balances object The information in the table below refers to values in the balances object. | Attribute | Type | Description | | :----------------- | :----- | :------------------------------------------------------------------------------------------------------------------------- | | currency\_code | string | Three-character ISO 4217 currency code | | balance | string | Current account balance | | available\_balance | string | Available balance for use in checking and savings asset accounts, `PENDING` transactions may not reflect available balance | | credit\_limit | string | Credit limit associated with account | #### Transactions object The values for the transactions object are in the table below. | Attribute | Type | Description | | :----------------------- | :--------------- | :--------------------------------------------------------------------- | | id | string | Unique identifier of transaction | | external\_id | string | External system transaction identifier | | amount | string | Monetary amount of transaction | | currency\_code | string | Three-character ISO 4217 currency code | | check\_number | string | Check number for transaction | | categories | array of strings | List of categories assigned to this transaction | | description | string | Human-readable transaction description | | status | string | Status of transaction: `POSTED`, `PENDING`, `AUTHORIZATION`, or `MEMO` | | type | string | Type of transaction: `CREDIT`, `DEBIT`, or `MEMO` | | posted\_at | date-time | Timestamp when transaction was posted | | transacted\_at | date-time | Timestamp when transaction took place | | merchant\_name | string | Merchant name extracted from the transaction description | | merchant\_category\_code | int32 | ISO 18245 category code for transaction | | ending\_daily\_balance | number | Daily ending balance for transaction | | is\_direct\_deposit | boolean | Whether transaction is direct deposit | | is\_subscription | boolean | Whether transaction is subscription | #### Owners object The values in this table are for the address object of the company. | Attribute | Type | Description | | :------------- | :----- | :--------------------------------------------------------------- | | id | string | ID of owner | | full\_name | string | Full name | | email | string | Email address | | phone | string | Phone number | | address | object | Address object with street, city, state, zip, and country fields | | relation\_type | string | Relationship type for account owner (see below) | ##### Relation types The table below contains valid relation types for account owners. | Relation Type | Description | | :------------------- | :----------------------------------------- | | PRIMARY | Primary account holder | | BUSINESS | Business account relationship | | JOINT | Joint account holder | | SECONDARY | Secondary account holder | | AUTHORIZED\_USER | Authorized user on the account | | FOR\_BENEFIT\_OF | Account held for benefit of another person | | ACCOUNT\_BENEFICIARY | Beneficiary of the account | | CUSTODIAN | Custodian of the account | | OTHER | Other relationship to the account | ## Account types and subtypes **Parent types:** | Type | Description | | ------------------------- | --------------------------------------- | | `ANY` | Not provided by data partner or invalid | | `CHECKING` | Checking account | | `SAVINGS` | Savings account | | `LOAN` | Loan account | | `CREDIT_CARD` | Credit card | | `INVESTMENT` | Investment account | | `LINE_OF_CREDIT` | Line of credit | | `MORTGAGE` | Mortgage | | `PROPERTY` | Property | | `CASH` | Cash account | | `INSURANCE` | Insurance | | `PREPAID` | Prepaid account | | `CHECKING_LINE_OF_CREDIT` | Checking with overdraft line | **Subtypes by parent:** | Subtype | Parent Type | | ------------------------------------------- | ----------- | | `MONEY_MARKET` | SAVINGS | | `CERTIFICATE_OF_DEPOSIT` | SAVINGS | | `AUTO` | LOAN | | `STUDENT` | LOAN | | `SMALL_BUSINESS` | LOAN | | `PERSONAL` | LOAN | | `PERSONAL_WITH_COLLATERAL` | LOAN | | `HOME_EQUITY` | LOAN | | `BOAT` | LOAN | | `POWERSPORTS` | LOAN | | `RV` | LOAN | | `HELOC` | LOAN | | `PLAN_401_K` | INVESTMENT | | `PLAN_403_B` | INVESTMENT | | `PLAN_529` | INVESTMENT | | `IRA` | INVESTMENT | | `ROLLOVER_IRA` | INVESTMENT | | `ROTH_IRA` | INVESTMENT | | `TAXABLE` | INVESTMENT | | `NON_TAXABLE` | INVESTMENT | | `BROKERAGE` | INVESTMENT | | `TRUST` | INVESTMENT | | `UNIFORM_GIFTS_TO_MINORS_ACT` | INVESTMENT | | `PLAN_457` | INVESTMENT | | `PENSION` | INVESTMENT | | `EMPLOYEE_STOCK_OWNERSHIP_PLAN` | INVESTMENT | | `SIMPLIFIED_EMPLOYEE_PENSION` | INVESTMENT | | `SIMPLE_IRA` | INVESTMENT | | `PLAN_ROTH_401_K` | INVESTMENT | | `FIXED_ANNUITY` | INVESTMENT | | `VARIABLE_ANNUITY` | INVESTMENT | | `HSA` | INVESTMENT | | `TAX_FREE_SAVINGS_ACCOUNT` | INVESTMENT | | `INDIVIDUAL` | INVESTMENT | | `REGISTERED_RETIREMENT_INCOME_FUND` | INVESTMENT | | `CASH_MANAGEMENT_ACCOUNT` | INVESTMENT | | `EMPLOYEE_STOCK_PURCHASE_PLAN` | INVESTMENT | | `REGISTERED_EDUCATION_SAVINGS_PLAN` | INVESTMENT | | `PROFIT_SHARING_PLAN` | INVESTMENT | | `UNIFORM_TRANSFER_TO_MINORS_ACT` | INVESTMENT | | `PLAN_401_A` | INVESTMENT | | `SARSEP_IRA` | INVESTMENT | | `FIXED_ANNUITY_TRADITIONAL_IRA` | INVESTMENT | | `VARIABLE_ANNUITY_TRADITIONAL_IRA` | INVESTMENT | | `SEPP_IRA` | INVESTMENT | | `INHERITED_TRADITIONAL_IRA` | INVESTMENT | | `FIXED_ANNUITY_ROTH_IRA` | INVESTMENT | | `VARIABLE_ANNUITY_ROTH_IRA` | INVESTMENT | | `INHERITED_ROTH_IRA` | INVESTMENT | | `COVERDELL` | INVESTMENT | | `ADVISORY_ACCOUNT` | INVESTMENT | | `BROKERAGE_MARGIN` | INVESTMENT | | `CHARITABLE_GIFT_ACCOUNT` | INVESTMENT | | `CHURCH_ACCOUNT` | INVESTMENT | | `CONSERVATORSHIP` | INVESTMENT | | `CUSTODIAL` | INVESTMENT | | `DEFINED_BENEFIT_PLAN` | INVESTMENT | | `DEFINED_CONTRIBUTION_PLAN` | INVESTMENT | | `EDUCATIONAL` | INVESTMENT | | `ESTATE` | INVESTMENT | | `EXECUTOR` | INVESTMENT | | `GROUP_RETIREMENT_SAVINGS_PLAN` | INVESTMENT | | `GUARANTEED_INVESTMENT_CERTIFICATE` | INVESTMENT | | `HRA` | INVESTMENT | | `INDEXED_ANNUITY` | INVESTMENT | | `INVESTMENT_CLUB` | INVESTMENT | | `IRREVOCABLE_TRUST` | INVESTMENT | | `JOINT_TENANTS_BY_ENTIRITY` | INVESTMENT | | `JOINT_TENANTS_COMMUNITY_PROPERTY` | INVESTMENT | | `JOINT_TENANTS_IN_COMMON` | INVESTMENT | | `JOINT_TENANTS_WITH_RIGHTS_OF_SURVIVORSHIP` | INVESTMENT | | `KEOUGH_PLAN` | INVESTMENT | | `LIFE_INCOME_FUND` | INVESTMENT | | `LIVING_TRUST` | INVESTMENT | | `LOCKED_IN_RETIREMENT_ACCOUNT` | INVESTMENT | | `LOCKED_IN_RETIREMENT_INVESTMENT_FUND` | INVESTMENT | | `LOCKED_IN_RETIREMENT_SAVINGS_ACCOUNT` | INVESTMENT | | `MONEY_PURCHASE_PLAN` | INVESTMENT | | `PARTNERSHIP` | INVESTMENT | | `PLAN_409_A` | INVESTMENT | | `PLAN_ROTH_403_B` | INVESTMENT | | `REGISTERED_DISABILITY_SAVINGS_PLAN` | INVESTMENT | | `REGISTERED_LOCKED_IN_SAVINGS_PLAN` | INVESTMENT | | `REGISTERED_PENSION_PLAN` | INVESTMENT | | `REGISTERED_RETIREMENT_SAVINGS_PLAN` | INVESTMENT | | `REVOCABLE_TRUST` | INVESTMENT | | `ROTH_CONVERSION` | INVESTMENT | | `SOLE_PROPRIETORSHIP` | INVESTMENT | | `SPOUSAL_IRA` | INVESTMENT | | `SPOUSAL_ROTH_IRA` | INVESTMENT | | `TESTAMENTARY_TRUST` | INVESTMENT | | `THRIFT_SAVINGS_PLAN` | INVESTMENT | | `INHERITED_ANNUITY` | INVESTMENT | | `CORPORATE_ACCOUNT` | INVESTMENT | | `LIMITED_LIABILITY_ACCOUNT` | INVESTMENT | | `VEHICLE_INSURANCE` | INSURANCE | | `DISABILITY` | INSURANCE | | `HEALTH` | INSURANCE | | `LONG_TERM_CARE` | INSURANCE | | `PROPERTY_AND_CASUALTY` | INSURANCE | | `UNIVERSAL_LIFE` | INSURANCE | | `TERM_LIFE` | INSURANCE | | `WHOLE_LIFE` | INSURANCE | | `ACCIDENTAL_DEATH_AND_DISMEMBERMENT` | INSURANCE | | `VARIABLE_UNIVERSAL_LIFE` | INSURANCE | #### Summary object Information in the table below are for the summary object. | Attribute | Type | Description | | :------------- | :----- | :------------------------------------- | | avg\_30 | string | Average balance for 30 days | | avg\_60 | string | Average balance for 60 days | | avg\_90 | string | Average balance for 90 days | | currency\_code | string | Three-character ISO 4217 currency code | # Endpoints Use the endpoints below to manage user-level asset reports. * [Create an assets report](/api-reference/user-asset-verification-reports/assets-report-create) * [Retrieve an assets report](/api-reference/user-asset-verification-reports/assets-report-retrieve) # Example response The JSON below is a sample response for the endpoint. ```json theme={null} { "report_id": "7d4fcb86b81a4880955beea558092391", "created_at": "2022-05-04T11:30:00Z", "completed_at": "2022-05-04T12:00:00Z", "days_requested": 60, "as_of_date": "2022-05-01", "large_deposit_threshold": 500, "is_voe": true, "borrower": { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "external_user_id": "12345", "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone": "+14155554193", "ssn": "222233333", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z" }, "links": [ { "link_id": "150491a20bdb4292bb2a2ad8554fecba", "tracking_info": "string", "provider": "string", "provider_name": "string", "accounts": [ { "id": "4d601895417c46ec99633978db12a866", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z", "type": "string", "subtype": "string", "mask": "string", "routing_number": "55999876", "nickname": "string", "days_available": 0, "balance_as_of": "2025-05-04T12:00:00Z", "balances": { "currency_code": "string", "balance": "string", "available_balance": "string", "credit_limit": "string" }, "transactions": [ { "id": "7d4fcb86b81a4880955beea558092391", "external_id": "string", "amount": "string", "currency_code": "string", "check_number": "string", "categories": [ "string" ], "description": "string", "status": "POSTED", "type": "DEBIT", "posted_at": "2022-05-05T15:30:00Z", "transacted_at": "2022-05-04T12:00:00Z", "merchant_name": "Starbucks", "merchant_category_code": 5967, "ending_daily_balance": 0, "is_direct_deposit": true, "is_subscription": true } ], "owners": [ { "id": "2b623fa2fa9e49cea17d9692caa884c5", "full_name": "John Doe", "email": "john.doe@example.com", "phone": "14155554193", "address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" }, "relation_type": "PRIMARY" } ], "summary": { "avg_30": "string", "avg_60": "string", "avg_90": "string", "currency_code": "string", "balance": "string" }, "same_owner_as_requested": true, "direct_deposit_from_employer": true, "nsf": 0 } ] } ], "summary": { "avg_30": "string", "avg_60": "string", "avg_90": "string", "currency_code": "string", "balance": "string" } } ``` # The User Income & Employment Reports object Source: https://docs.truv.com/api-reference/user-income-and-employment-reports/object User-level Verification of Income and Employment (VOIE) reports that aggregate income and employment data across all account links. User Reports aggregate income and employment data across all of a user's account links into a single report. For data from a single account link, see [Link Income and Employment Reports](/api-reference/account-link-income-and-employment-reports/object). **Link-level vs User-level reports:** Link-level reports (`GET /v1/links/{link_id}/income/report/`) contain data from a single payroll connection and include link-exclusive fields like `status`, `is_suspicious`, and `access_token`. User-level reports (`POST /v1/users/{user_id}/reports/`) aggregate across all connections, exposing the top-level `report_id` plus the per-employment `gse_accepted` flag (nested under `links[].employments[]`) for GSE submission. Both report types include `provider`. Use user-level reports for mortgage/GSE workflows. # Attributes The tables below have the values, format, and descriptions for the responses. | Attribute | Type | Description | | :------------ | :--------------- | :---------------------------------------------------------- | | report\_id | string | Unique identifier of the report | | created\_at | date-time | Timestamp when the report was created | | completed\_at | date-time | Timestamp when the report was completed | | links | array of objects | List of employment links, see [Links object](#links-object) | ## Links object The information in this table is for values in the Links object. | Attribute | Type | Description | | :------------- | :--------------- | :------------------------------------------------------------------- | | link\_id | string | Unique identifier of the link | | tracking\_info | string | Additional optional identifier passed by user | | provider | string | Data provider ID | | provider\_name | string | Data provider name | | employments | array of objects | List of employee data, see [Employments object](#employments-object) | ### Employments object The Employments object contains the values and descriptions below. | Attribute | Type | Description | | :---------------------- | :--------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | income | string | Income amount not including commission or bonuses, only for income product. Null for employment product | | income\_unit | string | Pay interval for income field, only for income product: `YEARLY` - Annual income, `MONTHLY` - Monthly income, `WEEKLY` - Weekly income, `DAILY` - Daily income, `HOURLY` - Hourly income. Null for employment product | | pay\_rate | string | Payment rate per pay cycle, only for income product. Null for employment product | | pay\_frequency | string | Pay frequency, only for income product: `M` - Monthly, `SM` - Semi-Monthly, `W` - Weekly, `BW` - Bi-Weekly, `A` - Annually, `SA` - Semiannually, `C` - Commission. Null for employment product | | statements | array of objects | List of Paystubs received from a payroll provider, only for income product, see [Statements object](#statements-object). Null for employment product | | annual\_income\_summary | array of objects | Annual income summary by years, only for income product, see [Annual income summary object](#annual-income-summary-object). Null for employment product | | bank\_accounts | array of objects | List of bank accounts linked to employment, only for income product, see [Bank accounts object](#bank-accounts-object). Null for employment product | | w2s | array of objects | List of W-2 forms linked to employment, only for income product, see [W2s object](#w2s-object). Null for employment product | | id | string | Unique ID | | is\_active | boolean | Status of active employment | | job\_title | string | Employee's job title | | job\_type | string | Employee's job type: `F` - Full Time, `P` - Part Time, `S` - Seasonal, `D` - Daily (per diem), `C` - Contract | | start\_date | date | Employee's hire date | | original\_hire\_date | date | Original hire date | | end\_date | date | Employee's end date | | external\_last\_updated | date | Indicates date of last updated employment data from Payroll Provider | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | | manager\_name | string, null | Supervisor's name | | profile | object | Person's identity information | | company | object | [Company object](#company-object) | | gse\_accepted | boolean | Status of provider eligibility from Fannie Mae Desktop Underwriter | #### Company object This table covers values within the company object. | Attribute | Type | Description | | :-------- | :----- | :-------------------------------- | | name | string | Company name | | address | object | [Address object](#address-object) | | phone | string | Company phone number | | ein | string | Employer Identification Number | #### Address object The values in this table are for the address object of the company. | Attribute | Type | Description | | :-------- | :----- | :---------- | | street | string | Street | | city | string | City | | state | string | State | | zip | string | Zip | | country | string | Country | #### Statements object View the table below for information from the Statements object. | Attribute | Type | Description | | :-------------------- | :--------------- | :--------------------------------------------------------------------------------- | | id | string | Unique ID | | check\_number | string | External ID of pay stub from payroll provider | | pay\_date | date | Pay date | | net\_pay | string | Net pay | | net\_pay\_ytd | string | Net pay year to date | | gross\_pay | string | Gross pay | | gross\_pay\_ytd | string | Gross pay year to date | | bonus | string | Bonus | | commission | string | Commission | | hours | string | Work hours during pay period | | basis\_of\_pay | string | Basis of pay: `S` - Salary, `H` - Hourly, `D` - Daily, `W` - Weekly, `M` - Monthly | | period\_start | date | Period start | | period\_end | date | Period end | | regular | string | Regular pay | | regular\_ytd | string | Regular salary year to date | | other\_pay\_ytd | string | All other payment year to date | | bonus\_ytd | string | Bonus year to date | | commission\_ytd | string | Commission year to date | | overtime | string | Overtime pay | | overtime\_ytd | string | Overtime pay year to date | | other\_pay | string | All other payment | | earnings | array of objects | Earnings for this pay cycle by type | | earnings\_ytd | array of objects | Earnings year to date by type | | deductions | array of objects | Deductions for pay cycle by type | | deductions\_ytd | array of objects | Deductions year to date by type | | md5sum | string | MD5 hash value computed based on file content | | file | uri | Link to pay stub file, format is specified in the content-type | | derived\_fields | array of strings | Array of derived fields | | missing\_data\_fields | array of strings | List of missing data fields from payroll response | #### Annual income summary object Find information for the attributes and values of the annual income summary object. | Attribute | Type | Description | | :--------- | :------ | :---------------------- | | id | string | Unique ID | | year | integer | Income report year | | regular | string | Regular salary | | bonus | string | Bonus | | commission | string | Commission | | overtime | string | Overtime pay | | other\_pay | string | All other payment forms | | net\_pay | string | Net pay | | gross\_pay | string | Gross pay | #### Bank accounts object The table below covers the attributes within the bank accounts object. | Attribute | Type | Description | | :-------------- | :----- | :---------------------------------------------------------------------------------------------------------- | | account\_number | string | Account number | | routing\_number | string | Routing number | | account\_name | string | User friendly account name | | account\_type | string | Account type: `C` - Checking account, `S` - Savings account | | deposit\_type | string | Deposit type: `E` - Entire paycheck, `P` - Percentage of the paycheck, `A` - Fixed amount from the paycheck | | deposit\_value | string | Deposit value | | bank\_name | string | Bank name | #### W2s object The values in this table are for the W-2s object field. | Attribute | Type | Description | | :---------------------- | :------ | :-------------------------------------------------------------- | | file | uri | Link to W2 report file, format is specified in the content-type | | md5sum | string | MD5 hash value computed based on file content | | year | integer | Year | | wages | string | Wages, tips, other compensation (Section 1) | | federal\_tax | string | Federal income tax withheld (Section 2) | | social\_security\_wages | string | Social security wages (Section 3) | | social\_security\_tax | string | Social security tax withheld (Section 4) | | medicare\_wages | string | Medicare wages (Section 5) | | medicare\_tax | string | Medicare tax withheld (Section 6) | | gross\_pay | string | Gross pay | # Endpoints Use the endpoints below to manage user-level reports. * [Create a report](/api-reference/user-income-and-employment-reports/users_reports) * [Retrieve a report](/api-reference/user-income-and-employment-reports/users_get_report) # Example response The sample below is a JSON response for the endpoint. ```json theme={null} { "report_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "created_at": "2022-05-04T11:30:00Z", "completed_at": "2022-05-04T12:00:00Z", "links": [ { "link_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "tracking_info": "string", "provider": "string", "employments": [ { "income": "70000.00", "income_unit": "YEARLY", "pay_rate": "6500.00", "pay_frequency": "M", "statements": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "check_number": "29205182", "pay_date": "2018-05-15", "net_pay": "11500.32", "net_pay_ytd": "31980.64", "gross_pay": "13900.11", "gross_pay_ytd": "49200.00", "bonus": "100.00", "commission": "12000.00", "hours": "40.00", "basis_of_pay": "S", "period_start": "2018-05-01", "period_end": "2018-05-15", "regular": "1695.11", "regular_ytd": "23000.00", "other_pay_ytd": "700.00", "bonus_ytd": "1000.00", "commission_ytd": "24000.00", "overtime": "45.00", "overtime_ytd": "500.00", "other_pay": "60.00", "earnings": [ { "name": "Regular", "amount": "1935.77", "category": "regular", "rate": null, "units": null }, { "name": "Overtime", "amount": "60.58", "category": "overtime", "rate": "30.29", "units": "2" } ], "earnings_ytd": [ { "name": "Regular", "amount": "1935.77", "category": "regular", "rate": null, "units": null }, { "name": "Overtime", "amount": "60.58", "category": "overtime", "rate": "30.29", "units": "2" } ], "deductions": [ { "amount": "127.01", "category": "socialsec", "name": "Social Security Tax" }, { "amount": "46.23", "category": "state", "name": "VA State Income Tax" }, { "amount": "29.7", "category": "medicare", "name": "Medicare Tax" } ], "deductions_ytd": [ { "amount": "127.01", "category": "socialsec", "name": "Social Security Tax" }, { "amount": "46.23", "category": "state", "name": "VA State Income Tax" }, { "amount": "29.7", "category": "medicare", "name": "Medicare Tax" } ], "md5sum": "03639d6a6624f69a54a88ea90bd25e9d", "file": "https://citadelid-resources.s3-us-west-2.amazonaws.com/paystub_sample.pdf", "derived_fields": [ "basis_of_pay" ], "missing_data_fields": [ "earnings_ytd" ] } ], "annual_income_summary": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "year": 2018, "regular": "23000.00", "bonus": "1000.00", "commission": "24000.00", "overtime": "500.00", "other_pay": "700.00", "net_pay": "31980.64", "gross_pay": "49200.00" } ], "bank_accounts": [ { "account_number": "1234567890", "routing_number": "123456789", "account_name": "My Bank", "account_type": "C", "deposit_type": "A", "deposit_value": "200.00", "bank_name": "TD Bank" } ], "w2s": [ { "file": "https://citadelid-resources.s3-us-west-2.amazonaws.com/W2_sample.pdf", "md5sum": "f65e30c39124ad707ac4b3aeaee923a7", "year": 2020, "wages": "900.50", "federal_tax": "75.01", "social_security_wages": "900.50", "social_security_tax": "56.30", "medicare_wages": "900.50", "medicare_tax": "13.15", "gross_pay": "18211.48" } ], "id": "24d7e80942ce4ad58a93f70ce4115f5c", "is_active": false, "job_title": "PR associate", "job_type": "F", "start_date": "2018-01-01", "original_hire_date": "2017-06-21", "end_date": "2023-04-29", "external_last_updated": "2023-04-29", "derived_fields": [ "is_active" ], "missing_data_fields": [ "w2s" ], "manager_name": "Jenny McDouglas", "profile": { "id": "48427a36d43c4d5aa6324bc06c692456", "created_at": "2022-06-07T15:00:00Z", "updated_at": "2022-06-31T15:00:00Z", "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "middle_initials": "K", "email": "john.doe@example.com", "ssn": "123456789", "date_of_birth": "1992-03-03", "home_address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" } }, "company": { "name": "Facebook Demo", "address": { "street": "1 Morgan Ave", "city": "Los Angeles", "state": "CA", "zip": "90210", "country": "US" }, "phone": "6503087300", "ein": "12-345678" }, "gse_accepted": true } ] } ] } ``` # Retrieve an income and employment report Source: https://docs.truv.com/api-reference/user-income-and-employment-reports/users_get_report GET /v1/users/{user_id}/reports/{report_id}/ The endpoint retrieves a report for a user. # Create an income and employment report Source: https://docs.truv.com/api-reference/user-income-and-employment-reports/users_reports POST /v1/users/{user_id}/reports/ The endpoint creates a report for a user. # The Users object Source: https://docs.truv.com/api-reference/users/object Manage users and user tokens for Truv Bridge with the Users endpoint. User objects represent distinct users that would connect their accounts via Truv Bridge. ### User Attributes | Attribute | Type | Description | | :----------------- | :------- | :----------------------------------- | | id | string | Unique ID of user | | external\_user\_id | string | External user ID | | first\_name | string | First name\* | | last\_name | string | Last name\* | | email | string | User email | | phone | string | User phone number | | ssn | string | User SSN | | created\_at | datetime | Timestamp when user was created | | updated\_at | datetime | Timestamp when user was last updated | Full name is required Users and applicants require both `first_name` and `last_name` values when testing for Integrating Document Processing. ## Endpoints The list below contains available endpoints for user management. * [List all users](/api-reference/users/users_list) * [Create a user](/api-reference/users/users_create) * [Retrieve a user](/api-reference/users/users_read) * [Update a user](/api-reference/users/users_partial_update) * [Delete a user](/api-reference/users/users_delete) *** ## Example response View the example object from the `Create User` endpoint below. ```json theme={null} { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "external_user_id": "12345", "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone": "+14155554193", "ssn": "222233333", "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z" } ``` # Create a user Source: https://docs.truv.com/api-reference/users/users_create POST /v1/users/ The endpoint creates a user. # Delete a user Source: https://docs.truv.com/api-reference/users/users_delete DELETE /v1/users/{user_id}/ The endpoint deletes a user. # List all users Source: https://docs.truv.com/api-reference/users/users_list GET /v1/users/ The endpoint returns a list of users. # Update a user Source: https://docs.truv.com/api-reference/users/users_partial_update PATCH /v1/users/{user_id}/ The endpoint updates a user. # Retrieve a user Source: https://docs.truv.com/api-reference/users/users_read GET /v1/users/{user_id}/ This endpoint retrieves a user. # Webhooks Source: https://docs.truv.com/api-reference/webhooks Receive real-time notifications when verification events occur Webhooks are HTTP POST requests sent automatically by Truv when events occur during the verification flow. They track Task status changes, Order updates, Link connections, and data object creation, keeping your system in sync as data progresses through processing stages. Configure webhook endpoints separately for Sandbox and Production. *** ## Set up webhooks Configure webhook endpoints in the [Truv Dashboard](https://dashboard.truv.com): 1. Navigate to **Development** → **Webhooks** 2. Enter your endpoint URL 3. Save the configuration Your endpoint will begin receiving webhook events for all activity in that environment. ### Test webhooks * Use **Truv Bridge** in the Dashboard Emulator to trigger webhook events in sandbox * Use tools like [ngrok](https://ngrok.com/) to expose a local development server: ```bash theme={null} ngrok http 3000 ``` Then configure the ngrok URL as your webhook endpoint in the Dashboard. *** ## Webhook payload structure All webhook requests include these standard fields: ### Headers | Header | Value | | ---------------- | -------------------------------------- | | `User-Agent` | `Truv-Webhook-Service/2.0` | | `X-WEBHOOK-SIGN` | HMAC-SHA256 signature for verification | HTTP header names are case-insensitive per RFC 7230. ### Body fields Every webhook payload includes these common fields: | Field | Description | | ------------------ | ------------------------------------------ | | `webhook_id` | Unique identifier for this webhook request | | `event_type` | The event classification | | `event_created_at` | Timestamp when the event occurred | | `user_id` | Associated Truv user identifier | Additional fields vary by event type — see [Events by object](#events-by-object) below. *** ## Security Every webhook includes an `X-WEBHOOK-SIGN` header with an HMAC-SHA256 signature. Verify it against the raw request body using your Access Secret before processing the event. ### How it works 1. Truv computes an HMAC-SHA256 hash of the raw request body using your Access Secret 2. The hash is sent in the `X-WEBHOOK-SIGN` header with a `v1=` prefix 3. Your server recomputes the hash and compares it to the header value Always verify signatures using the **raw request body**, not parsed JSON. Parsing and re-serializing may change the byte representation. ### Code examples ```python theme={null} import hashlib import hmac def verify_webhook(payload: str, signature: str, secret: str) -> bool: generated_hash = hmac.new( key=secret.encode('utf-8'), msg=payload.encode('utf-8'), digestmod=hashlib.sha256, ).hexdigest() expected = f'v1={generated_hash}' return hmac.compare_digest(expected, signature) ``` ```javascript theme={null} const crypto = require("crypto"); const express = require("express"); const bodyParser = require("body-parser"); const app = express(); app.use(bodyParser.json({ verify: (req, res, buf) => { req.rawBody = buf; } })); function verifyWebhook(rawBody, signature, secret) { const hash = crypto .createHmac("sha256", secret) .update(rawBody) .digest("hex"); const expected = `v1=${hash}`; return signature === expected; } app.post("/webhooks/truv", (req, res) => { const signature = req.headers["x-webhook-sign"]; const isValid = verifyWebhook(req.rawBody, signature, process.env.TRUV_SECRET); if (!isValid) { return res.status(401).send("Invalid signature"); } res.status(200).send("OK"); }); ``` ```go theme={null} import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "fmt" ) func verifyWebhook(body string, signature string, secret string) bool { mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(body)) expected := fmt.Sprintf("v1=%s", hex.EncodeToString(mac.Sum(nil))) return hmac.Equal([]byte(expected), []byte(signature)) } ``` ```ruby theme={null} require 'openssl' def verify_webhook(body, signature, secret) digest = OpenSSL::Digest.new('sha256') expected = "v1=" + OpenSSL::HMAC.hexdigest(digest, secret, body) Rack::Utils.secure_compare(expected, signature) end ``` ```csharp theme={null} using System.Security.Cryptography; using System.Text; private bool VerifyWebhook(string body, string signature, string secret) { using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret))) { byte[] hashValue = hmac.ComputeHash(Encoding.UTF8.GetBytes(body)); string expected = "v1=" + BitConverter.ToString(hashValue) .Replace("-", "").ToLower(); return expected == signature; } } ``` ### Originating IP addresses Allowlist the current Truv webhook IP addresses if your network requires source filtering: * `34.212.57.93` * `44.224.243.166` * `52.25.14.79` ### Additional authentication options Beyond signature verification, Truv supports: * Truv-signed certificates for webhook mTLS * Client-signed certificates for webhook mTLS * OAuth 2.0, where Truv obtains access tokens for secure webhook delivery (optional, configured with Truv) * Custom headers such as client ID and client secret, configured with Truv See [mTLS](/api-reference/security#mtls-for-webhooks) if you need mutual certificate-based authentication for webhook delivery. *** ## Timeouts and retries | Behavior | Detail | | ------------------- | --------------------------------------------------------------------------------------------- | | **Timeout** | Your endpoint must respond with a `2xx` status within **10 seconds** | | **Redirects** | `3xx` responses are followed | | **Retries** | `4xx` and `5xx` responses trigger up to **3 retry attempts** at **30-second intervals** | | **Failed delivery** | After the 3 retry attempts fail, Truv stops retrying that event and marks the delivery failed | *** ## Event ordering Webhooks are delivered in event order. For example, `full_parse` fires before `done`. However, network conditions can cause delays in delivery. Use the `event_created_at` field to sequence events correctly in your system, rather than relying on delivery order. When you need the authoritative full resource state, fetch it from the API instead of relying on the webhook payload alone. *** ## Handle webhooks ### Best practices Return a `200` response quickly. Process the webhook data asynchronously if needed: ```javascript theme={null} app.post("/webhooks/truv", (req, res) => { // Acknowledge immediately res.status(200).send("OK"); // Process asynchronously queue.add("process-webhook", req.body); }); ``` Webhooks may be delivered more than once. Use the `webhook_id` field for idempotency: ```javascript theme={null} async function handleWebhook(payload) { const exists = await db.webhooks.findOne({ webhookId: payload.webhook_id }); if (exists) return; // Already processed await processEvent(payload); await db.webhooks.insert({ webhookId: payload.webhook_id }); } ``` Never process a webhook without verifying the `X-WEBHOOK-SIGN` header. See [Security](#security) above. The `task-status-updated` event is the primary signal for monitoring connection progress. Key statuses to handle: * **`done`**: All data has been downloaded and processed. Fetch verification reports. * **`login_error`**: Authentication failed. The user may need to retry. * **`mfa_error`**: MFA verification failed. * **`config_error`**: Provider configuration issue. See [Connection Lifecycle](/api-reference/tasks/lifecycle) for the full status flow. *** ## Troubleshooting | Issue | Solution | | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Not receiving webhooks | Verify your URL is configured under **Development** → **Webhooks** for the correct environment | | Signature verification failing | Ensure you're using your **Access Secret** (not Client ID) and hashing the raw body | | Timeouts | Respond with `200` immediately, process asynchronously | | Failed deliveries | Each event is retried up to 3 times (30s apart), then marked failed. Use the [Webhook request history](/api-reference/webhooks/object#webhook-request-history) to find and debug failed deliveries | ## Events by object **Orders** ([see more](/api-reference/orders/events)) | Event | Trigger | | ------------------------- | -------------------------------------------------- | | `order-created` | Order first created, before any status transitions | | `order-status-updated` | Order status changes | | `order-refresh-failed` | Refresh task fails for an order | | `order-finalized` | Order group reaches its terminal, final state | | `certification-completed` | Applicant submits their income self-certification | **Tasks** ([see more](/api-reference/tasks/events)) | Event | Trigger | | --------------------- | ----------------------- | | `task-status-updated` | Task status transitions | **Bank Accounts** ([see more](/api-reference/bank-accounts/events)) | Event | Trigger | | ----------------------- | -------------------------------- | | `bank-accounts-created` | First bank account discovery | | `bank-accounts-updated` | Bank accounts changed on refresh | **Shift** ([see more](/api-reference/shifts/events)) | Event | Trigger | | ---------------- | ------------------------- | | `shifts-created` | First shift extraction | | `shifts-updated` | Shifts changed on refresh | **Pay Statement** ([see more](/api-reference/statements/events)) | Event | Trigger | | -------------------- | ------------------------- | | `statements-created` | First statement retrieval | | `statements-updated` | New statements on refresh | **Identity** ([see more](/api-reference/identity/events)) | Event | Trigger | | ----------------- | -------------------------- | | `profile-created` | First profile extraction | | `profile-updated` | Profile changed on refresh | **Employment** ([see more](/api-reference/employment/events)) | Event | Trigger | | -------------------- | ----------------------------- | | `employment-created` | First employment extraction | | `employment-updated` | Employment changed on refresh | **Links** ([see more](/api-reference/links/events)) | Event | Trigger | | ------------------- | ---------------------------- | | `link-connected` | Successful connection | | `link-disconnected` | Refresh connection failure | | `link-deleted` | Data and credentials removed | # The Webhook Endpoint object Source: https://docs.truv.com/api-reference/webhooks/object Learn how to create a webhook configuration to receive updates from Truv platform Webhooks provide a way for Truv to communicate to your servers when specific events happen. For example, when an account link connects successfully or new pay statements were added, you can receive notifications in realtime. To start receiving webhooks, your web application needs to expose a publicly accessible URL. Use that URL to create a webhook configuration. After creating a webhook configuration, you will receive POST requests with the event payloads that contain information about the events that have been triggered. # Attributes | Attribute | Type | Description | | :----------- | :------ | :------------------------------------------------------------ | | id | string | Unique ID of webhook configuration | | name | string | Public name for webhook configuration | | webhook\_url | string | Webhook URL to send event data | | events | string | List of events connected to webhook URL | | env\_type | string | Type of environment, `sandbox`, `dev`, or `prod` | | enabled | boolean | Whether the webhook is active | | created\_at | string | ISO 8601 value for when the webhook configuration was created | | updated\_at | string | ISO 8601 value for when the webhook configuration was updated | Truv may automatically disable a production webhook endpoint that fails continuously. The owner is notified by email before and after the endpoint is disabled, and delivery stops until you re-enable it. Re-enable a disabled endpoint by sending `"enabled": true` to the [update endpoint](/api-reference/webhooks/webhooks_partial_update). # Endpoints Available endpoints for Webhooks are in the list below. * [List all webhook endpoints](/api-reference/webhooks/webhooks_list) - GET /webhooks/ * [Create a webhook endpoint](/api-reference/webhooks/webhooks_create) - POST /webhooks/ * [Retrieve a webhook endpoint](/api-reference/webhooks/webhooks_read) - GET webhooks/\{id}/ * [Update a webhook endpoint](/api-reference/webhooks/webhooks_partial_update) - PATCH webhooks/\{id}/ * [Delete a webhook endpoint](/api-reference/webhooks/webhooks_delete) - DELETE webhooks/\{id}/ # Example response View the response for the Webhooks endpoints below. ```json theme={null} { "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "webhook_url": "http://example.com/", "events": [ "task-status-updated", "order-status-updated" ], "env_type": "dev", "enabled": true, "created_at": "2022-05-04T11:30:00Z", "updated_at": "2022-05-04T12:00:00Z" } ``` # Webhook request history ## Overview Use the Webhook request history endpoint to review and debug webhook delivery attempts made by Truv to your configured webhook URLs. This endpoint returns a paginated list of webhook delivery attempts, including metadata such as delivery status and timestamps. It can help you: * Confirm that Truv attempted to send a webhook * Investigate failed deliveries (non-2xx responses, timeouts, etc.) * Correlate webhook attempts with your internal logs * Audit recent webhook activity **Note:** Only webhook requests from the last 30 days are available. ## Endpoints * [List webhook request history](/api-reference/webhooks/webhook_requests_list) - GET /webhook-requests/ ## Example response View the response for the Webhook request history endpoint below. ```json theme={null} { "next": null, "previous": null, "results": [ { "webhook_id": "48427a36d43c4d5aa6324bc06c692456", "event_type": "task-status-updated", "event_created_at": "2024-01-15T10:30:00Z", "status_code": 200, "error_message": null, "webhook_payload": { "webhook_id": "a3f5b7c9d1e2f4a6b8c0d2e4f6a8b0c2", "event_type": "order-status-updated", "event_created_at": "2026-01-27T00:00:16.279921Z", "product": "assets", "link_id": null, "user_id": "b4c6d8e0f2a4b6c8d0e2f4a6b8c0d2e4", "order_id": "c5d7e9f1a3b5c7d9e1f3a5b7c9d1e3f5", "status": "expired" }, "webhook_url": "https://example.com/webhooks/truv" } ] } ``` # List webhook request history Source: https://docs.truv.com/api-reference/webhooks/webhook_requests_list GET /v1/webhook-requests/ Returns a paginated list of webhook requests filtered by the provided criteria. Only webhook requests from the last 30 days are available. # Create a webhook endpoint Source: https://docs.truv.com/api-reference/webhooks/webhooks_create POST /v1/webhooks/ The endpoint creates a webhook. # Delete a webhook endpoint Source: https://docs.truv.com/api-reference/webhooks/webhooks_delete DELETE /v1/webhooks/{webhook_id}/ The endpoint deletes a webhook. # List all webhook endpoints Source: https://docs.truv.com/api-reference/webhooks/webhooks_list GET /v1/webhooks/ The endpoint returns a list of webhooks. # Update a webhook endpoint Source: https://docs.truv.com/api-reference/webhooks/webhooks_partial_update PATCH /v1/webhooks/{webhook_id}/ The endpoint updates a webhook. # Retrieve a webhook endpoint Source: https://docs.truv.com/api-reference/webhooks/webhooks_read GET /v1/webhooks/{webhook_id}/ This endpoint retrieves a webhook. # Direct Deposit Switch Source: https://docs.truv.com/banking/integration/dds Switch customer direct deposits to your bank using the Deposit Switch demo Switch a new customer's paycheck deposit to your bank by embedding Truv Bridge in your application. The customer connects their payroll provider, selects an allocation, and Truv handles the deposit switch automatically. **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) (User + Bridge Token flow) | **Products:** DDS | **Demo:** [Direct Deposit Switch](/developers/demos/retail-banking/direct-deposit-switch) *** ## Get started Clone and run the [Direct Deposit Switch demo](/developers/demos/retail-banking/direct-deposit-switch) to see the full direct deposit switch flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Retail Banking > Deposit Switch**, and walk through a switch using sandbox credentials (`goodlogin` / `goodpassword`). See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Create a user** — Your server calls [POST /v1/users/](/api-reference/users/users_create) to create a Truv user. 2. **Create a bridge token** — Your server calls [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) with `product_type: "deposit_switch"` and an `account` object containing your bank's account details and allocation preferences. 3. **Initialize Bridge** — Your frontend opens [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. The customer connects their payroll provider and confirms the deposit switch. 4. **Receive webhooks** — Truv sends a `task-status-updated` [webhook](/api-reference/webhooks) with status `done` when the switch completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 5. **Retrieve the report** — Fetch the deposit switch confirmation with [GET /v1/users//deposit\_switch/report/](/api-reference/dds-reports/dds-report-retrieve). Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | --------------------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | | User creation | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users/](/api-reference/users/users_create) | | Bridge token creation | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) | | Bridge initialization | [`src/demos/DepositSwitch.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/DepositSwitch.jsx) | [Bridge SDK](/developers/sdks/overview) | | Webhook handling | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Report retrieval | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [DDS report](/api-reference/dds-reports/dds-report-retrieve) | *** ## Configure account details Pass your bank's account details in the `account` object when creating the bridge token. These fields tell Truv where to route the customer's paycheck. | Field | Required | Description | | ---------------- | -------- | ---------------------------------------------------------------------------- | | `account_number` | Yes | Your bank account number (4-20 digits) | | `routing_number` | Yes | Your bank routing number (8-12 digits) | | `bank_name` | Yes | Your bank's display name | | `account_type` | Yes | `checking` or `savings` | | `deposit_type` | No | Allocation type: `entire`, `amount`, or `percent` | | `deposit_value` | No | Amount or percentage (required when `deposit_type` is `amount` or `percent`) | *** ## Set allocation type Control how much of the customer's paycheck routes to your bank. Choose one of three allocation types. | Allocation | `deposit_type` | `deposit_value` | Behavior | | ------------- | -------------- | ------------------------------- | ----------------------------------- | | Full paycheck | `entire` | Not required | Routes the entire paycheck | | Fixed amount | `amount` | Dollar amount (e.g. `"500.00"`) | Routes a specific dollar amount | | Percentage | `percent` | Percentage (e.g. `"50"`) | Routes a percentage of the paycheck | ### Full paycheck ```json theme={null} { "account_number": "16002600", "routing_number": "123456789", "bank_name": "Your Bank", "account_type": "checking", "deposit_type": "entire" } ``` ### Fixed amount ```json theme={null} { "account_number": "16002600", "routing_number": "123456789", "bank_name": "Your Bank", "account_type": "checking", "deposit_type": "amount", "deposit_value": "500.00" } ``` ### Percentage ```json theme={null} { "account_number": "16002600", "routing_number": "123456789", "bank_name": "Your Bank", "account_type": "checking", "deposit_type": "percent", "deposit_value": "50" } ``` *** ## Next steps Full implementation guide for the User + Bridge Token flow Test deposit switching in sandbox Handle task-status-updated and other webhook events Retrieve deposit switch confirmation reports # Retail Banking Source: https://docs.truv.com/banking/overview Direct deposit switching and paycheck-linked lending for banks and fintech Truv helps banks and fintech companies acquire customers through direct deposit switching and enable paycheck-linked lending for loan repayment. Automatically switch customer direct deposit to your bank Automatic loan repayment from paycheck Connect to most US payroll providers Changes take effect on next pay cycle *** ## Quick start Run the demo app to see deposit switching end-to-end, then follow the integration guide to build it into your app. [Clone the demo app →](https://github.com/truvhq/demo-apps) *** ## What you can do **Use cases:** * New account funding * Customer acquisition * Payroll deposit capture **How it works:** 1. Customer connects their payroll account 2. Truv updates direct deposit settings 3. Next paycheck deposits to your bank **Use cases:** * Consumer loan repayment * Earned wage access repayment * Subscription collection **How it works:** 1. Customer authorizes payroll deduction 2. Set repayment amount (fixed or percentage) 3. Payment automatically deducted each pay period *** ## Integration: User Token Flow Direct deposit switch via Truv Bridge **Deposit Switch and Paycheck Linked Lending use the [Bridge Widget](/developers/integration/bridge-widget/overview) flow** (User + Bridge Token). Other verification use cases use [Embedded Orders](/developers/integration/embedded-orders/overview). *** ## How it works ### Deposit Switch Flow ```mermaid theme={null} sequenceDiagram participant Customer participant Your App participant Truv participant Payroll Customer->>Your App: Open new account Your App->>Truv: Create bridge token Truv-->>Your App: bridge_token Your App->>Customer: Show Truv Bridge Customer->>Truv: Connect payroll Truv->>Payroll: Update direct deposit Payroll-->>Truv: Confirmed Truv-->>Your App: Webhook: task-status-updated (done) Note over Payroll: Next paycheck deposits to your bank ``` ### Paycheck Linked Lending Flow ```mermaid theme={null} sequenceDiagram participant Borrower participant Your App participant Truv participant Payroll Borrower->>Your App: Accept loan terms Your App->>Truv: Create bridge token Truv-->>Your App: bridge_token Borrower->>Truv: Connect payroll Your App->>Truv: Configure PLL deduction Truv->>Payroll: Set up deduction Note over Payroll: Each pay period Payroll->>Your App: Deduction sent ``` *** ## Implementation timeline | Integration Method | Timeline | Code Required | | --------------------------- | --------- | ------------- | | **Deposit Switch** | 2-4 weeks | Moderate | | **Paycheck Linked Lending** | 2-4 weeks | Moderate | *** ## Get started * Acquiring deposits? --> [Deposit Switch](/banking/products/dds) * Loan repayment? --> [Paycheck Linked Lending](/credit/products/pll) Switch customer deposits to your bank Set up paycheck-linked loan repayment Test with sandbox credentials before going live *** ## Next steps Implement deposit switching Complete API documentation Talk to our banking solutions team [support@truv.com](mailto:support@truv.com) # Transactions Source: https://docs.truv.com/banking/products/bank-aggregation Bank account and transaction data for fintech applications Bank Aggregation provides access to bank account balances and transaction data for fintech applications. Use it for account funding verification, balance checks, and cash flow analysis alongside Deposit Switch or Paycheck Linked Lending. *** ## Benefits Confirm account ownership and balances instantly Up to 2 years of categorized transactions Identify recurring payroll deposits automatically 30/60/90-day average balance calculations *** ## What you get | Data Point | Description | | ----------------------- | ------------------------------------------------------- | | **Account balances** | Current and available balances for checking and savings | | **Transaction history** | Individual transactions over the lookback period | | **Account ownership** | Verified account holder information | | **Cash flow analysis** | Deposit and withdrawal patterns | | **Account metadata** | Account type, institution name, routing number | *** ## Use cases Confirm that a new customer's bank account is real and funded before enabling Deposit Switch. Verify sufficient funds before initiating transfers or setting up Paycheck Linked Lending deductions. Analyze deposit and withdrawal patterns to assess customer financial health. Identify recurring payroll deposits as a complementary income signal. *** ## How to implement Bank Aggregation uses the **Embedded Orders** flow, unlike Deposit Switch and Paycheck Linked Lending which use the User Token flow. See [Embedded Orders](/developers/integration/embedded-orders/overview) for details. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["transactions"], "first_name": "John", "last_name": "Doe", "external_user_id": "user-123" }' ``` *** ## Data coverage ### Financial Institutions Truv connects to major banks and credit unions: | Institution Type | Examples | | ---------------- | ----------------------------------------- | | National banks | Chase, Bank of America, Wells Fargo, Citi | | Regional banks | PNC, US Bank, TD Bank | | Credit unions | Navy Federal, State Employees CU | | Online banks | Ally, Marcus, Discover | | Neobanks | Chime, Current, Varo | *** ## API reference Create tokens for Truv Bridge Financial account details Account balance data Create and manage users *** ## Best practices Request enough transaction history to identify recurring patterns. 60 days of data is the default and typically sufficient for cash flow analysis and recurring deposit identification. Verify account funding before enabling Deposit Switch to ensure the customer's account is active and in good standing. Focus on recurring deposits to estimate stable income from bank transaction data. *** ## Next steps Integration guide for Bank Aggregation Direct Deposit Switch integration guide # Deposit Switch Source: https://docs.truv.com/banking/products/dds Automatically switch customer direct deposit to your bank Deposit Switch (DDS) enables you to redirect customer paychecks to your bank account by updating their payroll direct deposit settings. The process is fully digital -- customers connect their payroll account, and Truv handles the rest. **Try the demo** — Run the [Direct Deposit Switch demo](/banking/integration/dds) to see deposit switching working end-to-end. [Clone the demo app →](https://github.com/truvhq/demo-apps) *** ## How it works The customer authenticates with their employer's payroll system through Truv Bridge. You specify how much of the paycheck to redirect: full, partial percentage, or a fixed dollar amount. Truv automatically updates the direct deposit settings with the customer's payroll provider. Starting with the next pay cycle, the customer's paycheck deposits to your bank. *** ## Benefits Paychecks arrive automatically with no manual transfers Strong incentive for customers to switch primary banking Works with most US payroll providers No documents or manual forms needed *** ## Allocation types | Type | Description | Example | | --------- | ---------------------- | ------------------ | | `entire` | Full paycheck | 100% of paycheck | | `percent` | Percentage of paycheck | 50% of paycheck | | `amount` | Fixed dollar amount | \$500 per paycheck | Deposit Switch uses the **User Token flow** instead of Embedded Orders. This gives you direct control over the payroll connection and deposit allocation configuration. *** ## Data coverage ### Payroll Providers Truv connects to payroll providers covering 85%+ of US employees: | Provider | Coverage | | ------------- | ------------------- | | ADP | \~20% of US workers | | Paychex | \~10% of US workers | | Workday | Large enterprises | | UKG (Kronos) | Healthcare, retail | | Paylocity | Mid-market | | Gusto | Small business | | And 100+ more | | *** ## API reference Create tokens for Truv Bridge Deposit switch report DDS link detail report Create and manage users *** ## Best practices Starting with a partial deposit (e.g., 50%) reduces friction and increases conversion. Encourage full switching later once the customer is comfortable. After a successful webhook, inform the customer that their direct deposit has been updated and when they can expect the first deposit. Watch for `task-status-updated` webhooks to detect if the payroll provider rejects the change or the customer reverses it. *** ## Next steps Demo-first guide to implementing deposit switching Understand the User + Bridge Token integration flow # Document Processing Source: https://docs.truv.com/banking/products/document-processing AI-powered document upload and verification for banking and fintech Truv Document Processing lets you accept documents directly from users when a live payroll connection isn't possible. Truv's AI automatically splits, classifies, and extracts data from uploaded files, delivering the same structured output as a direct payroll connection. For banking and fintech, document upload supports account opening workflows, income verification for credit decisions, and identity verification when direct connections aren't available. *** ## Benefits Extract income, employment, and tax data from documents Paystubs, W-2s, 1099s, bank statements, and more Automatic document type and readability checks Seamless fallback when payroll connection unavailable *** ## Banking use cases Verify income and employment as part of new account onboarding Accept pay stubs and tax returns when payroll connection isn't available for income-based lending Extract and validate identity documents (driver's license, passport) alongside income documents When a user can't connect via payroll for deposit switching, verify employment through documents *** ## Supported document types ### Income & employment documents | Document | Type Code | | ---------------- | --------- | | Pay stubs | `PAYSTUB` | | W-2s | `W2` | | 1099s | `F1099` | | 1040 tax returns | `F1040` | ### Additional document types | Document | Type Code | | ----------------- | ---------------- | | Bank statements | `BANK_STATEMENT` | | Driver's licenses | `DRIVER_LICENSE` | | Passports | `PASSPORT` | | Green cards | `GREEN_CARD` | | Utility bills | `UTILITY_BILL` | *** ## How it works 1. **Create a document collection**: Initialize a container for the user's documents. Upload one or more files (Base64-encoded PDFs or images) in the same request, or add files incrementally. 2. **Truv validates and classifies**: Truv validates each file and classifies document types using AI. Fraud detection checks every document against 50M+ verified pay stubs. With [intelligent intake](/developers/integration/document-processing#intelligent-intake), users can upload any mix of files — including phone photos — and Truv flags unreadable scans up front and recognizes which files count. 3. **Finalize the collection**: Trigger processing for the full collection or selectively finalize specific documents. Truv generates Links with structured income and employment data. 4. **Retrieve verified data**: When the processing Task completes (`task-status-updated` webhook with `status: done`), fetch the report. Same format as a live payroll connection. *** ## API reference Upload and process documents via the Collections API Manage document collections Retrieve parsed data *** ## Next steps Platform-level document processing guide Full API reference for document collections # Smart Login Source: https://docs.truv.com/banking/smart-login Truv Smart Login presents the best authentication method for each user to maximize deposit switch and PLL conversion Truv's Smart Login has business logic in place to present the best authentication method with the highest likelihood of success based on: * Employer selected * Historical successes * Payroll system compatibility *** ## Authentication methods In-bridge redirect to payroll provider. A Truv patented solution available across some of the largest provider integrations to increase coverage and leverage password managers. Leverage employee credentials to access payroll systems. Truv has integrations to 64 SSO systems, enabling customers to log in the same way they do at work. Leverage trusted phone or email for one-time passcode. Currently supported by ADP and Paycom. For employers behind VPNs: iOS uses Apple's AppClip, Android uses Instant App. QR codes available for desktop users. Truv maps over 300,000 employers to payroll providers so customers don't need to make that selection. For unmapped employers, Truv recommends providers based on historical data and employer size distribution. *** ## Fallback options When primary authentication paths are unavailable, Truv provides fallback options for Deposit Switch and Paycheck Linked Lending flows: Customers can generate a prefilled, e-signed PDF with account number, routing number, and allocation information to download and send to HR. Truv displays the customer's account number, routing number, and bank details so they can manually enter the information in their payroll system. *** ## Why this matters for banking Smart Login is particularly important for Deposit Switch and Paycheck Linked Lending because: * **Higher conversion**: Presenting the right login method first reduces drop-off during the payroll authentication step * **Broader coverage**: Multiple authentication paths mean more employers are supported, expanding your eligible customer base * **Fallback safety net**: Even if a direct connection fails, eSigned PDF and manual entry options ensure the member can still complete the flow * **Reduced support burden**: Fewer authentication failures mean fewer support tickets and better member experience *** ## Next steps Implement Direct Deposit Switch Implement Paycheck Linked Lending # Document Processing Source: https://docs.truv.com/credit/data-sources/document-processing Collect and process documents for income and employment verification Collect user documents, extract structured data, and analyze them for fraud with Truv's document processing. Common use cases include: * **Fallback** for unsuccessful payroll connection attempts * **Standalone solution** to collect and parse documents into structured data **Try the demo** -- The [Smart Routing demo](/credit/integration/smart-routing) includes document upload as a fallback verification method. [Clone the demo app ->](https://github.com/truvhq/demo-apps) *** ## Supported document types * Paystubs * W-2s * 1099 tax forms (1099-DIV, 1099-G, 1099-INT, 1099-MISC, 1099-NEC, 1099-R, any year after 2021) Files can be PDFs or phone photos. With [intelligent intake](/developers/integration/document-processing#intelligent-intake), Truv classifies each uploaded file, flags unreadable scans up front, and lets you finalize only the documents you need. *** ## Configure bridge token When creating a [Truv Bridge](/developers/sdks/overview) [Token](/api-reference/bridge-token/users_tokens), include `product_type = income` and `data_sources = ["docs"]`: ```bash theme={null} curl -X POST https://prod.truv.com/v1/users/{user_id}/tokens/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "product_type": "income", "data_sources": ["docs"], "tracking_info": "any data for tracking" }' ``` *** ## Testing ### Successful Documents Upload these PDFs for successful sandbox responses: * [Most recent paystub](https://prod.truv.com/v1/permalink/most.recent.paystub.pdf) * [Next recent paystub](https://prod.truv.com/v1/permalink/next.recent.paystub.pdf) * [First paystub](https://prod.truv.com/v1/permalink/first.paystub.pdf) * [W2](https://prod.truv.com/v1/permalink/w2.pdf) ### 1099 Tax Forms * [1099-DIV](https://prod.truv.com/v1/permalink/1099div.pdf), [1099-G](https://prod.truv.com/v1/permalink/1099g.pdf), [1099-INT](https://prod.truv.com/v1/permalink/1099int.pdf), [1099-MISC](https://prod.truv.com/v1/permalink/1099misc.pdf), [1099-NEC](https://prod.truv.com/v1/permalink/1099nec.pdf), [1099-R](https://prod.truv.com/v1/permalink/1099r.pdf), [SSA-1099](https://prod.truv.com/v1/permalink/ssa1099.pdf) Test scenarios use the file name to return results. Testing ignores file contents in sandbox. *** ## Suspicious document detection ### Suspicious Flag (`is_suspicious`) When processing documents, Truv may flag them as suspicious while still completing the task. The `is_suspicious` flag indicates potential document manipulation that warrants additional review. #### When Documents Are Flagged Documents are flagged when PDF metadata indicates potential manipulation, including software like FoxitPDF, Adobe Scan, CamScanner, and other document editing applications. * **Too Early:** Pay date before the pay period start date * **Too Late:** Pay date 30+ days after the pay period end date Documents created through browser "Print to Save as PDF" on non-PDF files are flagged because the original content may have been modified before conversion. #### When Documents Are Failed In cases of high-confidence fraud, the task fails entirely: * **Known fraud templates**: Document matches a known fraudulent template * **Obvious manipulation tools**: PDF metadata indicates use of tools like iLovePDF, Canva, etc. Documents flagged as `is_suspicious = true` are still processed and results are returned. Failed documents do not return results and require resubmission. *** ## API reference Upload and process documents via the Collections API Manage document collections Retrieve parsed data Create tokens for Truv Bridge *** ## Next steps Tax return verification Full Document Processing API walkthrough # Tax Returns Source: https://docs.truv.com/credit/data-sources/tax-returns Verify income through tax preparation software connections Verify income instantly through tax preparation software connections. Skip the wait for IRS tax returns and 4506-C documents while improving conversion rates. Truv supports connections to major tax preparation software providers through [Truv Bridge](/developers/sdks/overview), including F1040 document support. *** ## Configure bridge token When creating a [Bridge Token](/api-reference/bridge-token/users_tokens), include `product_type = income` and `data_sources = ["tax"]`: ```bash theme={null} curl -X POST https://prod.truv.com/v1/users/{user_id}/tokens/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "product_type": "income", "data_sources": ["tax"], "tracking_info": "any data for tracking" }' ``` *** ## Example response The JSON data below is a sample payload from the tax documents endpoint: ```json theme={null} [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "document_type": "F1040", "document_subtype": "", "file": "https://example.com/tax_sample.pdf", "md5sum": "24d7e80942ce4ad58a93f70ce4115f5c", "year": 2019 } ] ``` *** ## Testing Use the credentials below for sandbox testing: | Username | Password | SSN | Scenario | | --------------- | -------------- | ------------- | ----------------------------------- | | `goodlogin.tax` | `goodpassword` | `991-91-9991` | Successful login with complete data | ### Error Scenarios | Username | Password | Scenario | | ------------ | ---------------- | --------------------------------- | | `error.user` | `login_error` | Incorrect login and password | | `error.user` | `mfa_error` | Multi-factor authentication issue | | `error.user` | `account_locked` | Locked account | | `error.user` | `no_data` | No data found | | `error.user` | `unavailable` | Provider maintenance | | `error.user` | `error` | Generic login error | *** ## API reference Tax document schema and endpoints Create tokens for Truv Bridge Create and manage users *** ## Next steps Upload and process documents # Bank Income Source: https://docs.truv.com/credit/integration/bank-income Verify applicant income from bank transactions using income insights Verify income by connecting to the applicant's bank account and analyzing transaction history. Truv generates an [income insights report](/api-reference/income-insights/income-insights-report-create) from deposit patterns, giving you income data even when payroll connections are unavailable. **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** Income Insights | **Demo:** [Bank Income](/developers/demos/consumer-credit/bank-income) *** ## Get started Clone and run the [Bank Income demo](/developers/demos/consumer-credit/bank-income) to see the full bank income verification flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Consumer Credit > Bank Income**, and walk through a verification using sandbox credentials (`goodlogin` / `goodpassword`). See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Search for financial institution** -- Your server calls [GET /v1/providers/](/api-reference/data-providers/providers-list) with `data_source=financial_accounts` to find the applicant's bank. The response returns a `provider_id`. 2. **Create a user** -- Your server calls [POST /v1/users/](/api-reference/users/users_create) to create a Truv user. 3. **Create a bridge token** -- Your server calls [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) with `product_type: "income"`, `data_sources: ["financial_accounts"]`, and optionally `provider_id` to [deeplink](/developers/integration/bridge-widget/deeplinking) Bridge to the bank. 4. **Initialize Bridge** -- Your frontend opens [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. The applicant connects their bank account. 5. **Receive webhooks** -- Truv sends a `task-status-updated` [webhook](/api-reference/webhooks) when verification completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 6. **Retrieve the income insights report** -- Fetch the report with [POST /v1/users//income\_insights/reports/](/api-reference/income-insights/income-insights-report-create). The report contains income derived from bank transaction analysis. Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | Institution search | [`src/components/CompanySearch.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/components/CompanySearch.jsx) | [Providers List](/api-reference/data-providers/providers-list) | | User creation | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users/](/api-reference/users/users_create) | | Bridge token | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) | | Bridge initialization | [`src/demos/BankIncome.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/BankIncome.jsx) | [Bridge SDK](/developers/sdks/overview) | | Webhook verification | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Report retrieval | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Income Insights Report](/api-reference/income-insights/income-insights-report-create) | *** ## Consumer Credit-specific configuration ### Bridge token for bank income Set `data_sources` to `["financial_accounts"]` to restrict Bridge to bank connections only: ```json theme={null} { "product_type": "income", "data_sources": ["financial_accounts"], "provider_id": "PROVIDER_ID" } ``` Pass `provider_id` from the [providers search](/api-reference/data-providers/providers-list) to deeplink Bridge directly to the bank. Without it, Bridge shows its own institution search. Bank income uses `provider_id` (not `company_mapping_id`). The `company_mapping_id` field is for payroll employers. Passing the wrong identifier type causes Bridge to show a generic search screen. ### Income insights report Bank income verification returns an [income insights report](/api-reference/income-insights/income-insights-report-create) instead of a standard VOIE report. Income insights are derived from transaction patterns rather than payroll data. The report includes: * Estimated annual income * Income streams and frequency * Transaction-level detail *** ## How bank income differs from payroll VOIE Bank income analyzes deposit transactions in the applicant's bank account to derive income. It does **not** connect to payroll systems. This means the data shape and coverage differ significantly from a standard [payroll income](/credit/integration/payroll-income) verification. ### Data comparison | Data point | Payroll VOIE | Bank income | | ---------------------- | ------------------------------------- | ------------------------------------------------------ | | Income amount | Exact gross/net from paystubs | Estimated from deposit patterns | | Employer name | From payroll provider | Not available (inferred from transaction descriptions) | | Pay frequency | Exact (`BW`, `SM`, `M`, etc.) | Estimated from deposit cadence | | Deductions breakdown | Federal/state taxes, benefits, 401k | Not available | | W-2 forms | Available when employer provides them | Not available (`w2s` is always null) | | Employment dates | From payroll records | Not available | | Bank account details | Not included under employments | Included in the income insights report | | Self-employment income | Not captured | Captured from deposit patterns | | Gig / on-demand income | Not captured | Captured from deposit patterns | | Government benefits | Requires SSA connection | Detected from deposit patterns | ### Report structure notes * The `bank_income_summary` arrays are structured to support multiple currencies, but in practice contain only USD entries. * Fields standard to payroll VOIE that are always null in bank income responses: `w2s`, `bank_accounts` under employments, and standard payroll deduction line items. * Income amounts are derived estimates, not exact figures from pay stubs. ### When to use bank income vs payroll | Scenario | Recommended approach | | ----------------------------------------- | ------------------------------------------------------------------------------ | | W-2 employee at a large employer | Payroll VOIE -- higher data quality and exact figures | | Self-employed or freelance | Bank income -- payroll VOIE has no coverage | | Gig worker (Uber, DoorDash, etc.) | Bank income -- deposits appear in bank transactions | | Government benefit recipient | Bank income or direct SSA connection | | Multiple income streams | Both -- payroll VOIE for the primary job, bank income for supplemental sources | | Employer not covered by payroll providers | Bank income as fallback | For the most complete income picture, include both `income` and `assets` products in your [order](/api-reference/orders/orders_create). The `income` product captures payroll-connected employment, while `assets` with `data_sources: ["financial_accounts"]` enables bank income analysis. The applicant connects both in a single Bridge session. *** ## Next steps Automatically recommend the best method based on employer coverage Verify income directly from payroll for higher data quality Full implementation guide for user creation, bridge tokens, and Bridge initialization Full API reference for income insights reports # Integration for Consumer Credit Source: https://docs.truv.com/credit/integration/implementation Choose the right verification method for your lending workflow Verify applicant income, employment, and assets by embedding [Truv Bridge](/developers/sdks/overview) in your lending application. Choose the verification method that fits your use case. All Consumer Credit integrations use the [Bridge Widget](/developers/integration/bridge-widget/overview) flow. Create a [user](/api-reference/users/users_create) and [bridge token](/api-reference/bridge-token/users_tokens), then open Bridge for the applicant to connect. *** ## Choose your verification method | Method | What it does | Data source | Best for | Demo | | ---------------------------------------------------- | --------------------------------------------------- | ---------------------- | -------------------------------------- | ---------------------------------------------------------- | | [Smart Routing](/credit/integration/smart-routing) | Check employer coverage, recommend the fastest path | Payroll, bank, or docs | Most lending workflows | [SmartRouting](https://github.com/truvhq/demo-apps) | | [Bank Income](/credit/integration/bank-income) | Verify income from bank transactions | Financial accounts | Thin-file borrowers, gig workers | [BankIncome](https://github.com/truvhq/demo-apps) | | [Payroll Income](/credit/integration/payroll-income) | Verify income directly from payroll | Payroll | Employed borrowers with payroll access | [PayrollIncome](https://github.com/truvhq/demo-apps) | | [Paycheck-Linked Loans](/credit/integration/pll) | Set up automatic loan repayment from paycheck | Payroll | Post-approval repayment | [PaycheckLinkedLoans](https://github.com/truvhq/demo-apps) | *** ## API flow All Consumer Credit integrations follow the same User + Bridge Token flow: 1. **Create a user** -- Your server calls [POST /v1/users/](/api-reference/users/users_create). 2. **Create a bridge token** -- Your server calls [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) with the `product_type` and `data_sources` for the chosen method. 3. **Open Bridge** -- Your frontend initializes [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. The applicant connects their provider. 4. **Receive webhooks** -- Truv sends a `task-status-updated` [webhook](/api-reference/webhooks) when verification completes. 5. **Fetch the report** -- Your server retrieves the [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) or [income insights report](/api-reference/income-insights/income-insights-report-create) depending on the method. *** ## Combine methods Most production implementations combine two or more approaches: * **Smart Routing + PLL**: Verify income during the application, then set up automatic repayment after approval. * **Payroll + Bank**: Try payroll first for the best data quality. Fall back to bank income when the employer has low payroll coverage. * **Any method + Documents**: Enable document upload as a fallback in Bridge when direct connections are unavailable. *** ## Next steps Automatically recommend the best verification method for each applicant Verify income from bank transactions when payroll is unavailable Connect directly to payroll for verified income and employment data Set up automatic loan repayment from the borrower's paycheck # Payroll Income Source: https://docs.truv.com/credit/integration/payroll-income Verify applicant income and employment directly from payroll providers Verify income and employment by connecting directly to the applicant's payroll provider. This delivers the highest data quality -- verified pay history, employer details, and current employment status -- for lending decisions. **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** VOIE | **Demo:** [Payroll Income](/developers/demos/consumer-credit/payroll-income) *** ## Get started Clone and run the [Payroll Income demo](/developers/demos/consumer-credit/payroll-income) to see the full payroll income verification flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Consumer Credit > Payroll Income**, and walk through a verification using sandbox credentials (`goodlogin` / `goodpassword`). See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Search for employer** -- Your server calls [GET /v1/company-mappings-search/](/api-reference/companies/company_autocomplete_search) to find the applicant's employer by name. The response returns a `company_mapping_id`. 2. **Create a user** -- Your server calls [POST /v1/users/](/api-reference/users/users_create) to create a Truv user. 3. **Create a bridge token** -- Your server calls [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) with `product_type: "income"`, `data_sources: ["payroll"]`, and `company_mapping_id` to [deeplink](/developers/integration/bridge-widget/deeplinking) Bridge to the employer. 4. **Initialize Bridge** -- Your frontend opens [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. The applicant connects their payroll account. 5. **Receive webhooks** -- Truv sends a `task-status-updated` [webhook](/api-reference/webhooks) when verification completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 6. **Retrieve the VOIE report** -- Fetch the report with [POST /v1/users//reports/](/api-reference/user-income-and-employment-reports/users_reports). The report contains verified income and employment data from the payroll provider. Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Employer search | [`src/components/CompanySearch.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/components/CompanySearch.jsx) | [Company Search](/api-reference/companies/company_autocomplete_search) | | User creation | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users/](/api-reference/users/users_create) | | Bridge token | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) | | Bridge initialization | [`src/demos/PayrollIncome.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/PayrollIncome.jsx) | [Bridge SDK](/developers/sdks/overview) | | Webhook verification | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Report retrieval | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Income reports](/api-reference/user-income-and-employment-reports/users_reports) | *** ## Consumer Credit-specific configuration ### Bridge token for payroll income Set `data_sources` to `["payroll"]` to restrict Bridge to payroll connections only: ```json theme={null} { "product_type": "income", "data_sources": ["payroll"], "company_mapping_id": "COMPANY_MAPPING_ID" } ``` Pass `company_mapping_id` from the [company search](/api-reference/companies/company_autocomplete_search) to deeplink Bridge directly to the employer's payroll provider. Without it, Bridge shows a generic employer search screen. Payroll income uses `company_mapping_id` (not `provider_id`). The `provider_id` field is for financial institutions like banks. Passing the wrong identifier type causes Bridge to show a generic search screen. ### VOIE report Payroll income verification returns a standard [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) containing: * Current and historical income (base pay, overtime, bonuses, commissions) * Employment details (employer name, hire date, status) * Pay frequency and YTD earnings The `income` product type includes employment data automatically. You do not need to request `employment` separately. *** ## Next steps Automatically recommend payroll, bank, or documents based on employer coverage Fall back to bank transactions when payroll coverage is low Full implementation guide for user creation, bridge tokens, and Bridge initialization Skip the employer search when you already know the company # Paycheck-Linked Loans Source: https://docs.truv.com/credit/integration/pll Set up automatic loan repayment directly from the borrower paycheck via payroll deduction Set up automatic loan repayment by connecting to the borrower's payroll provider. The borrower authenticates through [Truv Bridge](/developers/sdks/overview), and Truv routes a fixed amount or percentage of each paycheck to your bank account. You also receive a verified income report alongside the deposit switch confirmation. **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** PLL (Paycheck-Linked Lending) | **Demo:** [Paycheck-Linked Loans](/developers/demos/consumer-credit/paycheck-linked-loans) *** ## Get started Clone and run the [Paycheck-Linked Loans demo](/developers/demos/consumer-credit/paycheck-linked-loans) to see the full paycheck-linked lending flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Consumer Credit > Paycheck-Linked Loans**, and walk through a verification using sandbox credentials (`goodlogin` / `goodpassword`). See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Search for employer** -- Your server calls [GET /v1/company-mappings-search/](/api-reference/companies/company_autocomplete_search) to find the borrower's employer by name. 2. **Create a user** -- Your server calls [POST /v1/users/](/api-reference/users/users_create) to create a Truv user. 3. **Create a bridge token** -- Your server calls [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) with `product_type: "pll"` and optionally `company_mapping_id` to [deeplink](/developers/integration/bridge-widget/deeplinking) Bridge to the employer. Include the `account` object with your bank details and deduction configuration. 4. **Initialize Bridge** -- Your frontend opens [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. The borrower connects their payroll and confirms the deduction. 5. **Receive webhooks** -- Truv sends a `task-status-updated` [webhook](/api-reference/webhooks) when the enrollment completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 6. **Retrieve dual reports** -- Fetch the [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) with `POST /v1/users/{user_id}/reports/` for income data. Fetch the [deposit switch report](/api-reference/dds-reports/dds-report-retrieve) with `GET /v1/users/{user_id}/deposit_switch/report/` for deduction confirmation. Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | --------------------- | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Employer search | [`src/components/CompanySearch.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/components/CompanySearch.jsx) | [Company Search](/api-reference/companies/company_autocomplete_search) | | User creation | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users/](/api-reference/users/users_create) | | Bridge token | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) | | Bridge initialization | [`src/demos/PaycheckLinkedLoans.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/PaycheckLinkedLoans.jsx) | [Bridge SDK](/developers/sdks/overview) | | Webhook verification | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Income report | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Income reports](/api-reference/user-income-and-employment-reports/users_reports) | | Deposit switch report | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Deposit switch report](/api-reference/dds-reports/dds-report-retrieve) | *** ## Consumer Credit-specific configuration ### Bridge token for PLL Set `product_type` to `"pll"` and include the `account` object with your bank details and deduction configuration: ```json theme={null} { "product_type": "pll", "company_mapping_id": "COMPANY_MAPPING_ID", "account": { "account_number": "16002600", "routing_number": "123456789", "bank_name": "Your Bank", "account_type": "checking", "deposit_type": "amount", "deposit_value": "200.00" } } ``` ### Deduction options Control the repayment amount with `deposit_type` and `deposit_value`: | `deposit_type` | `deposit_value` | Description | | -------------- | --------------- | -------------------------------- | | `amount` | `"200.00"` | Fixed dollar amount per paycheck | | `percent` | `"10"` | Percentage of each paycheck | ### Dual reports PLL verification produces two reports in parallel: | Report | Endpoint | What it contains | | ------------------------------------------------------------------------------ | ------------------------------------------------ | ---------------------------------------------- | | [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) | `POST /v1/users/{user_id}/reports/` | Verified income, employment, and pay history | | [Deposit switch report](/api-reference/dds-reports/dds-report-retrieve) | `GET /v1/users/{user_id}/deposit_switch/report/` | Deduction confirmation with allocation details | Both reports become available after the `task-status-updated` webhook fires with `status: done`. Fetch them in parallel for the fastest results. *** ## Next steps Verify income before approval, then set up PLL after Full implementation guide for user creation, bridge tokens, and Bridge initialization Product details for Paycheck-Linked Lending Handle all Bridge lifecycle events and error codes # Smart Routing Source: https://docs.truv.com/credit/integration/smart-routing Automatically recommend the best verification method based on employer payroll coverage Route each applicant to the fastest verification path -- payroll, bank transactions, or document upload -- based on their employer's payroll coverage. The system checks coverage via [company search](/api-reference/companies/company_autocomplete_search), recommends a method, and lets the applicant confirm or override. **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** VOIE, Income Insights | **Demo:** [Smart Routing](/developers/demos/consumer-credit/smart-routing) *** ## Get started Clone and run the [Smart Routing demo](/developers/demos/consumer-credit/smart-routing) to see the full smart routing flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Consumer Credit > Smart Routing**, and walk through a verification using sandbox credentials (`goodlogin` / `goodpassword`). See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Search for employer** -- Your server calls [GET /v1/company-mappings-search/](/api-reference/companies/company_autocomplete_search) to find the applicant's employer. The `success_rate` field in the response determines the recommendation: `high` suggests payroll, `low`/`medium` suggests bank, and no results suggests documents. 2. **Create a user** -- Your server calls [POST /v1/users/](/api-reference/users/users_create) to create a Truv user. 3. **Create a bridge token** -- Your server calls [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) with the selected `data_sources` array (`["payroll"]`, `["financial_accounts"]`, or `["docs"]`). Pass `company_mapping_id` for payroll to [deeplink](/developers/integration/bridge-widget/deeplinking) Bridge to the employer. 4. **Initialize Bridge** -- Your frontend opens [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. The applicant connects their provider. 5. **Receive webhooks** -- Truv sends a `task-status-updated` [webhook](/api-reference/webhooks) when verification completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 6. **Retrieve the report** -- For payroll or document methods, fetch the [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) with `POST /v1/users/{user_id}/reports/`. For bank income, fetch the [income insights report](/api-reference/income-insights/income-insights-report-create) with `POST /v1/users/{user_id}/income_insights/reports/`. Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Employer search | [`src/components/CompanySearch.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/components/CompanySearch.jsx) | [Company Search](/api-reference/companies/company_autocomplete_search) | | User creation | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users/](/api-reference/users/users_create) | | Bridge token | [`server/routes/bridge.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/bridge.js) | [POST /v1/users//tokens/](/api-reference/bridge-token/users_tokens) | | Bridge initialization | [`src/demos/SmartRouting.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/SmartRouting.jsx) | [Bridge SDK](/developers/sdks/overview) | | Webhook verification | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Report retrieval | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Income reports](/api-reference/user-income-and-employment-reports/users_reports) | *** ## Consumer Credit-specific configuration ### Routing logic The `success_rate` field from [company search](/api-reference/companies/company_autocomplete_search) drives the recommendation: | `success_rate` value | Recommended method | `data_sources` | | -------------------- | ------------------ | ------------------------ | | `high` | Payroll | `["payroll"]` | | `low` / `medium` | Bank transactions | `["financial_accounts"]` | | No results | Document upload | `["docs"]` | The applicant can always override the recommendation and pick any method. ### Data sources Control which verification methods Bridge shows by setting the `data_sources` array when creating the bridge token: ```json theme={null} { "product_type": "income", "data_sources": ["payroll"], "company_mapping_id": "COMPANY_MAPPING_ID" } ``` For payroll, pass `company_mapping_id` to deeplink Bridge to the employer. For bank income, pass `provider_id` to deeplink to the financial institution. Document upload requires no additional identifier. ### Report types The report endpoint depends on the method the applicant chose: | Method | Report endpoint | Report type | | ----------------- | --------------------------------------------------- | ------------------------------------------------------------------------------- | | Payroll | `POST /v1/users/{user_id}/reports/` | [VOIE](/api-reference/user-income-and-employment-reports/users_reports) | | Bank transactions | `POST /v1/users/{user_id}/income_insights/reports/` | [Income Insights](/api-reference/income-insights/income-insights-report-create) | | Documents | `POST /v1/users/{user_id}/reports/` | [VOIE](/api-reference/user-income-and-employment-reports/users_reports) | *** ## Next steps Verify income from bank transactions when payroll coverage is low Connect directly to payroll for the highest data quality Full implementation guide for user creation, bridge tokens, and Bridge initialization Skip the provider search screen when you already know the employer or bank # Consumer Credit Source: https://docs.truv.com/credit/overview Income and asset verification for auto loans, personal loans, and credit decisioning Truv helps consumer lenders verify borrower income and assets instantly, improving approval rates and reducing fraud. Real-time income verification for instant approvals Verify income for thin-file borrowers Direct data prevents document falsification No document uploads needed *** ## Quick start Run a demo app to see Truv in action, then follow the integration guide to build it into your workflow. Payroll-first with automatic document fallback Transaction-based income verification Direct payroll connection for income data Automatic loan repayment from paycheck *** ## What you can verify * Current income * Employment status * Pay frequency * YTD earnings * Bank balances * Account ownership * Transaction patterns * Cash flow analysis * Income deposits * Spending patterns *** ## Use cases Verify income for vehicle financing: * New and used car loans * Refinancing * Lease buyouts **Products:** Income & Employment, Assets Income verification for unsecured lending: * Debt consolidation * Home improvement loans * Emergency expenses **Products:** Income & Employment, Assets Income verification for credit limit decisions: * New account applications * Credit limit increases * Risk assessment **Products:** Income & Employment Quick income checks for BNPL: * Point-of-sale financing * Installment plans * Higher-ticket items **Products:** Income & Employment *** ## Integration options ### Option 1: Dashboard (No Code) Truv Dashboard and order landing page Use the Truv Dashboard to create and manage verification orders without any integration: * Create orders manually via the Dashboard UI * Send verification links to borrowers via email/SMS * View results directly in the Dashboard * Optionally add webhooks to sync data to your loan origination system [Learn more about Dashboard integration -->](/developers/dashboard) ### Option 2: Embedded Orders (Recommended) Embedded order For custom implementations or automated lending workflows: Payroll-first with automatic document fallback Transaction-based income verification Direct payroll connection for income data Automatic loan repayment from paycheck *** ## Implementation timeline | Integration Method | Timeline | Code Required | | ------------------- | --------- | ------------- | | **Dashboard** | Same day | None | | **Embedded Orders** | 2-4 weeks | Minimal | *** ## Get started * Quick start with no code? --> [Dashboard Integration](/developers/dashboard) * Building custom? --> Choose an integration from the [Quick start](#quick-start) section above Clone the [demo apps repo](https://github.com/truvhq/demo-apps) and run a demo to see the verification flow end-to-end. Test with various borrower scenarios Start verifying borrower income instantly *** ## Next steps Payroll-first with document fallback Complete API documentation Implementation guidelines Talk to our lending solutions team # Assets for Lending Source: https://docs.truv.com/credit/products/assets Asset verification for consumer lending Verify borrower bank account balances, ownership, and transaction history for lending decisions. Truv pulls data directly from financial institutions, giving you a verified view of borrower liquidity. *** ## Benefits Real-time account balances and transaction data Data from Chase, Bank of America, and thousands more 30/60/90-day balance averages and deposit patterns Verified ownership and large deposit flagging *** ## What you get * Account type (checking, savings, money market, CD, investment) * Verified account holder name and ownership * Current and available balances * Routing number and masked account number * Up to 2 years of transaction history (30-730 days via `days_requested`) * Date, description, amount, and type * Direct deposit identification * 30/60/90-day average balances * Balance history * Currency and metadata * Bank statements (PDF) * Account verification letter *** ## Use cases Confirm the borrower has sufficient liquid assets to cover the down payment and closing costs for auto or personal loans with collateral requirements. Evaluate total liquid assets across checking, savings, and investment accounts to determine borrower financial stability. Analyze deposit and withdrawal patterns to assess repayment capacity, especially useful for self-employed or gig-economy borrowers. Verify account ownership and flag unusual patterns such as large unexplained deposits or inconsistent account activity. *** ## Data coverage ### Financial Institutions Truv connects to major banks and credit unions: | Institution Type | Examples | | ---------------- | ----------------------------------------- | | National banks | Chase, Bank of America, Wells Fargo, Citi | | Regional banks | PNC, US Bank, TD Bank | | Credit unions | Navy Federal, State Employees CU | | Online banks | Ally, Marcus, Discover | | Investment | Fidelity, Charles Schwab, Vanguard | *** ## How to implement Choose your integration path based on your tech stack: | Path | Code required | Best for | | -------------------------------------------------- | ------------- | ------------------------------------ | | [Smart Routing](/credit/integration/smart-routing) | Minimal | Payroll-first with document fallback | | [Truv Dashboard](/developers/dashboard) | None | Manual orders, pilot testing | **Combine with Income & Employment for a complete picture.** Request both `assets` and `income` product types in a single order to verify both income and liquidity. [Learn about Income & Employment -->](/credit/products/income-employment) For a full implementation walkthrough including webhook handling and [Truv Bridge](/developers/sdks/overview) setup, see the [Smart Routing guide](/credit/integration/smart-routing). *** ## Report structure When you retrieve asset data via the API, the response contains a `links` array with accounts, balances, and transactions per financial institution. | Field | Path | Example | | --------------- | ----------------------------------------------------- | --------------------- | | Account type | `links[].accounts[].type` | `CHECKING`, `SAVINGS` | | Masked number | `links[].accounts[].mask` | `"1234"` | | Account holder | `links[].accounts[].owners[].full_name` | `"John Smith"` | | Current balance | `links[].accounts[].balances.current` | `"15420.50"` | | Direct deposit | `links[].accounts[].transactions[].is_direct_deposit` | `true` | | 30-day avg | `summary.avg_30` | `"14500.00"` | ```json theme={null} { "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab", "large_deposit_threshold": "2500.00", "summary": { "avg_30": "9200.50", "avg_60": "8850.75", "avg_90": "8500.00", "balance": "23750.25" }, "links": [ { "accounts": [ { "type": "CHECKING", "mask": "1234", "owners": [ { "full_name": "Jane Smith" } ], "balances": { "balance": "8750.25", "available_balance": "8500.00" }, "transactions": [ { "transacted_at": "2024-01-15T10:30:00Z", "posted_at": "2024-01-15T14:00:00Z", "description": "DIRECT DEPOSIT - ACME CORP", "amount": "2650.00", "type": "CREDIT", "is_direct_deposit": true } ] }, { "type": "SAVINGS", "mask": "5678", "owners": [ { "full_name": "Jane Smith" } ], "balances": { "balance": "15000.00", "available_balance": "15000.00" }, "transactions": [] } ] } ] } ``` *** ## API reference Create tokens for Truv Bridge Retrieve asset data Financial account details Create and manage users *** ## Best practices Use the `large_deposit_threshold` from the report and review transactions that exceed it: ```javascript theme={null} const largeDeposits = report.links .flatMap(link => link.accounts) .flatMap(account => account.transactions) .filter(t => t.type === "CREDIT" && t.amount >= report.large_deposit_threshold); ``` Filter for direct deposits to verify recurring income: ```javascript theme={null} const directDeposits = report.links .flatMap(link => link.accounts) .flatMap(account => account.transactions) .filter(t => t.is_direct_deposit); ``` Use the report-level summary or aggregate across all linked accounts: ```javascript theme={null} // Use the report summary for quick totals const totalBalance = report.summary.balance; // Or aggregate per-account balances const perAccount = report.links .flatMap(link => link.accounts) .map(a => ({ type: a.type, mask: a.mask, current: a.balances.current })); ``` *** ## Next steps Payroll-first with document fallback Transaction-level bank data # Transactions for Lending Source: https://docs.truv.com/credit/products/bank-aggregation Cash flow analysis and bank data for lending decisions Analyze transaction-level bank data for cash flow underwriting and alternative credit assessment. Connect directly to the borrower's bank through [Truv Bridge](/developers/sdks/overview) for a detailed view of income deposits, spending behavior, and balance trends. **Try the demo** -- Run the [Bank Income demo](/credit/integration/bank-income) to see bank transaction-based income verification. [Clone the demo app ->](https://github.com/truvhq/demo-apps) *** ## Benefits Real transaction data for repayment capacity Extend credit to thin-file and underserved borrowers Identify recurring deposits without payroll connection 30-730 days of transaction history, configurable per request *** ## What you get * Individual transactions with date, description, amount, and type * Recurring deposit identification * Expense categorization * Account type (checking, savings) * Verified account holder * Current and available balances * Routing and masked account number * Net cash flow trends * Balance history * Recurring income patterns * Spending behavior *** ## Use cases Analyze real transaction data to assess repayment capacity. Particularly effective for borrowers whose income is not easily captured by traditional pay stubs. Identify recurring deposits to estimate income when payroll-based verification is not available, such as for self-employed or gig-economy workers. Build a financial profile from transaction data for borrowers with thin credit files or limited credit history. Extend credit to underserved populations by supplementing traditional credit data with bank transaction insights. *** ## Data coverage ### Financial Institutions Truv connects to major banks and credit unions: | Institution Type | Examples | | ---------------- | ----------------------------------------- | | National banks | Chase, Bank of America, Wells Fargo, Citi | | Regional banks | PNC, US Bank, TD Bank | | Credit unions | Navy Federal, State Employees CU | | Online banks | Ally, Marcus, Discover | | Neobanks | Chime, Current, Varo | *** ## How to implement | Path | Code required | Best for | | ---------------------------------------------- | ------------- | ------------------------------------- | | [Bank Income](/credit/integration/bank-income) | Minimal | Transaction-based income verification | | [Truv Dashboard](/developers/dashboard) | None | Manual orders, pilot testing | | [API Reference](/api-reference) | Custom | Full API control | *** ## Report structure ### API Response ```json theme={null} { "count": 2, "accounts": [ { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "type": "CHECKING", "subtype": null, "mask": "1234", "nickname": "Primary Checking", "balances": { "currency_code": "USD", "balance": "4500.00", "available_balance": "4200.00", "credit_limit": null } } ], "transactions": [ { "id": "tx_a1b2c3d4", "account_id": "24d7e80942ce4ad58a93f70ce4115f5c", "amount": "2650.00", "currency_code": "USD", "description": "DIRECT DEPOSIT - ACME CORP", "status": "POSTED", "type": "CREDIT", "posted_at": "2024-01-15T14:00:00Z", "transacted_at": "2024-01-15T10:30:00Z", "categories": ["Transfer", "Payroll"], "is_direct_deposit": true }, { "id": "tx_e5f6a7b8", "account_id": "24d7e80942ce4ad58a93f70ce4115f5c", "amount": "1800.00", "currency_code": "USD", "description": "RENT PAYMENT", "status": "POSTED", "type": "DEBIT", "posted_at": "2024-01-12T10:00:00Z", "transacted_at": "2024-01-12T10:00:00Z", "categories": ["Home", "Rent"] } ] } ``` *** ## API reference Create tokens for Truv Bridge Account balance data Financial account details Create and manage users *** ## Best practices Truv supports 30 to 730 days of transaction history. Set `days_requested` when creating the report to control how much data you receive. 60 days is the default. Check the `days_available` field on each account to see how much history was returned. Filter for recurring deposits to estimate stable income, especially for borrowers with irregular pay schedules. Bank Aggregation works best alongside Income & Employment verification. Use payroll data as the primary income source and bank data for supplementary analysis. *** ## Next steps Full implementation walkthrough Payroll-based income data # Income & Employment for Lending Source: https://docs.truv.com/credit/products/income-employment Income verification for consumer lending decisions Verify borrower income and employment instantly for loan underwriting and credit decisions. Truv connects directly to payroll systems, returning verified details in seconds. **Try the demo** -- Run the [Smart Routing demo](/credit/integration/smart-routing) or [Payroll Income demo](/credit/integration/payroll-income) to see income verification working end-to-end. [Clone the demo app ->](https://github.com/truvhq/demo-apps) *** ## Benefits Verified income and employment data in seconds ADP, Paychex, Workday, UKG, and 100+ payroll providers Structured data ready for your decision engine W-2, 1099, gig, and self-employed income *** ## What you get * Base salary, hourly rate, commission, bonus * Pay frequency * Year-to-date gross and net pay * Historical pay statements * Tax deductions and withholdings * Employer name, address, EIN * Employment status (active, terminated, leave) * Start and end dates * Job title and position * Pay stubs (PDF) * W-2 forms (when available) * W-2 employees * 1099 contractors * Multiple employers * Self-employed (limited) *** ## Use cases Verify borrower income in real time during the application flow. Supports both prime and subprime decisioning with gross pay, pay frequency, and employment tenure. Calculate debt-to-income ratios using verified pay data. Ideal for debt consolidation, home improvement, and emergency expense loans. Use current income to set or increase credit limits. Works for new account applications and periodic limit reviews. Quick income checks at the point of sale. Verify affordability for installment plans and higher-ticket purchases. *** ## Data coverage ### Payroll Providers Truv connects to payroll providers covering 85%+ of US employees: | Provider | Coverage | | ------------- | ------------------- | | ADP | \~20% of US workers | | Paychex | \~10% of US workers | | Workday | Large enterprises | | UKG (Kronos) | Healthcare, retail | | Paylocity | Mid-market | | Gusto | Small business | | And 100+ more | | ### Supported Income Types * W-2 employees * 1099 contractors * Multiple employers * Self-employed (limited) *** ## How to implement Choose your integration path based on your tech stack: | Path | Code required | Best for | | ---------------------------------------------------- | ------------- | ------------------------------------ | | [Smart Routing](/credit/integration/smart-routing) | Minimal | Payroll-first with document fallback | | [Payroll Income](/credit/integration/payroll-income) | Minimal | Direct payroll connection | | [Truv Dashboard](/developers/dashboard) | None | Manual orders, pilot testing | The `income` product automatically includes employment data. Do not pass both `income` and `employment` in the same order. **Combine with Assets for stronger decisions.** Request both `income` and `assets` product types in a single order to get a complete financial picture of the borrower. [Learn about Assets verification -->](/credit/products/assets) For a full implementation walkthrough including webhook handling and [Truv Bridge](/developers/sdks/overview) Token setup, see the [Smart Routing guide](/credit/integration/smart-routing) or [Payroll Income guide](/credit/integration/payroll-income). *** ## Report structure The response follows the `IncomeCheck` schema with a top-level `employments` array. Each employment includes income summary fields, company details, borrower profile, and an array of pay statements. | Field | Path | Example | | -------------- | ----------------------------- | -------------------- | | Annual income | `employments[].income` | `"70000.00"` | | Income period | `employments[].income_unit` | `YEARLY` | | Pay per period | `employments[].pay_rate` | `"6500.00"` | | Pay frequency | `employments[].pay_frequency` | `SM` (Semi-Monthly) | | Employer | `employments[].company.name` | `"Acme Corporation"` | | Pay statements | `employments[].statements[]` | Array of pay stubs | ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "done", "provider": "adp", "data_source": "payroll", "employments": [ { "income": "70000.00", "income_unit": "YEARLY", "pay_rate": "6500.00", "pay_frequency": "SM", "company": { "name": "Acme Corporation", "address": { "street": "123 Main St", "city": "New York", "state": "NY", "zip": "10001" } }, "profile": { "first_name": "John", "last_name": "Doe" }, "statements": [ { "pay_date": "2024-01-19", "gross_pay": "2650.00", "net_pay": "1950.00" }, { "pay_date": "2024-01-05", "gross_pay": "2650.00", "net_pay": "1950.00" } ] } ] } ``` **Pay frequency codes:** `M` (Monthly), `SM` (Semi-Monthly), `W` (Weekly), `BW` (Bi-Weekly), `A` (Annually), `SA` (Semiannually), `C` (Commission) The `income` product automatically includes employment data. You never need to request both `income` and `employment` separately. *** ## API reference Create tokens for Truv Bridge Retrieve income data Retrieve employment data Create and manage users *** ## Best practices For most consumer lending decisions, reviewing 90 days of pay statements provides a solid baseline for income calculation. Truv returns available pay statements from the payroll provider. Check the `statements` array in the response and verify that coverage meets your underwriting requirements. Borrowers may have side jobs or gig work. Each payroll connection creates a separate employment entry in the `employments` array. To capture multiple income sources, have the borrower connect each employer through the Truv Bridge widget sequentially. Trigger verification as part of the loan application flow rather than as a separate step to improve completion rates. *** ## Next steps Payroll-first with document fallback Add asset data to your decisions # Paycheck Linked Lending Source: https://docs.truv.com/credit/products/pll Automatic loan repayment directly from paycheck Collect loan repayments automatically by deducting payments directly from the borrower's paycheck. Achieve higher repayment rates and lower default risk compared to traditional ACH-based collections. **Try the demo** -- Run the [Paycheck-Linked Loans demo](/credit/integration/pll) to see payroll deduction setup working end-to-end. [Clone the demo app ->](https://github.com/truvhq/demo-apps) *** ## How it works The borrower authenticates with their employer's payroll system through [Truv Bridge](/developers/sdks/overview). You specify the repayment amount as a fixed dollar value or a percentage of net pay. Each pay period, the configured amount is deducted from the borrower's paycheck. The deducted payment is sent directly to your collection account. *** ## Benefits Payments happen before discretionary spending Automatic, consistent payments every pay period No manual payment management or missed due dates Know payment status immediately through webhooks *** ## Deduction types | Type | Description | Example | | --------- | --------------------- | -------------------- | | `amount` | Fixed dollar amount | \$200 per paycheck | | `percent` | Percentage of net pay | 10% of each paycheck | Paycheck Linked Lending uses the **User Token flow** instead of Embedded Orders. This provides ongoing access to the payroll connection for recurring deductions. *** ## Data coverage ### Payroll Providers Truv connects to payroll providers covering 85%+ of US employees: | Provider | Coverage | | ------------- | ------------------- | | ADP | \~20% of US workers | | Paychex | \~10% of US workers | | Workday | Large enterprises | | UKG (Kronos) | Healthcare, retail | | Paylocity | Mid-market | | Gusto | Small business | | And 100+ more | | *** ## Report structure The PLL report returns the deduction status and deposit configuration for a borrower's payroll link. | Field | Description | | -------------------------------- | ----------------------------------------------------- | | `id` | Unique report identifier | | `status` | Request status (`new`, `done`, `error`) | | `deposit_details.deposit_type` | `amount` (fixed) or `percent` (percentage of net pay) | | `deposit_details.deposit_value` | Configured deduction value | | `deposit_details.account_number` | Target bank account number | | `deposit_details.routing_number` | Target bank routing number | | `deposit_details.bank_name` | Target bank name | | `deposit_details.account_type` | `checking` or `savings` | | `finished_at` | Timestamp when the report completed | ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "done", "finished_at": "2021-04-06T11:30:00Z", "access_token": "48427a36d43c4d5aa6324bc06c692456", "tracking_info": "user123456", "deposit_details": { "account_number": "16002600", "routing_number": "123456789", "bank_name": "TD Bank", "account_type": "checking", "deposit_type": "amount", "deposit_value": "200.00" } } ``` See the [PLL Report API reference](/api-reference/deposit-switch/link_detail_reports_pll) for the full schema. *** ## Manage the lifecycle Once a Paycheck Linked Lending deduction is active, you can: * **Update the deduction amount**, adjust as the loan balance changes * **Pause deductions**, temporarily suspend during hardship periods * **Cancel deductions**, remove when the loan is fully repaid *** ## API reference Create tokens for Truv Bridge Paycheck Linked Lending report PLL link detail report Create and manage users *** ## Best practices Always cancel the deduction when the loan balance reaches zero to avoid over-collection and maintain borrower trust. Fixed dollar deductions provide consistent repayment schedules. Percentage-based deductions are useful when income varies. Watch for `task-status-updated` webhooks to detect if the borrower changes jobs or their payroll provider rejects the deduction. *** ## Next steps Step-by-step Paycheck Linked Lending setup Understand the User + Bridge Token integration flow # Scoring Attributes for Lending Source: https://docs.truv.com/credit/products/scoring Transaction-derived risk scores and financial metrics for credit decisioning Analyze bank transaction data to generate risk scores, income metrics, and spending patterns for credit decisioning. Use scoring reports as an alternative or supplement to traditional credit bureau data. No hard inquiry on the consumer's credit report. *** ## Benefits Risk assessment without impacting the consumer's credit Score borrowers with limited credit history Scores derived from real bank activity, not models Analyze from 1 week to lifetime of data *** ## What you get * Overdraft risk prediction * Balance pattern analysis * Transaction behavior scoring * Derived income streams * Frequency and average amount * Monthly income projections * Daily balance calculations * Minimum balance tracking * Balance trends over time * NSF fee detection * Debit activity ratios * Expense categorization *** ## Report purposes | Purpose | Use Case | Fair Credit Reporting Act (FCRA) | | -------------- | ---------------------------------------------- | -------------------------------- | | `decisioning` | Credit decisioning and loan approval | Yes | | `verification` | Underwriting verifications and income analysis | No | | `analytics` | Retroactive portfolio analysis | No | *** ## Use cases Use transaction-derived risk scores and income metrics as an alternative or supplement to traditional credit bureau data. Particularly valuable for borrowers with thin credit files. Verify income claims and assess financial stability during the loan origination process using real bank transaction data. Run retroactive analysis on existing portfolios to identify risk concentration and performance drivers. Extend credit to underserved populations by supplementing traditional credit data with bank transaction signals. *** ## How to implement | Path | Code required | Best for | | -------------------------------------------------- | ------------- | ---------------------------- | | [Scoring API](/api-reference/data-structure) | Custom | Direct API integration | | [Smart Routing](/credit/integration/smart-routing) | Minimal | Combined with other products | See the [Scoring API reference](/api-reference/data-structure) for full request and response schemas. *** ## API reference Scoring attributes and report schema Create tokens for Truv Bridge Create and manage users *** ## Next steps Full API reference and schema Transaction data that feeds scoring reports # Widget-only Best Practices Source: https://docs.truv.com/developers/best-practices/bridge-token Guidelines for implementing Deposit Switch and Paycheck Linked Lending Follow these best practices for Deposit Switch (DDS) and Paycheck Linked Lending (PLL) integrations using the Widget-only flow. *** ## Wait for webhooks before proceeding Always wait for the `task-status-updated` webhook with `status: done` before treating a connection as complete. Do not rely solely on the client-side `onSuccess` callback. The task may still be processing server-side. ```bash theme={null} # When you receive a task-status-updated webhook with status: done, # retrieve the link details curl --request GET \ --url https://prod.truv.com/v1/links/{link_id}/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` *** ## Validate account details upfront Provide complete and accurate bank account information when creating the bridge token. Missing or incorrect fields cause configuration failures. **Deposit Switch**: route the user's entire paycheck or a fixed amount: ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "deposit_switch", "account": { "account_number": "16002600", "routing_number": "123456789", "bank_name": "TD Bank", "account_type": "checking", "deposit_type": "entire" } }' ``` **Paycheck Linked Lending**: deduct a fixed amount per paycheck: ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "pll", "account": { "account_number": "16002600", "routing_number": "123456789", "bank_name": "TD Bank", "account_type": "checking", "deposit_type": "amount", "deposit_value": "200.00" } }' ``` ### Deposit type options | `deposit_type` | Description | | -------------- | -------------------------------------------------------- | | `entire` | Route the entire paycheck | | `amount` | Route a fixed dollar amount (set `deposit_value`) | | `percent` | Route a percentage of the paycheck (set `deposit_value`) | *** ## Handle errors from webhooks Monitor `task-status-updated` webhooks for error statuses. These indicate the connection or configuration failed. | Webhook status | Cause | Resolution | | ---------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | | `login_error` | Incorrect credentials | Prompt the user to re-authenticate via [Bridge Update Mode](/developers/integration/bridge-widget/returning-user) | | `mfa_error` | MFA challenge failed | Prompt the user to try again | | `config_error` | Provider doesn't support the requested operation | Fall back to manual instructions or try a different provider | | `account_locked` | Too many failed attempts at the provider | Ask the user to unlock their account with the provider | See [Task lifecycle](/api-reference/tasks/lifecycle) for all status transitions. *** ## Handle client-side errors Listen for `ERROR` events in the Bridge `onEvent` callback. The error object uses `error_code`, not a generic `code` field. ```javascript theme={null} onEvent: function(type, payload) { if (type === 'ERROR') { switch (payload.error.error_code) { case 'LOGIN_ERROR': // User entered wrong credentials — Bridge handles retry UI break; case 'UNAVAILABLE': showMessage('This provider is temporarily unavailable. Try again later.'); break; case 'LINK_EXISTS': showMessage('This account is already connected.'); break; } } } ``` See [Bridge Events](/developers/sdks/bridge-events#errors) for all error codes and their meanings. *** ## Use deeplinking when you know the employer If you know the user's employer or payroll provider, pass it when creating the bridge token to skip search screens and improve conversion. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "deposit_switch", "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456", "account": { "account_number": "16002600", "routing_number": "123456789", "bank_name": "TD Bank", "account_type": "checking", "deposit_type": "entire" } }' ``` See [Deeplinking](/developers/integration/bridge-widget/deeplinking) for the full guide. *** ## Check DDS/PLL support before connecting Use the [company search endpoint](/api-reference/companies/company_autocomplete_search) to check if a provider supports DDS or PLL before routing the user through the flow. This avoids dead-end experiences where the user connects but the provider doesn't support the desired product. ```bash theme={null} curl --request GET \ --url 'https://prod.truv.com/v1/company-mappings-search/?query=Facebook' \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` Check the response for DDS/PLL availability before initiating the bridge token. *** ## Leverage VOIE-PLL flow For combined income verification and paycheck linked lending, complete the VOIE flow first, then check if the connected provider supports DDS/PLL. After VOIE completes, fetch the link details: ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/links/{link_id}/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` Check the `is_dds_available` flag in the response. If `true`, the user's payroll provider supports DDS/PLL and you can offer it as a follow-up step without requiring the user to reconnect. *** ## Understand the token flow The Widget-only flow uses a three-token exchange to securely connect users to their payroll providers: ```text theme={null} bridge_token → public_token → access_token ``` | Token | Created By | Lifetime | Purpose | | -------------- | ------------------------ | ----------- | ------------------------------------ | | `bridge_token` | Your server (via API) | 6 hours | Initialize Truv Bridge on the client | | `public_token` | Truv Bridge (on success) | Short-lived | Temporary token for exchange | | `access_token` | Token exchange (via API) | Persistent | Configure DDS/PLL and retrieve data | ## Store and protect tokens * **`access_token`** is persistent and grants access to the user's data. Store it encrypted on your server. * **`bridge_token`** is short-lived (6 hours) and safe to pass to the client. Generate a new one if the user hasn't started within that window. * **`public_token`** is single-use. Exchange it immediately for an `access_token` via `POST /v1/link-access-tokens/` and discard it. Never expose `access_token` or API credentials in client-side code. *** ## Verify webhook signatures Always verify the `X-WEBHOOK-SIGN` header on incoming webhooks to confirm they are from Truv. Use the raw request body. Never use parsed JSON. See [Webhook Security](/api-reference/security) for verification examples. *** ## Next steps Implementation guide for Widget-only flow Reconnect or update an existing link Client-side event types and error codes Server-side connection statuses # Embedded Orders Best Practices Source: https://docs.truv.com/developers/best-practices/embedded-orders Guidelines for implementing Embedded Orders Follow these best practices to ensure a successful Embedded Orders integration, from order creation through data retrieval and ongoing maintenance. *** ## Embedded Orders vs Bridge Token Truv offers two integration methods. Choose based on your use case: | | Embedded Orders | Bridge Token | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | **When to use** | You don't know the user's employer upfront, or you need Truv to manage the order lifecycle (notifications, reminders, status tracking) | You already know the employer and want full control over the UI and data flow | | **Create via** | `POST /v1/orders/` | `POST /v1/users/{user_id}/tokens/` | | **Products parameter** | `products` array: `["income"]`, `["assets"]`, `["income", "assets"]` | `product_type` string: `"income"`, `"employment"`, `"assets"` + optional `allowed_products` array | | **Bridge initialization** | Pass `bridge_token` from order response, set `isOrder: true` | Pass `bridge_token` from token response, `isOrder` not set | | **Notifications** | Truv can send email/SMS to the user with a verification link | You handle all user communication | | **Webhooks** | `order-status-updated` + `task-status-updated` | `task-status-updated` only | | **Data retrieval** | Via order ID or link ID | Via link ID only | | **Best for** | Hosted flows, multi-employer orders, caseworker-initiated verification | Inline embedded flows where you control the full UX | Most integrations use Embedded Orders. Use Bridge Token only when you need direct control over the connection flow and already have the employer identified. See [Embedded Orders overview](/developers/integration/embedded-orders/overview) and [Bridge Widget overview](/developers/integration/bridge-widget/overview) for full implementation guides. *** ## Create an order ### Request the right products Specify only the products your use case requires. When you include `income` in the products array, employment data is automatically included. You do not need to pass both. ```json theme={null} // Correct — income includes employment data { "products": ["income"] } // Incorrect — employment is redundant here { "products": ["income", "employment"] } // Assets only { "products": ["assets"] } // Income + Assets { "products": ["income", "assets"] } ``` ### Use `external_user_id` for user continuity Pass your internal user identifier as `external_user_id` when creating orders. This maps to a persistent Truv user and carries forward across every order you create for that person. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "external_user_id": "your-internal-user-id-1235" }' ``` When you create a second order with the same `external_user_id`, the user's previous connections are remembered. For example, if a user connected to ADP on their first order and you create a new order with the same `external_user_id`, the orders landing page will already show their ADP connection, reducing friction and improving completion rates. Always pass `external_user_id` in production. It enables user continuity and simplifies data lookups across orders. *** ## Optimize conversion ### Skip search with deeplinking If you already know the user's employer or payroll provider, pass a `company_mapping_id` when creating the order. This skips the search screen and drops users directly into the login flow, one of the highest-impact conversion improvements you can make. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "employers": [{ "company_mapping_id": "abc123" }] }' ``` Look up `company_mapping_id` values using the [Companies API](/api-reference/companies/company_mapping). [Deeplinking guide →](/developers/integration/embedded-orders/deeplinking) ### Send follow-up reminders When a user leaves without completing verification, Truv can automatically send email and SMS reminders. Suppress notifications during the in-app session, then enable them after the user exits. ```bash theme={null} # Create order with notifications suppressed during in-app flow curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "notification_settings": { "suppress_user_notifications": true } }' ``` After the user closes the widget without finishing, update the order to enable reminders: ```bash theme={null} curl --request PATCH \ --url https://prod.truv.com/v1/orders/{order_id}/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "notification_settings": { "suppress_user_notifications": false } }' ``` Truv sends up to 3 automatic reminders before the order expires. Order links are valid for 72 hours by default (configurable per client). [Follow-up guide →](/developers/integration/embedded-orders/follow-up) ### Refresh data without re-authentication When you need updated income or employment data for an existing user, create a data refresh order instead of asking them to reconnect. Truv reuses existing account links. The user doesn't need to do anything. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/refresh/tasks/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "access_token": "EXISTING_ACCESS_TOKEN", "product_type": "income" }' ``` [Data refresh guide →](/developers/integration/embedded-orders/data-refresh) *** ## User experience ### Wait for the right event Use the `COMPLETED` event with `source: "order"` before advancing the user in your application. Don't use `onSuccess` or `onClose`. The order may still have pending connections. ```javascript theme={null} onEvent: function(type, payload, source) { if (type === 'COMPLETED' && source === 'order') { navigateToNextStep(); } } ``` ### Handle errors gracefully Listen for `ERROR` events from the connection widget (`source: "bridge"`). The error payload uses the `error` object with `error_code`. See [Bridge Events](/developers/sdks/bridge-events#errors) for all codes. ```javascript theme={null} onEvent: function(type, payload, source) { if (type === 'ERROR' && source === 'bridge') { switch (payload.error.error_code) { case 'LOGIN_ERROR': // User entered wrong credentials — Bridge handles retry UI break; case 'UNAVAILABLE': showMessage('This provider is temporarily unavailable. Please try again later.'); break; } } } ``` *** ## Webhooks ### Process tasks as they complete Handle `task-status-updated` webhooks to process data as each connection finishes. Don't wait for the full order to complete. ```bash theme={null} # When you receive a task-status-updated webhook with status: done, # fetch the income report for the completed link curl --request GET \ --url https://prod.truv.com/v1/links/{link_id}/income/report/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` ### Validate webhook signatures Always verify the `X-WEBHOOK-SIGN` header to confirm requests are from Truv. Use the raw request body. Never use parsed JSON. See [Webhook Security](/api-reference/security) for full verification examples in multiple languages. *** ## Security * Never expose API credentials in client-side code. Use `bridge_token` for frontend operations only. * Don't log sensitive data (SSN, income figures, account numbers) * Encrypt verification data at rest * Implement data retention policies. Don't store data longer than needed. * Validate webhook signatures on every request *** ## Monitoring Track these metrics to monitor integration health: * **Order completion rate**: percentage of orders where the user finishes at least one connection * **Average connections per order**: indicates whether users are connecting all requested accounts * **Error rates by type**: identify provider-specific or credential issues * **Webhook delivery success**: ensure you're receiving all status updates * **Time to completion**: how long users take to finish the verification flow *** ## Next steps Complete implementation walkthrough Skip employer search for higher conversion Automatic email and SMS reminders Refresh data without re-authentication # Building with AI Source: https://docs.truv.com/developers/building-with-ai Connect Claude Code, Codex, or Cursor to Truv docs via MCP for accurate API integrations Connect your AI coding tool to Truv's MCP server. It searches the docs and retrieves full page content on demand, so you get correct auth headers, status enums, and webhook handlers without pasting context manually. *** ## Connect the MCP server The Truv MCP server runs at `https://docs.truv.com/mcp`. It exposes two tools: **search** across all documentation and **retrieve** the full content of any page by path. ```bash theme={null} claude mcp add --transport http truv-api https://docs.truv.com/mcp ``` Add to `~/.codex/config.toml`: ```toml theme={null} [mcp_servers.truv-api] url = "https://docs.truv.com/mcp" ``` Add to `~/.cursor/mcp.json`: ```json theme={null} { "mcpServers": { "truv-api": { "url": "https://docs.truv.com/mcp" } } } ``` Test it by starting a new chat and asking: *"What headers does the Truv API use for authentication?"* *** ## Context files Truv publishes two static context files following the [llms.txt standard](https://llmstxt.org). Use these to seed `CLAUDE.md` / `AGENTS.md`, paste into a prompt, or as a fallback when MCP isn't available. | File | Size | Use case | | ------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------- | | [`llms.txt`](https://docs.truv.com/llms.txt) | \~3.5 KB | Structured overview with links to docs sections | | [`llms-full.txt`](https://docs.truv.com/llms-full.txt) | \~18 KB | Everything inlined: auth, endpoints, schemas, enums, webhooks, sandbox credentials | * Authentication pattern (headers, base URL, SDK init) * All products and when to use each integration method * Complete integration code for Embedded Orders and User Token flows * Connection lifecycle with every status and error state * Webhook event types with example payloads and signature verification * Field-level data reference for Income & Employment, Employment, and Assets reports * Every enum value: job types, pay frequencies, deposit types, account types, income units * All API endpoints grouped by resource * Sandbox test credentials for every scenario ### Seed your rules file Drop this into `CLAUDE.md`, `AGENTS.md`, or `.cursorrules` so your AI tool follows Truv conventions without re-deriving them each time: ```md theme={null} # Truv API conventions - Base URL: https://prod.truv.com/v1/ (credentials select sandbox vs production) - Auth headers: X-Access-Client-Id and X-Access-Secret (never Authorization: Bearer) - Money amounts are decimal strings, e.g. "50000.00" - Products: income, employment, assets, deposit_switch, pll ## Bridge (frontend) - Embedded Orders: initialize TruvBridge with isOrder: true - User Token flows (e.g. Deposit Switch): initialize WITHOUT isOrder - Callbacks: onSuccess, onLoad, onEvent, onClose - Errors surface in onEvent with type=ERROR and an ErrorData payload — there is no onError callback ## Statuses - Task lifecycle: new → login → mfa → parse → full_parse → done - Income/employment emit full_parse (base data) before done; assets (VOA) emit done only - Error statuses: login_error, mfa_error, account_locked, unavailable ## Webhooks - Verify the X-WEBHOOK-SIGN header: HMAC-SHA256 of the raw request body, format v1={hash} - Respond with 2xx within 10 seconds; dedupe on webhook_id ## Enums (report output) - pay_frequency: M, SM, W, BW, A, SA, C - income_unit: YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY - job_type: F, P, S, D, C, V - account_type: C, S — deposit_type: E, P, A - Deposit Switch INPUT (deposit_details) uses words instead: account_type checking/savings, deposit_type entire/percent/amount ``` *** ## Reference repos Clone these repos and point your AI tool at the source for working reference implementations. * [**demo-apps**](https://github.com/truvhq/demo-apps): Full-stack demo apps covering Embedded Orders, Hosted Orders, Document Processing, and more * [**quickstart**](https://github.com/truvhq/quickstart): Minimal end-to-end integration in Node.js, Python, Ruby, Go, and C# * [**demo-ios**](https://github.com/truvhq/demo-ios) / [**demo-android**](https://github.com/truvhq/demo-android) / [**demo-react-native**](https://github.com/truvhq/demo-react-native) / [**demo-flutter**](https://github.com/truvhq/demo-flutter): Mobile SDK samples *** ## What AI commonly gets wrong | What AI guesses | Correct value | | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Authorization: Bearer {token}` | `X-Access-Client-Id` and `X-Access-Secret` headers | | Status: `complete`, `success`, `finished` | `done` (task statuses: `new`, `login`, `mfa`, `parse`, `full_parse`, `done`) | | Product: `voie`, `voe`, `voa` | `income`, `employment`, `assets` | | `TruvBridge.init({ bridgeToken })` for orders | Must include `isOrder: true` | | Separate sandbox URL | Same URL: `https://prod.truv.com/v1/`, credentials determine environment | | Webhook signature: raw HMAC | Format: `v1={hmac_sha256_hex}` in `X-WEBHOOK-SIGN` header | | Income amounts as numbers | Strings: `"50000.00"` | | Pay frequency: `biweekly`, `monthly` | Codes: `BW`, `M`, `SM`, `W` | | Deposit Switch input uses report codes (`C`/`S`, `E`/`P`/`A`) | Input `deposit_details` uses words: `account_type` is `checking`/`savings`, `deposit_type` is `entire`/`percent`/`amount`. Only the report output uses the single-letter codes. | | Fetch the report when status is `done` | Income and employment fire `full_parse` (base data) before `done`; assets (VOA) only fire `done` | *** ## Prompting tips Copy these prompts directly or adapt for your use case. ``` Build a server endpoint that creates a Truv Embedded Order for income and employment verification. Use the Truv API with X-Access-Client-Id and X-Access-Secret headers. Return the bridge_token to the frontend. Then build a frontend that initializes TruvBridge with isOrder: true and handles onSuccess, onClose, and onEvent callbacks (errors surface in onEvent with type=ERROR and an ErrorData payload -- there is no onError callback). ``` ``` Create a webhook endpoint for Truv that: 1. Verifies the X-WEBHOOK-SIGN header using HMAC-SHA256 with my API secret (format: v1={hash}) 2. Handles task-status-updated events - fetch the income report when status is "done" 3. Handles error statuses: login_error, mfa_error, account_locked, unavailable 4. Uses webhook_id for idempotency 5. Responds within 10 seconds ``` ``` Build a Deposit Switch integration using Truv's User Token flow (NOT Embedded Orders). Create a bridge token with product_type "deposit_switch" and include the target bank account details (account_number, routing_number, bank_name, account_type, deposit_type). Initialize TruvBridge WITHOUT the isOrder flag. ``` ``` Build a server-side poller that fetches a Truv income report via GET /v1/links/{link_id}/income/report/ using X-Access-Client-Id and X-Access-Secret headers. Poll until the link status is full_parse or done; stop on error, no_data, or unavailable. Respect the documented rate limit. ``` ``` Trigger a Truv data refresh for an existing link without re-prompting the user. Create a refresh task at POST /v1/refresh/tasks/ for the stored access_token, then handle the task-status-updated webhook the same way as the initial run. ``` ``` Write a function that takes a Truv income verification report and extracts: - Current employer name, job title, start_date, is_active status, and pay_frequency - Most recent pay statement: gross_pay, net_pay, pay_date, gross_pay_ytd - Annual income breakdown by year from annual_income_summary - All bank accounts (bank_accounts) with routing_number and deposit_type Use the exact field names from the Truv API docs. ``` *** ## Next steps Create your first verification in minutes Full integration walkthrough Test credentials and sandbox environment Complete endpoint documentation # Financial Accounts Source: https://docs.truv.com/developers/coverage-financial-accounts Financial institution coverage, supported account types, and data access Truv connects to 14,000+ financial institutions covering 98% of US bank accounts. A single `transactions` product connection gives access to account balances, transaction history, and liability details.
*** ## Institution coverage API Query institution coverage and success rates using the [Data Providers API](/api-reference/data-providers/providers-list). *** ## Supported account types | Type | Subtypes | | ---------------- | --------------------------------------- | | `CHECKING` | Standard checking, money market | | `SAVINGS` | Standard savings, high-yield savings | | `CREDIT_CARD` | Rewards, cashback, secured | | `LOAN` | Auto, personal, student, small business | | `LINE_OF_CREDIT` | HELOC, home equity | | `MORTGAGE` | Fixed-rate, adjustable-rate | | `INVESTMENT` | Brokerage, retirement (IRA, 401k) | | `CD` | Certificates of deposit | *** ## Implementation Create an [order](/api-reference/orders/object) with the `transactions` or `assets` product to connect a user's financial accounts. See the [Embedded Orders guide](/developers/integration/embedded-orders/overview) for a complete walkthrough. *** ## Financial accounts products Bank account balances and asset reports Account balances and auth data Transaction history and categorization Credit cards, loans, and mortgage data Risk scores derived from transaction data # Payroll Source: https://docs.truv.com/developers/coverage-payroll Payroll provider coverage, authentication methods, and Smart Login Truv connects to 93+ payroll providers covering 220M+ Americans, 96% of the US labor force, including gig income workers. Truv maps over 300,000 employers to payroll providers so users don't need to make that selection.
*** ## Provider coverage API Query provider coverage and success rates using the [Data Providers API](/api-reference/data-providers/providers-list). Search for employers and retrieve their mapped payroll provider using the [Companies API](/api-reference/companies/object). *** ## Authenticate users Truv's [Smart Login](/banking/smart-login) presents the best authentication method for each user based on employer, historical success rates, and payroll system compatibility. | Method | Description | | --------------------- | ------------------------------------------------------------------------------------------ | | Native OAuth | In-bridge redirect to payroll provider. Patented solution across the largest integrations. | | Single Sign-On (SSO) | Employee credentials via 64 SSO system integrations | | Credential-less Login | One-time passcode via trusted phone or email. Supported by ADP, Paycom. | | AppClip & Instant App | iOS AppClip and Android Instant App for employers behind VPNs | | Mapped Payroll | 300,000+ employers mapped to payroll providers automatically | | Unmapped Payroll | Provider recommendations based on historical data and employer size | *** ## Data sources The `data_source` field on links and providers identifies how data was collected. | Data source | Description | | -------------------- | ---------------------------------------------------- | | `payroll` | Direct API connection to payroll provider | | `docs` | User-uploaded documents (pay stubs, W-2s, tax forms) | | `financial_accounts` | Bank account transaction analysis | | `tax` | Tax return data | *** ## Payroll products Instant income and employment verification from payroll Multi-year employment history from payroll systems Redirect user paychecks to your bank account Automatic loan repayment from borrower paychecks # UX Customization Source: https://docs.truv.com/developers/customization Brand your verification experience across Bridge, emails, SMS, and landing pages Customization templates let you personalize the entire verification experience, from the [Truv Bridge](/developers/sdks/overview) widget to emails, SMS messages, and landing pages. Templates are configured per product type and can be managed in the [Dashboard](https://dashboard.truv.com) under **Customization > Templates** or programmatically via the [Templates API](/api-reference/templates/object). Truv adds default templates to your account tailored to your use case and products — open and edit these to get started. Template configurations take priority over universal branding settings. Set a template as **Primary** to make it the default for its product type when creating new orders. *** ## Manage templates Truv automatically creates default templates in your account tailored to your products and use case. Adjust them in the [Dashboard](/developers/dashboard/customization#templates) or via the API below. ### API Manage templates programmatically for automated workflows. | Operation | Endpoint | Description | | --------- | -------------------------------------------------------------------------------- | ----------------------------------- | | Create | [`POST /v1/templates/`](/api-reference/templates/templates_create) | Create a new customization template | | List | [`GET /v1/templates/`](/api-reference/templates/templates_list) | List all templates | | Read | [`GET /v1/templates/{id}/`](/api-reference/templates/templates_read) | Retrieve a specific template | | Update | [`PATCH /v1/templates/{id}/`](/api-reference/templates/templates_partial_update) | Update template settings | | Delete | [`DELETE /v1/templates/{id}/`](/api-reference/templates/templates_delete) | Delete a template | Pass a `template_id` when [creating an order](/api-reference/orders/orders_create) to apply a specific template. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "template_id": "a1b2c3d4e5f6" }' ``` In a [multi-tenancy](/developers/multi-tenancy) setup, each company has its own set of templates. Make sure you're editing templates in the correct company context. *** ## Settings Configure the template's core identity and order behavior. Truv Dashboard - Template settings | Field | Description | | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | | **Template name** | Display name for the template. Cannot be "Default". | | **Product type** | One or more verification products this template applies to | | **Set as primary template for specified product type(s)** | Preselects this template by default when creating new orders for the selected product type(s) | | **Add your end-user agreement or privacy policy** | Toggle on to show a custom agreement on the landing page and in Bridge. Requires a display text label and a URL. | | **Link expiration** | How long the verification link stays active before expiring | | **Send notifications to the end-user** | Toggle whether email and SMS notifications are sent to the applicant | | **Notifications start** | When notifications are first sent: on order creation, or 1–24 hours after | | **Customer support email address** | Support email shown to end users during verification | | **Custom field** | Toggle on to add a custom text field to orders. The value is entered when creating each order and appears in the email body and landing page. | *** ## Company branding Configure the visual identity that appears across all touchpoints. If not specified, these will be inherited from the Branding settings set at the Dashboard level. | Field | Description | | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | | **Logo** | Displayed in emails, verification screens, and Truv Bridge | | **Company name** | Name shown across all verification touchpoints | | **Accent color** | Used for buttons and links. A warning is shown if the selected color is too light and may impact conversion rate. | | **Background color (desktop only)** | Overlay background color shown on desktop | | **Hide confetti** | Toggle to show or hide the confetti animation on successful connection | | **Bank name** *Direct Deposit Switch, Paycheck Linked Lending* | Prefilled in emails and the landing page | | **Product name in Truv Bridge and on the landing page** *Paycheck Linked Lending* | Overrides "Auto Pay" across all Bridge screens and the landing page | *** ## Customize Bridge Template settings - Bridge search ### Search Configure the search header for each product and data source combination: | Field | Max length | Description | | ---------- | ---------- | ------------------------- | | **Header** | 34 | Search screen header text | ### Popular companies Set the list shown to users before they search: | Field | Description | | ----------------------------- | ------------------------------------------------------------------------------------------- | | **List of popular companies** | Use the default list or upload a custom CSV (company name + domain, max 15 rows) | | **List of popular providers** | Use the default list or upload a custom CSV for payroll providers or financial institutions | | **Bridge categories** | Select which provider categories are visible in Bridge. At least one must be active. | ### Document upload Configure which document types are accepted: | Field | Description | | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Document upload toggle** | Enable or disable document upload as a fallback | | **Document types** | Enable individual document types: Paystubs, W-2, 1099, 1040. For each: set mandatory/optional, minimum and maximum number of documents, and the upload button label. | ### Success screen Customize what the end user sees after a successful connection: | Field | Max length | Description | | ---------- | ---------- | -------------------------------------------------------------------------------- | | **Title** | 500 | Success screen headline | | **Body** | 500 | Supporting text. Use `{data_provider}` to display the connected provider's name. | | **Button** | 26 | Button text shown after connection | *** ## Customize the order flow Customize the communication and landing pages users see when they receive an order via [Hosted Orders](/developers/integration/hosted-orders/new-user) or [Manual Orders](/developers/integration/manual-orders/new-user). ### Email Order email customization examples Customize the emails sent to applicants. Each section has a **First email** and **Reminder email** sub-tab. Text applied to the first email can optionally be copied to the reminder. | Field | Max length | Description | | ---------------------- | ---------- | ------------------------------------- | | **Subject and header** | 2000 | Email subject line and header text | | **Body** | 2000 | Main body of the email | | **Button** | 26 | Call-to-action button text | | **Caption** | 2000 | Small text displayed below the button | ### SMS * Custom message text within a **120-character limit** * Configurable follow-up SMS timing * The `{link}` variable is required and must be included in the message | Field | Max length | Description | | -------- | ---------- | ---------------------------------------- | | **Text** | 120 | SMS message body. Must include `{link}`. | SMS reminders are only sent between 10am–6pm ET. Contact [support@truv.com](mailto:support@truv.com) to enable SMS for your account. ### Landing Pages Order page customization examples ### Initial landing page Shown before the applicant starts verification: | Field | Max length | Description | | ----------------------------------- | ---------- | ----------------------------------------- | | **Header** | 500 | Headline text on the initial landing page | | **Body** | 500 | Supporting body text | | **Hide frequently asked questions** | — | Toggle to show or hide the FAQ section | ### Success landing page Shown after a successful connection: | Field | Max length | Description | | ---------- | ---------- | ----------------------------------------- | | **Header** | 500 | Headline text on the success landing page | | **Body** | 500 | Supporting body text | ### Expired landing page Shown when the verification link has expired: | Field | Max length | Description | | ---------- | ---------- | ----------------------------------------- | | **Header** | 500 | Headline text on the expired landing page | | **Body** | 500 | Supporting body text | *** ## Dynamic text variables Use variables in emails, SMS, and landing pages to personalize messages with order-specific data. | Variable | Description | Available in | | ----------------------------- | ------------------------ | ---------------------------------- | | `{first_name}` | Recipient's first name | All channels | | `{last_name}` | Recipient's last name | All channels | | `{my_company_name}` | Your company name | All channels | | `{order_number}` | Order tracking ID | All channels | | `{link}` | Unique verification URL | Email, SMS | | `{prospective_employer_name}` | Employer name | Employment orders | | `{target_bank_name}` | Target bank name | Direct Deposit Switch (DDS) orders | | `{target_account_type}` | Target account type | DDS orders | | `{custom_field}` | Custom form input values | All channels | | `{customer_support_email}` | Your support email | All channels | *** ## Results Control what data is returned and displayed in reports. Fields vary by product type. Truv Dashboard - Template results **Income & Employment:** | Field | Description | | --------------------------------- | ------------------------------------------------------ | | **Deposit data** | Show or hide the deposit data section in the report | | **Historical pay period summary** | Show or hide the historical pay period summary section | | **Paystubs limit** | Restrict returned paystubs to the most recent 1–6 | | **W-2 years limit** | Restrict returned W-2s to the most recent 1–3 years | **Assets:** | Field | Description | | --------------------------- | ---------------------------------------------------------------------- | | **Days requested** | Number of days of transaction history to retrieve (30–730, default 60) | | **Large deposits** | Show or hide the large deposits section in the report | | **Large deposit threshold** | Minimum amount ($1–$100,000) for a deposit to be flagged as large | *** ## Next steps Full API reference for template management Apply templates when creating orders The widget you're customizing Manage templates in the Dashboard UI # Truv Dashboard Source: https://docs.truv.com/developers/dashboard Your central hub for managing verifications, teams, customization, billing, integrations and more. Truv Dashboard - orders The [Truv Dashboard](https://dashboard.truv.com) is the central management interface for your Truv account. You can create and manage verification orders, monitor activity, customize the user experience, and administer your team, all without writing any code. The Dashboard can be used as a **standalone platform**. Some teams manage their entire verification workflow through the Dashboard, though Truv is most effective when integrated in the platform your end-users and frontline team use. *** ## Dashboard sections View order summaries filtered by environment, add team members, access reporting, and see a snapshot of verification activity. Simulate the [Truv Bridge](/developers/sdks/overview) flow with pre-configured values. Test different product types, preview the user experience, and view real-time event logs with full JSON details. Search and filter across three tabs: **Users** (end-user information), **Orders** (create and manage orders), and **Tasks** (historical data retrieval details). View Truv's data source coverage statistics: population reach and supported payroll provider and bank integrations. Create and manage [customization templates](/developers/customization) to brand Bridge, emails, SMS messages, and landing pages. Configure data field selections per product type. Manage API keys (Client ID and Access secret), view API event logs, and configure [webhook](/api-reference/webhooks) endpoints and notification settings. View your subscription, invoices, usage breakdown, and download monthly usage reports. Team management, [single sign-on (SSO)](/developers/sso) configuration, [multi-tenancy](/developers/multi-tenancy) company switching, and account-level settings like order expiration windows. *** ## Environments The Dashboard supports two environments. Owners and Administrators have access to toggle Sandbox mode On or Off. | Environment | Purpose | | -------------- | -------------------------------------------------------------------------------------------------------------------- | | **Sandbox** | Test with simulated data and [test credentials](/developers/testing/test-credentials). No real provider connections. | | **Production** | Live environment with real user data and production API keys. | When Sandbox mode is enabled in your Dashboard, it is enabled for all users. Once testing is complete, ensure that you have switched Sandbox mode off. Sandbox mode toggle in Truv Dashboard *** ## Team roles and permissions The Dashboard supports five roles with granular access control: | Access | Owner | Administrator | Developer | Orders Manager | Billing Manager | | --------------------------- | ----- | ------------- | --------- | -------------- | --------------- | | **Reporting** | Yes | Yes | Yes | Yes | Yes | | **Orders / Users** | Yes | Yes | Yes | Yes | No | | **Tasks** | Yes | Yes | Yes | Yes | No | | **Development** | Yes | Yes | Yes | No | No | | **Customization** | Yes | Yes | Yes | No | No | | **Customization Templates** | Yes | Yes | Yes | No | No | | **Company settings** | Yes | Yes | Yes | No | No | | **Team** | Yes | Yes | No | No | No | | **Billing** | Yes | Yes | No | No | Yes | | **Usage** | Yes | Yes | No | No | Yes | | **Support tickets** | Yes | Yes | Yes | Yes | Yes | | **Can be deleted** | No | Yes | Yes | Yes | Yes | Every company must have at least one Owner. In a [multi-tenancy](/developers/multi-tenancy) setup, members can have different roles in each company. ### Manage Team Members Navigate to **Settings > Team > Add member** and provide the member's name, email, role, and available order templates. To edit a team member's role or access, find the user in the Team Members table, click their row, and change any settings. ### Restrict access by template Truv supports controlling Order Manager access through Template assignment. If an Order Manager is assigned specific templates, they will only be able to create orders using those templates and see orders that were created using those templates. This is convenient if team members belong to specific branches or regions and need to create orders with that branding and only see orders for their team. *** ## Get started Test the full verification flow using [sandbox credentials](/developers/testing/test-credentials) before going live. Switch Sandbox mode off and run a real verification with production API keys. Go to **Settings > Team > Add member** to invite your team and assign roles. Go to **Customization > Branding** to upload your logo and set your brand colors. Explore **Customization > Templates** to configure the verification experience for each workflow. Confirm production settings, ensure Sandbox mode is off, and begin processing real verifications. Pick your vertical (Mortgage, Consumer Credit, Retail Banking, Public Sector, Screening) from the top navigation and follow the matching integration guide. # Activity Source: https://docs.truv.com/developers/dashboard/activity Search and manage users, orders, tasks, and provider coverage Search and manage every user, order, task, and provider connection across your Truv account. The Activity section has four tabs: **Users**, **Orders**, **Tasks**, and **Coverage**. *** ## Users The Users tab shows every applicant created in your company and all of their connections. Truv Dashboard - Users ### Table columns | Column | Description | | -------------------- | ------------------------------------------------------------------------------------------------------- | | **Name** | Applicant's full name | | **Created at** | Date the user record was created | | **Updated at** | Date the user record was last updated | | **User ID** | System-generated unique identifier for the user | | **External user ID** | Your system's identifier for the applicant, passed at user creation | | **Email** | Applicant's email address | | **Phone number** | Applicant's phone number | | **SSN** | Applicant's Social Security Number | | **Product type** | The verification product(s) associated with this user's connections | | **Accounts (links)** | The data provider(s) the user has connected to | | **Data source** | The type of data source used (payroll, financial accounts, document upload, etc.) | | **Status** | Outcome status of the user's connection attempts | | **Suspicious** | Flags users where the SSN doesn't match the provider, or uploaded documents may contain fraudulent data | ### Search and filters | Name | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **Search** | Search by name, email, phone, user ID, external user ID, or link ID | | **Date period** | Filter by when the user was created. Presets: Last 24 hours, Last 7 days, This week, Last 30 days (default), Last 90 days, or a custom date range | | **Product type** | Filter by the verification product associated with the user's connections | | **Data provider** | Filter by the specific provider the user connected to | | **Attempts** | Filter by users with attempts, users without attempts, or all users | ### Open a user Click any user to see all reports returned across their links. Reports can be downloaded as PDFs or viewed in the Dashboard UI. Paystubs and W-2s can be downloaded directly from the report view. Additional connection details or errors can be reviewed under the Connections tab. Truv Dashboard - User detail *** ## Orders The Orders tab shows every Truv verification order in your account. Truv Dashboard - Orders ### Table columns | Column | Description | | ------------------------- | -------------------------------------------------------------------------------------------------------- | | **Name** | Applicant's full name | | **Email** | Applicant's email address. Shows a warning if email delivery failed. | | **Phone number** | Applicant's phone number. Shows a warning if SMS delivery failed. | | **Created at** | Date the order was created | | **Refreshed at** | Date a data refresh was completed on this order | | **Source** | Where the order originated (Dashboard, API, Encompass, etc.) | | **Created by** | Name of the order manager who created the order | | **Created by email** | Email of the order manager who created the order | | **Template ID** | ID of the template applied to this order | | **Template name** | Name of the template applied to this order | | **Loan number** | Loan number associated with this order | | **Tracking number** | Internal tracking number for the order | | **Loan processor name** | Name of the loan processor from the loan object | | **Loan processor email** | Email of the loan processor from the loan object | | **Loan originator name** | Name of the loan originator from the loan object | | **Loan originator email** | Email of the loan originator from the loan object | | **Custom field** | Custom field value specified during order creation | | **AIM check report ID** | Report ID for an AIM Check (Freddie Mac) verification | | **VOA report ID** | Report ID for a Verification of Assets report | | **VOIE report ID** | Report ID for a Verification of Income and Employment report | | **User ID** | ID of the applicant user associated with this order | | **Order ID** | Unique identifier for this order | | **Refresh order ID** | ID of the refresh order, if a refresh has been initiated | | **Order link** | Shareable verification link sent to the applicant | | **Status updates** | Email addresses receiving status update notifications for this order | | **External user ID** | Your system's identifier for the applicant | | **Product type** | The verification product(s) requested for this order | | **Data source** | The data source used to complete the verification | | **Provider** | The specific provider the applicant connected to | | **Status** | Current order status (completed, pending, expired, canceled, etc.) | | **Was attempted** | Whether the applicant opened the verification link and attempted to connect | | **Suspicious** | Flags orders where the SSN doesn't match the provider, or uploaded documents may contain fraudulent data | | **Notes** | Internal notes added to the order | Column customization is per-user and does not affect other team members' views. ### Search and filters | Name | Description | | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | | **Search** | Search by name, email, phone, employer, order ID, report ID, loan number, tracking number, or custom field | | **Date period** | Filter by when the order was created. Presets: Last 24 hours, Last 7 days, This week, Last 30 days (default), Last 90 days, or a custom date range | | **Status** | Filter by order status: Done, Pending, Expired, Canceled, Error, Skipped by user, or No data | | **Product type** | Filter by the verification product requested for the order | | **Source** | Filter by where the order originated: Dashboard, API, Encompass, and other integrated platforms | | **Order type** | Filter between All orders, Initial orders, or Refresh orders | | **Order managers** | Filter by the team member who created the order. Supports multi-select with search. | ### Open an order Click any order to see all associated reports. Reports can be downloaded as PDFs or viewed in the Dashboard UI. Paystubs, W-2s, and order invoices can be downloaded directly from the report view. End-user interaction can be viewed in the timeline and additional connection details or errors can be reviewed under the Connections tab. A new refresh order can also be triggered from the top right. Truv Dashboard - Order detail ### Create an order Create order in Truv Dashboard Go to [dashboard.truv.com](https://dashboard.truv.com) and sign in. Navigate to **Activity > Orders** and click **Create Order**. Provide the applicant's name, email, and last 4 digits of their SSN. Choose Income & Employment, Employment, or Assets. Deliver the link to your applicant via email or SMS. The applicant connects through Truv Bridge. Open the order to view the report, download a PDF, or export as needed. Configure [webhooks](/api-reference/webhooks) to receive automatic notifications when an order completes, then fetch the data via API to sync results to your LOS or internal tools. ### Export Click **Export CSV** to download the current table with all active filters and selected columns applied. *** ## Tasks The Tasks tab is the most granular view. Every time an applicant attempted to connect to a provider, it appears as a unique task row. Truv Dashboard - Tasks ### Table columns | Column | Description | | ----------------- | ------------------------------------------------------------------------------------------------------- | | **Created at** | Date and time the connection attempt was made | | **Data source** | The type of data source used (payroll, financial accounts, document upload, etc.) | | **Data provider** | The specific provider the applicant attempted to connect to | | **Task ID** | Unique identifier for this connection attempt | | **Link ID** | ID of the link (account connection) this task belongs to | | **Status** | Outcome of the connection attempt (done, login error, MFA error, etc.) | | **Suspicious** | Flags tasks where the SSN doesn't match the provider, or uploaded documents may contain fraudulent data | | **Product type** | The verification product associated with this task | | **Tracking info** | Tracking identifier passed through from the order or bridge token | | **Bridge token** | The bridge token used to initialize this connection attempt | | **User ID** | ID of the applicant user associated with this task | ### Search and filters | Name | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | **Search** | Search by task ID, link ID, user ID, order ID, bridge token, or tracking info | | **Date period** | Filter by when the task was created. Presets: Last 24 hours, Last 7 days, This week, Last 30 days (default), Last 90 days, or a custom date range | | **Status** | Filter by task outcome: Done, Error, Login Error, Account Locked, MFA Error, Config Error, No Data, Unavailable, Unable to Reset, or Not Supported | | **Product type** | Filter by the verification product associated with the task | | **Data provider** | Filter by the specific provider the applicant attempted to connect to | ### Open a task Click any task row to open the task detail. The detail view shows: | Field | Description | | ---------------------- | ----------------------------------------------------------------- | | **ID** | Unique identifier for this task | | **Created** | Timestamp when the connection attempt was initiated | | **Last updated** | Timestamp when the task was last updated | | **Provider** | The data provider the applicant attempted to connect to | | **Environment** | Sandbox or Production | | **Status** | Outcome of the connection attempt (e.g., Done, Login error) | | **User ID** | Links to the associated user record | | **Link ID** | ID of the link this task belongs to | | **Link is suspicious** | Whether the link was flagged for potential fraud | | **Bridge token** | The bridge token used to initialize this connection | | **Error message** | Details about any error that occurred during the attempt | | **Tracking info** | Tracking identifier passed through from the order or bridge token | | **Product type** | The verification product associated with this task | | **Logs** | Link to view raw connection logs for debugging | Truv Dashboard - Task detail ### Export Like Users and Orders, the Tasks table can be exported as a CSV with all active filters and columns applied. *** ## Coverage The Coverage tab shows Truv's provider coverage across four product categories: * **Payroll** * **Insurance** * **Financial Accounts** * **Scoring Attributes** Truv Dashboard - Coverage ### Provider search In the Payroll and Financial Accounts categories, search for a specific employer, payroll provider, or financial institution to see: * Whether the provider is covered by Truv * The historical connection success rate for that provider Truv Dashboard - Coverage search Each result displays a success rate indicator. The icon shown reflects Truv's historical connection data for that provider:
Icon Rating Payroll Financial accounts
High Expected to succeed, send the verification order. Expected to succeed, send the verification order.
Low May succeed, send if the user knows their payroll provider and is confident. May succeed, send if the user is confident and knows their login credentials.
Unsupported Verification via payroll is not feasible. Try Truv's Document Upload solution or the next step in your waterfall as an alternative. Verification with this financial institution is not supported, use an alternative method.
Unknown Not enough attempts to determine success. May succeed if the user knows their payroll provider and it's supported by Truv. Not enough attempts to determine success. Likely to succeed based on other financial institutions.
*** ## Next steps Manage orders programmatically via the API Retrieve task details and statuses Full payroll provider coverage list Full financial institution coverage list # Billing Source: https://docs.truv.com/developers/dashboard/billing View your subscription, invoices, and usage data View your subscription, track invoices, monitor credits, and break down usage in the Billing section. It has four tabs: **Subscription**, **Invoices**, **Credits**, and **Usage**. *** ## Subscription The Subscription tab shows your current active plan and enabled products. Truv Dashboard - Subscription * Plan name and enabled product details * Billing cycle and price per billable unit (task, report, or loan, depending on your contract) *** ## Invoices The Invoices tab lists all invoices issued to your account. Truv Dashboard - Invoices For each invoice you can: * View invoice details including date, amount, invoice number, due date, and status * Open a direct link to the invoice * Pay outstanding invoices *** ## Credits The Credits tab is visible when your account has a credit balance. It shows how credits are being consumed over time. All dates in the Credits tab are displayed in UTC. ### Summary | Metric | Description | | -------------------- | ------------------------------------------------------ | | **Starting balance** | Credit balance at the beginning of the selected period | | **Ending balance** | Credit balance at the end of the selected period | | **Total usage** | Total credits consumed during the selected period | ### Charts Two line charts visualize credit activity over the selected date range: * **Usage** — daily credit consumption * **Credits balance** — daily ending balance Use the **date period** filter to adjust the range (up to 365 days). *** ## Usage The Usage tab shows a detailed breakdown of all usage in your account, mapped to your billable unit. Truv Dashboard - Usage * The view adjusts to reflect whether your contract bills per **task**, **report**, or **loan** * Filter by **date range** to see usage for a specific billing period * Click **Export CSV** to download usage data for reconciliation against your invoice # Customization Source: https://docs.truv.com/developers/dashboard/customization Control branding, order defaults, templates, and API response fields Brand your verification experience, configure order-level defaults, manage templates, and control which fields your API responses return. The Customization section has four areas: **Branding**, **Order Settings**, **Templates**, and **Data**. *** ## Branding Set your company's visual identity for all verification experiences. Truv Dashboard - Branding Branding settings apply globally across your account as defaults. Template-level branding takes precedence when a template is applied to an order. | Setting | Description | | -------------------- | ------------------------------------------------------------------------------------------------------------- | | **Company logo** | Displayed in emails, verification screens, and Truv Bridge. PNG or JPG under 2 MB. Circular logo recommended. | | **Company name** | Displayed in verification communications | | **Accent color** | Primary color in the verification UI | | **Background color** | Background overlay color for the verification UI (desktop only) | | **Hide confetti** | Show or hide the confetti animation on successful connection | Click **Preview** to see your branding in the Emulator before saving, or **Apply** to save changes. *** ## Order Settings Configure account-wide defaults applied to all orders unless overridden at the template level. Truv Dashboard - Order settings | Setting | Description | | --------------------------------------- | ---------------------------------------------------------------------------------------- | | **End-user agreement / privacy policy** | Toggle on to add a URL to all verification experiences | | **Link expiration** | How long verification links stay active before expiring (e.g. 3 days) | | **Customer support email** | Support email address shown to end users during verification | | **Custom field** | Enforces a required custom data field (e.g. loan number) on all orders | | **Custom phone number** | Send SMS notifications from a specific authenticated phone number via Twilio integration | *** ## Templates Create and manage templates to apply distinct customizations to individual workflows or clients. Truv Dashboard - Templates Templates give fine-grained control over branding, the end-user experience, and returned data for individual workflows. Select a template when creating an order to apply its full configuration. Templates also control **order manager access** — a team member assigned to a specific template can only create orders with that template and can only view orders using it. This makes templates an effective tool for branch-level access control. See the full [UX Customization guide](/developers/customization) for detailed configuration options for each template section. *** ## Data Control which fields are included in API responses for each product type. Truv Dashboard - Data Select a product type to view its full API response schema. Each field group (Profile, Employer, Employment, Income, Pay statements, Earnings, etc.) can be expanded to show individual fields. Uncheck any field to exclude it from all API responses when a connection is completed using that product type. This is useful for limiting data returned to only what your application needs. *** ## Next steps Full template configuration reference Full configuration reference for templates # Development Source: https://docs.truv.com/developers/dashboard/development Manage API keys, view logs, and configure webhooks for your Truv integration Authenticate, debug, and extend your Truv integration from one place — manage API keys, inspect request logs, and configure webhooks. The Development section has three tabs: **API Keys**, **Logs**, and **Webhooks**. *** ## API Keys The API Keys tab is where you find and manage your Truv credentials. Truv Dashboard - API Keys ### Client ID Your **Client ID** is displayed at the top of the page. Pass it as the `X-Access-Client-Id` header on all API requests. ### Keys table The table shows all API keys for your account, grouped by environment (Sandbox, Development, Production): | Column | Description | | ---------------- | ------------------------------------------------ | | **Environment** | Sandbox, Development, or Production | | **Created date** | When the key was generated | | **Secret** | Masked except for the last four characters | | **Last used** | Most recent API call authenticated with this key | #### Actions * **Reveal** — Show the full key value on screen * **Copy** — Copy to clipboard without revealing * **Delete** — Permanently remove the key (irreversible) * **Generate new key** — Create a new key for an environment You cannot have more than **two active keys per environment**. Deleting a key is permanent and immediately revokes authentication for any system using it. ### Rotate API keys To rotate keys without downtime: 1. Generate a new key 2. Update your integration to use the new key 3. Test to confirm the new key works 4. Delete the old key only after confirming the new key is live See [API Keys Rotation](/api-reference/authentication) for the full rotation guide. *** ## Logs The Logs tab shows a record of all API requests associated with your account. Truv Dashboard - Logs ### Filters | Filter | Description | | -------------- | ----------------------------------------- | | **Date range** | Narrow to a specific time window | | **Status** | HTTP response status: 200, 400, 500, etc. | | **Brand** | Filter by a specific sub-company or brand | Use Logs to debug integration issues, trace specific requests, and understand API traffic patterns. *** ## Webhooks The Webhooks tab lets you configure endpoints where Truv sends event notifications. Truv Dashboard - Webhooks ### Create a webhook | Field | Description | | --------------- | ------------------------------------------------- | | **Name** | A label to identify this webhook | | **URL** | The HTTPS endpoint where Truv sends POST requests | | **Environment** | Production, Development, or Sandbox | | **Events** | The event types that trigger this webhook | Always validate the `X-WEBHOOK-SIGN` header before processing any webhook payload. See [Webhook Security](/api-reference/security#webhook-signature-verification). See [Webhooks](/api-reference/webhooks) for the full list of supported event types and payload schemas, plus delivery best practices — 10-second timeout, retry behavior, and idempotency guidance. *** ## Next steps API authentication reference Full list of webhook event types Step-by-step key rotation guide Webhook signature verification # Emulator Source: https://docs.truv.com/developers/dashboard/emulator Preview and test the Truv verification experience as the end-user using different products and flows. Walk through the end-user verification experience with simulated conditions — preview templates, test workflows, and demo the Bridge flow before shipping. *** ## Configure the emulator Emulator allows you to explore the end-user experience using different Products, Solutions, Templates, as well as routing to a specific Company or Payroll provider. Truv Dashboard - Emulator | Option | Description | | ------------------------- | ------------------------------------------------------------------------------------------------------- | | **Product type** | Income & Employment, Assets, etc. | | **Solution** | Payroll only, or include fallback workflows (document upload, financial accounts, etc.) | | **Template** | Preview how your branding and [template configuration](/developers/dashboard/customization) will appear | | **Company / Provider ID** | Optionally specify a company or provider to open that connection directly | *** ## Explore the verification flow Once configured, click any company in the search results and use one of our [login test credentials](/developers/testing/test-credentials#universal-login-scenarios) to begin the simulated login experience. In Sandbox mode, the emulator lets you test every solution: * Payroll connections * Financial accounts * Document processing (paystubs, W-2s, tax returns) * Smart routing, Choice Connect, and fallback workflow behavior As you click through the experience, login events and their corresponding JSON payloads are loaded in real time. Once a connection is complete, the returned report can be viewed in the UI, as a JSON payload, or downloaded via PDF. Truv Dashboard - Emulator report *** ## Common use cases * **Training demos** — Walk a client through the borrower experience before go-live, with their branding applied via a template * **Template QA** — Validate that branding, copy, and search categories are configured correctly * **Workflow testing** — Reproduce specific fallback or error scenarios in a controlled environment *** ## Next steps Use sandbox credentials to simulate different outcomes Configure the template shown in the emulator # Home Source: https://docs.truv.com/developers/dashboard/home Monitor verification performance and team activity from your reporting dashboard Monitor verification activity and team performance in real time. Home opens on login with two tabs: **Reporting** and **Team Performance**. *** ## Reporting The Reporting tab shows performance metrics for all verifications in the selected period. Truv Dashboard - Reporting ### Filters Use the filter bar to slice the data: | Filter | Description | | ----------------------- | --------------------------------------------------------------------------- | | **Date** | Select a date range for the reporting period | | **Companies** | Filter by sub-company in a [multi-tenancy](/developers/multi-tenancy) setup | | **Product type** | Income & Employment, Assets, etc. | | **Data source** | Payroll, Document Upload, Financial Accounts, etc. | | **Initial vs. Refresh** | Toggle between initial and refresh orders | | **Source** | Dashboard, API, Encompass, or other platforms | | **Template** | Filter by a specific [customization template](/developers/customization) | | **Orders vs. Embedded** | Compare hosted order performance vs. Bridge embedded implementations | ### Charts and tables | Chart | What it shows | | ----------------------------------- | -------------------------------------------------------------------------------------------------------- | | **Total order volume** | Total orders created in the selected period | | **Conversion rate graph** | Created orders and conversion rate over time | | **Status breakdown** | Distribution by status: completed, expired, canceled, etc. | | **Order turnaround time** | Time from creation to completion, broken down by notification method (Email & SMS, Email only, SMS only) | | **Funnel** | Step-by-step breakdown of where users drop off in the verification flow | | **Error distribution** | Incomplete orders broken down by error type | | **Benchmark** | Your conversion rate compared to industry benchmarks | | **Volume & conversion by template** | Order count, completions, and conversion rate per template | ### Export Click **Export CSV** in the top-right corner of any chart to download the underlying data. ### Notifications The bell icon in the top navigation shows in-app notifications in three categories: * **Order updates** — Order completed, canceled, expired, or moved to another terminal status * **Team updates** — A team member requires approval to access the account * **API updates** — A new API key was issued or rotated In addition to opening notifications through the bell icon, notifications will automatically appear as a tile in the Dashboard. To edit notification preferences, see the [Settings](/developers/dashboard/settings) tab. *** ## Team Performance The Team Performance tab shows orders created and conversion rate broken down by individual team members. * Filter by template to see per-template performance for each member * Export the table as a CSV *** ## Next steps View individual users, orders, and tasks Configure templates to brand your experience # Settings Source: https://docs.truv.com/developers/dashboard/settings Configure company details, manage your team, and control notification preferences Configure your company, manage team members, and control notification preferences across four tabs: **Company**, **Team**, **Profile**, and **Notifications**. *** ## Company Truv Dashboard - Company settings | Field | Description | | ------------------------ | ------------------------------------------------------------------------------- | | **Company name** | Name displayed in the Dashboard | | **Website** | Your company's website URL | | **Billing email** | Email address for billing communications | | **Status updates email** | Email address for receiving order status notifications | | **Show / hide API keys** | Control whether API keys are visible to team members in the Development section | *** ## Team The Team tab shows all members in your Truv Dashboard account. Truv Dashboard - Team ### Table columns | Column | Description | | ----------------------- | -------------------------------------------------------------------------------- | | **Name** | Team member's full name | | **Email** | Team member's email address | | **Created at** | Date the member was added | | **Role** | Assigned role (Owner, Administrator, Developer, Orders Manager, Billing Manager) | | **Status** | Current membership status (see [Member statuses](#member-statuses) below) | | **Available templates** | Templates the member has access to | | **Actions** | Actions available per member (see [Member actions](#member-actions) below) | ### Member statuses | Status | Description | | ------------------------ | ------------------------------ | | **Active** | Accepted invite, full access | | **Invited** | Email sent, pending acceptance | | **Waiting for approval** | Signed up, not yet approved | | **Declined** | Access denied | | **Invite expired** | Link expired before acceptance | | **Invitation error** | Invite send failed | | **Deactivated** | Account deactivated | ### Member actions | Action | When available | | ---------------------------- | --------------------------------- | | **Edit** | Always — change role or templates | | **Approve / Decline member** | For members waiting for approval | | **Revoke access** | For active members | | **Grant access** | For declined members | | **Resend invite** | When invite has expired | | **Delete** | For declined or expired members | ### Search and filters | Name | Description | | ------------- | ------------------------------------------------------------------------------------------ | | **Search** | Search by name or email across members of the selected status | | **Status** | Filter by invite status: All members, Approved, Invited, Waiting for approval, or Declined | | **Templates** | Filter by assigned template. Supports multi-select with search. | | **Roles** | Filter by role. Supports multi-select. | Click **Export CSV** to download the current member list. ### Add a member Click **Add Member** and provide: * First name, last name, and email address * Role to assign * Available templates — if the member has the Orders Manager role and you want to restrict their access to specific templates, select the templates here. If none are selected, they can access all templates. Truv Dashboard - Add member The member receives an email with a link to set their password. After setting a password or logging in via Google, Microsoft, or SSO, they are automatically approved. ### Roles See the [full role access matrix](/developers/dashboard#team-roles-and-permissions). In a [multi-tenancy](/developers/multi-tenancy) setup, team members can have different roles in each company. *** ## Profile The Profile tab shows your personal account information. Truv Dashboard - Profile | Field | Description | | -------------- | -------------------------------------------------- | | **First name** | Your first name (editable) | | **Last name** | Your last name (editable) | | **Email** | Your login email address (read-only) | | **Role** | Your assigned role (read-only, visible for Owners) | Click **Save** to apply any changes. *** ## Notifications The Notifications tab controls which notifications you receive and how. Truv Dashboard - Notifications ### Delivery methods For each notification type, toggle delivery via **Email** or **Dashboard** (in-app bell), or both. Deselecting a method stops delivery through that channel. If enabled, a notification feed tile will briefly appear on the Dashboard when a notification is triggered. This can be disabled by unchecking **Show notification popups**. ### Notification types | Notification | Trigger | | ------------------------------------ | ------------------------------------------------------------------------------------------------------------ | | **Order updates** | Get notified when an order you created or were added to completes, expires, or gets updated in any other way | | **Automatically created orders** | Get notified when an order is created in Encompass via ASO and your role is a recipient | | **Refreshes requiring reconnection** | Get notified when a refreshed order requires the end-user to reconnect their accounts | | **Members pending approval** | Get notified when a team member joins the Truv Dashboard and requires approval | | **Production keys** | Get notified when a production API key is issued or rotated | *** ## Next steps Set up single sign-on for your team Manage multiple companies # Support Source: https://docs.truv.com/developers/dashboard/support Submit and track support tickets with the Truv team Submit and track support tickets with the Truv team. Log in with your Truv credentials to access the support portal. Truv Dashboard - Support *** ## What you can do * **View open tickets** — See all active support requests for your account. Click a ticket to see responses from support and reply to the thread. * **Filter by scope** — View tickets submitted by yourself or across your entire organization. Search tickets by Subject or ID. * **Export tickets** — Download ticket data as a CSV * **Submit new tickets** — Create a new support request directly from the portal *** ## Get help Browse FAQs and how-to articles Reach the Truv support team directly # Bank Income Demo Source: https://docs.truv.com/developers/demos/consumer-credit/bank-income Verify applicant income from bank transactions when payroll data is unavailable The Bank Income demo shows how to verify income by connecting to an applicant's bank account and analyzing transaction history — use this when payroll data isn't available for the applicant's employer. **Source:** [GitHub](https://github.com/truvhq/demo-apps#consumer-credit) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Consumer Credit" → "Bank Income" ``` Bank Income demo ## Flow The backend creates a user and generates a bridge token restricted to financial accounts. ``` POST /v1/users/ POST /v1/users/{id}/tokens/ # { product_type: "income", data_sources: ["financial_accounts"] } ``` Bridge opens showing only financial institutions. The applicant selects their bank and logs in. Sandbox credentials: `goodlogin` / `goodpassword` `task-status-updated` fires on completion. Fetch the Income Insights report. ``` POST /v1/users/{user_id}/income_insights/reports/ ``` **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** Income Insights # Paycheck-Linked Loans Demo Source: https://docs.truv.com/developers/demos/consumer-credit/paycheck-linked-loans Verify income and set up automatic loan repayment through payroll deductions in one flow The Paycheck-Linked Loans demo shows how to verify income and configure automatic loan repayment via payroll deductions in one Bridge flow. Payments start on the next pay cycle once the applicant connects their payroll provider. **Source:** [GitHub](https://github.com/truvhq/demo-apps#consumer-credit) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Consumer Credit" → "Paycheck-Linked Loans" ``` Paycheck-Linked Loans demo ## Flow The backend creates a user and generates a bridge token with `product_type: pll`. ``` POST /v1/users/ POST /v1/users/{id}/tokens/ # { product_type: "pll", account_details: true } ``` Bridge opens. The applicant selects their employer, logs in, and authorizes the payroll deduction. Sandbox credentials: `goodlogin` / `goodpassword` `task-status-updated` fires on completion. Fetch both the VOIE report and the deposit switch report. ``` POST /v1/users/{user_id}/reports/ GET /v1/users/{user_id}/deposit_switch/report/ ``` **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** PLL # Payroll Income Demo Source: https://docs.truv.com/developers/demos/consumer-credit/payroll-income Verify income and employment directly from payroll data for fast lending decisions The Payroll Income demo shows the fastest path to income verification: connect directly to the applicant's payroll provider to return current income, employment status, and pay history in a single flow. **Source:** [GitHub](https://github.com/truvhq/demo-apps#consumer-credit) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Consumer Credit" → "Payroll Income" ``` Payroll Income demo ## Flow The backend creates a user and generates a bridge token restricted to payroll providers. ``` POST /v1/users/ POST /v1/users/{id}/tokens/ # { product_type: "income", data_sources: ["payroll"] } ``` Bridge opens showing only payroll providers. The applicant selects their employer and logs in. Sandbox credentials: `goodlogin` / `goodpassword` `task-status-updated` fires on completion. Fetch the VOIE report. ``` POST /v1/users/{user_id}/reports/ ``` **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** VOIE # Smart Routing Demo Source: https://docs.truv.com/developers/demos/consumer-credit/smart-routing Check employer payroll coverage and route applicants to the fastest verification method The Smart Routing demo checks an employer's payroll coverage and recommends the best verification path — payroll, bank transactions, or document upload — based on actual coverage data. **Source:** [GitHub](https://github.com/truvhq/demo-apps#consumer-credit) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Consumer Credit" → "Smart Routing" ``` Smart Routing demo ## Flow The applicant enters their employer name. The backend checks payroll coverage and returns a `success_rate`. ``` GET /v1/company-mappings-search/?query=... ``` Based on `success_rate`, the UI recommends a `data_sources` value. The backend creates a user and token. ``` POST /v1/users/ POST /v1/users/{id}/tokens/ # { product_type: "income", data_sources: [...] } ``` Bridge opens with the selected method. After completion, fetch the report. ``` POST /v1/users/{user_id}/reports/ ``` **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** VOIE # Document Processing Demo Source: https://docs.truv.com/developers/demos/mortgage/document-processing Upload pay stubs, W-2s, and tax returns and extract structured income data for underwriting The Document Processing demo shows how to validate and extract structured income data from documents already collected — pay stubs, W-2 forms, tax returns, and bank statements — without launching Bridge. **Source:** [GitHub](https://github.com/truvhq/demo-apps#mortgage) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Mortgage" → "Document Processing" ``` Document Processing demo ## Flow Upload pay stubs, W-2s, 1040s, or bank statements. The backend creates a user and a document collection. ``` POST /v1/users/ POST /v1/documents/collections/ ``` Poll until all files reach a terminal status. ``` GET /v1/documents/collections/{id}/ ``` Finalize the collection to generate the structured income report. ``` POST /v1/documents/collections/{id}/finalize/ GET /v1/documents/collections/{id}/finalize/ ``` **Integration pattern:** [Document Processing](/developers/integration/document-processing) | **Products:** Pay stubs, W-2s, 1040s, bank statements # LOS Demo Source: https://docs.truv.com/developers/demos/mortgage/los Create verification orders from your LOS and send borrowers a link to complete on their own The LOS demo shows server-side order creation: a loan processor creates verification orders using borrower data already on file, and Truv sends the borrower an email or SMS link to complete verification on their own device. **Source:** [GitHub](https://github.com/truvhq/demo-apps#mortgage) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Mortgage" → "LOS" ``` LOS demo ## Flow Enter borrower PII from the LOS. The backend creates an order and receives a `share_url`. ``` POST /v1/orders/ # Returns order_id + share_url ``` Truv delivers the `share_url` to the borrower via email or SMS. No Bridge embedding needed on your end. The borrower opens the link and connects their employer. `order-status-updated` fires on completion. ``` POST /v1/users/{user_id}/reports/ ``` **Integration pattern:** [Hosted Orders](/developers/integration/hosted-orders/new-user) | **Products:** VOIE, VOE # POS Application Demo Source: https://docs.truv.com/developers/demos/mortgage/pos-application Verify borrower income or assets in real time during the loan application The POS Application demo shows how a borrower fills out a loan application and verifies income or assets inline, without leaving the point-of-sale. **Source:** [GitHub](https://github.com/truvhq/demo-apps#mortgage) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Mortgage" → "POS Application" ``` POS Application demo ## Flow Enter applicant PII. The app searches for the employer and creates an Order. ``` GET /v1/company-mappings-search/?query=... POST /v1/orders/ ``` Truv Bridge opens inline. The borrower selects their employer and logs in. Sandbox credentials: `goodlogin` / `goodpassword` `order-status-updated` fires on completion. Fetch the structured report. ``` POST /v1/users/{user_id}/reports/ ``` **Integration pattern:** [Embedded Orders](/developers/integration/embedded-orders/overview) | **Products:** VOIE, VOA # POS Tasks Demo Source: https://docs.truv.com/developers/demos/mortgage/pos-tasks Complete outstanding income, employment, and asset verifications after loan submission The POS Tasks demo shows the follow-up flow: after submitting a loan application, the borrower returns to complete outstanding verification tasks — income, employment, and assets — all linked by a shared `external_user_id`. **Source:** [GitHub](https://github.com/truvhq/demo-apps#mortgage) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Mortgage" → "POS Tasks" ``` POS Tasks demo ## Flow The loan processor creates separate orders for income, employment, and assets — all sharing the same `external_user_id`. ``` POST /v1/orders/ # income POST /v1/orders/ # employment POST /v1/orders/ # assets ``` Each order returns a `bridge_token`. Bridge opens for each task in sequence. Sandbox credentials: `goodlogin` / `goodpassword` `order-status-updated` fires per task. Fetch the appropriate report for each. ``` POST /v1/users/{user_id}/reports/ POST /v1/users/{user_id}/assets/reports/ ``` **Integration pattern:** [Embedded Orders](/developers/integration/embedded-orders/overview) (multi-task) | **Products:** VOIE, VOE, VOA # Case Worker Portal Demo Source: https://docs.truv.com/developers/demos/public-sector/case-worker-portal Create verification orders from applicant data and send a link for self-service completion The Case Worker Portal demo shows server-side order creation for government workflows: a caseworker creates verification orders using applicant data on file, and Truv sends the applicant a link to complete verification on their own device. **Source:** [GitHub](https://github.com/truvhq/demo-apps#public-sector) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Public Sector" → "Case Worker Portal" ``` Case Worker Portal demo ## Flow Enter applicant PII from the case management system. The backend creates an order and receives a `share_url`. ``` POST /v1/orders/ # Returns order_id + share_url ``` Truv delivers the `share_url` to the applicant via email or SMS. The applicant opens the link and connects their employer. `order-status-updated` fires on completion. ``` POST /v1/users/{user_id}/reports/ ``` **Integration pattern:** [Hosted Orders](/developers/integration/hosted-orders/new-user) | **Products:** VOIE, VOE # Customer Portal Demo Source: https://docs.truv.com/developers/demos/public-sector/customer-portal Let benefit applicants verify income and employment through a self-service portal The Customer Portal demo shows a self-service benefits portal where an applicant verifies their income and employment through an embedded Truv flow — no caseworker required. **Source:** [GitHub](https://github.com/truvhq/demo-apps#public-sector) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Public Sector" → "Customer Portal" ``` Customer Portal demo ## Flow The applicant enters their PII in the benefits portal. The backend searches for the employer and creates an Order. ``` GET /v1/company-mappings-search/?query=... POST /v1/orders/ ``` Truv Bridge opens inline. The applicant connects their payroll provider. Sandbox credentials: `goodlogin` / `goodpassword` `order-status-updated` fires on completion. Fetch income and employment data for eligibility. ``` POST /v1/users/{user_id}/reports/ ``` **Integration pattern:** [Embedded Orders](/developers/integration/embedded-orders/overview) | **Products:** VOIE, VOE # Document Processing Demo Source: https://docs.truv.com/developers/demos/public-sector/document-processing Process pay stubs, W-2s, and tax returns for benefit eligibility decisions The Public Sector Document Processing demo shows how to extract structured income data from documents submitted by benefit applicants for eligibility determination. **Source:** [GitHub](https://github.com/truvhq/demo-apps#public-sector) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Public Sector" → "Document Processing" ``` Public Sector Document Processing demo ## Flow Upload documents submitted by the applicant. The backend creates a user and a document collection. ``` POST /v1/users/ POST /v1/documents/collections/ ``` Poll until all files reach a terminal status. ``` GET /v1/documents/collections/{id}/ ``` Finalize to generate the structured income report for eligibility determination. ``` POST /v1/documents/collections/{id}/finalize/ GET /v1/documents/collections/{id}/finalize/ ``` **Integration pattern:** [Document Processing](/developers/integration/document-processing) | **Products:** Pay stubs, W-2s, 1040s, bank statements # Direct Deposit Switch Demo Source: https://docs.truv.com/developers/demos/retail-banking/direct-deposit-switch Switch a customer's direct deposit to your bank through their payroll provider The Direct Deposit Switch demo shows how a new customer connects their payroll provider and redirects their direct deposit routing to your bank. The change takes effect on the next pay cycle. **Source:** [GitHub](https://github.com/truvhq/demo-apps#retail-banking) ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps && npm install && cp .env.example .env npm start && npm run dev # select "Retail Banking" → "Direct Deposit Switch" ``` Direct Deposit Switch demo ## Flow The backend creates a user and generates a bridge token with `product_type: deposit_switch`. ``` POST /v1/users/ POST /v1/users/{id}/tokens/ # { product_type: "deposit_switch", account_details: true } ``` Bridge opens. The customer selects their employer and logs in to authorize the deposit switch. Sandbox credentials: `goodlogin` / `goodpassword` `task-status-updated` fires on completion. Fetch the deposit switch report. ``` GET /v1/users/{user_id}/deposit_switch/report/ ``` **Integration pattern:** [Bridge Widget](/developers/integration/bridge-widget/overview) | **Products:** DDS # Fraud Detection & Manual Review Source: https://docs.truv.com/developers/fraud-and-manual-review How to interpret the is_suspicious flag, detect document fraud, and handle manual review scenarios Truv provides two layers of protection when processing verifications: an `is_suspicious` flag on verification reports and detailed error detection for document uploads. Understanding when and how to act on each is critical for maintaining data integrity without creating unnecessary friction. *** ## Detect document upload fraud For document processing (pay stubs, W-2s, tax forms), Truv runs every uploaded document through fraud detection trained on 50M+ verified pay stubs. When fraud or data issues are detected, the connection status is set to `config_error` or `no_data`. ### Detecting fraud in document uploads When a document upload task completes with a `config_error` status, fetch the task record to get the specific error message: ```bash theme={null} curl --request GET \ --url 'https://prod.truv.com/v1/tasks/?order_id=ORDER_ID' \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` Check the `error_message` field on each task in the response. The `error_message` field on the task record provides the specific reason for the failure. ### config\_error messages These indicate issues with the uploaded documents that require action. Some are fraud-related, others are validation failures. | error\_message | Description | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Possible tampering detected` | The document appears to have been altered or modified from its original form. **This is the strongest fraud signal.** Route to your fraud review team. | | error\_message | Description | | --------------------------------------------------------------- | --------------------------------------------------------------------- | | `The documents contain different full names` | Full names across uploaded documents don't match each other | | `The documents contain different company names` | Employer names across uploaded documents don't match each other | | `The documents contain different SSN's` | SSNs across uploaded documents don't match each other | | `The applicant first name mismatched with one in the documents` | The applicant's first name from the order doesn't match the documents | | `The applicant last name mismatched with one in the documents` | The applicant's last name from the order doesn't match the documents | | `SSN mismatch in application and data` | The SSN from the order doesn't match the SSN in the documents | These errors only occur for documents uploaded through the Truv Bridge experience. For document collections, the same issues are caught up front by the validation check at upload time (see [Monitor validation and classification](/developers/integration/document-processing#step-4-monitor-validation-and-classification-server-side)) and never reach this `config_error` path. | error\_message | Description | | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | | `Please upload documents without password protection or encryption.` | The file is password-protected or encrypted. Re-upload an unprotected version. | | `File type not supported. Please ensure each uploaded file matches the requested document type.` | Unsupported file format. Accepted formats include PDF and common image types. | | `Some documents have mismatched type or subtype: '{filename}' has '{type}' type, expected '{type}'` | A paystub was uploaded when a W-2 was expected, or vice versa | ### no\_data messages These indicate the documents were processed but didn't contain enough information to complete the verification. | error\_message | Description | | ---------------------------------------------------------------------------------- | --------------------------------------------------------- | | `Not enough data to complete the task` | Documents didn't contain sufficient information | | `No employment dates are available` | Employment dates couldn't be found in the documents | | `No saved employments found` | No employment records found in the documents | | `The connected account does not have required data` | The account doesn't contain the needed data | | `No paystubs or W-2s found for the most recent employment` | No recent income documents found for the current employer | | `Required data not found in the source` | Required verification data couldn't be located | | `No statements found for employment` | No income statements found for the reported employment | | `Most recent company does not have address` | Employer address couldn't be determined | | `Empty annual income summary data for {year}` | No annual income summary for the specified year | | `Task {task_id}. Profile validation failed: first_name and last_name are required` | Applicant name wasn't provided. Required for processing. | *** ## Manual Review with is\_suspicious Flag Every income and employment verification report includes an `is_suspicious` boolean field. When `true`, it signals that something in the returned data warrants a closer look. It **does not necessarily indicate fraud**. ### Two-tier fraud detection Truv uses a two-tier detection system. The tier determines whether the task completes with data or fails entirely. | Tier | Behavior | `is_suspicious` | Task status | Data returned | When it triggers | | ---------- | ---------------------------- | --------------- | -------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | | **Tier 1** | Task completes, data flagged | `true` | `completed` | Yes | Data anomalies detected but document is processable (e.g., SSN mismatch, name mismatch, minor inconsistencies) | | **Tier 2** | Task fails, no data returned | N/A | `config_error` | No | Document is too suspicious to process (e.g., confirmed tampering, known fraud template match) | Tier 1 flags require manual review but still return data. Tier 2 blocks the verification entirely because the document cannot be trusted. Check the task `error_message` for Tier 2 failures. ### Common triggers | Scenario | What happened | Tier | Recommended action | | ------------------------ | --------------------------------------------------------------------------------- | ---- | ---------------------------------------------------------------------------------- | | **Name mismatch** | The order was for John Doe, but his spouse Jane Doe connected her payroll account | 1 | Manual review. Verify the correct person connected. | | **SSN mismatch** | The SSN on the order doesn't match the SSN returned from the payroll provider | 1 | Manual review. Confirm identity with the applicant. | | **Employer mismatch** | The applicant's reported employer doesn't match the connected payroll account | 1 | Manual review. The applicant may have changed jobs or connected the wrong account. | | **Document tampering** | Uploaded document metadata or content shows signs of alteration | 2 | Route to fraud team. No data is returned. | | **Known fraud template** | Document matches a known fraudulent template pattern | 2 | Route to fraud team. No data is returned. | ### Detection indicators Truv's fraud detection engine, trained on 50M+ verified pay stubs, analyzes documents across multiple dimensions. Every uploaded document carries metadata that reveals its creation and editing history. Truv inspects PDF producer fields, creation timestamps, and modification history to detect documents that were generated or altered using manipulation tools rather than produced by a legitimate payroll system. Truv maintains a library of known fraudulent document templates. Uploaded documents are compared against these patterns to catch documents created from widely circulated fraud kits or template generators. Documents edited with PDF manipulation software leave distinct artifacts. Truv detects these fingerprints, including font substitution, layer inconsistencies, and editing tool signatures that differ from legitimate payroll-generated documents. Pay stubs "printed to PDF" from a browser rather than exported from a payroll system have different structural characteristics. While not always fraudulent, browser-generated PDFs bypass the payroll system's native export and are flagged for review. Truv validates that pay dates, pay period start and end dates, and year-to-date totals are internally consistent. Mismatched dates, impossible pay periods, or YTD totals that don't align with pay frequency are flagged. When multiple documents are uploaded (e.g., several pay stubs or a pay stub plus a W-2), Truv cross-references them for consistency. Inconsistencies trigger Tier 1 flags or Tier 2 failures depending on severity: | Check | Flag | | ------------------------------------------ | ----------------------------------------------- | | Different SSNs across documents | `The documents contain different SSN's` | | Different company names across documents | `The documents contain different company names` | | Different applicant names across documents | `The documents contain different full names` | Individual fields within a document are validated against each other. Truv checks that gross pay, deductions, and net pay are arithmetically consistent, that tax withholdings are within plausible ranges for the stated income, and that employer identification numbers (EINs) match known formats. ### How to handle each tier #### Tier 1: `is_suspicious = true` The `is_suspicious` flag appears in the response body when you fetch a verification report: ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "completed", "is_suspicious": true, "employers": [...] } ``` When `is_suspicious` is `true`: 1. **Do not auto-reject.** The flag is a signal for manual review, not an automatic denial. 2. **Compare the order details against the returned data.** Check names, SSN, and employer information. 3. **Contact the applicant if needed.** In many cases, the mismatch has a simple explanation (e.g., a spouse connected instead of the applicant). Treating `is_suspicious: true` as an automatic rejection will create false positives. Always route these to manual review rather than declining outright. #### Tier 2: Task fails with `config_error` When a document is too suspicious to process, the task fails with status `config_error` and no verification data is returned. Fetch the task record to get the specific `error_message`. See [Detect document upload fraud](#detect-document-upload-fraud) for all error messages and recommended actions. ### SSN mismatch detection When you create an order with the applicant's SSN, Truv automatically compares it against the SSN returned from the payroll provider or extracted from uploaded documents. This is a backend validation -- there is no front-end control or configuration. | Scenario | Source of truth | Comparison target | Result | | ----------------------------------- | ---------------- | ---------------------------------------- | --------------------------------------------- | | **Payroll connection** | SSN on the order | SSN from the payroll provider's records | `is_suspicious: true` if mismatch | | **Document upload (single doc)** | SSN on the order | SSN extracted from the uploaded document | `SSN mismatch in application and data` error | | **Document upload (multiple docs)** | Each document | Other uploaded documents | `The documents contain different SSN's` error | SSN matching runs automatically on every verification where an SSN is provided on the order. You cannot disable or configure this behavior. If no SSN is provided on the order, cross-matching against the payroll provider is skipped, but cross-document SSN consistency checks still run for document uploads. For payroll connections, an SSN mismatch sets `is_suspicious: true` on the report (Tier 1). The verification still completes with data, but you should route the result to manual review before accepting it. For document uploads, SSN mismatches produce `config_error` task failures with specific error messages listed in the [Identity mismatches](#detect-document-upload-fraud) section below. *** ## Recommended review workflow ```mermaid theme={null} flowchart TD A[Verification completes] --> B{Check status} B -->|completed| C{is_suspicious?} B -->|config_error| D[Fetch task details] B -->|no_data| E[Fetch task details] C -->|false| F[Auto-approve or proceed] C -->|true| G[Route to manual review] D --> H{error_message?} H -->|Possible tampering detected| I[Route to fraud team] H -->|Identity mismatch| G H -->|File issue| J[Request re-upload] E --> K[Request additional documents] ``` ### Priority levels | Signal | Priority | Action | | -------------------------------------------- | ------------------ | -------------------------------------------------- | | `Possible tampering detected` | **High: Fraud** | Escalate to fraud review team immediately | | Identity mismatches (names, SSN across docs) | **Medium: Review** | Manual review to determine if intentional or error | | `is_suspicious: true` on payroll connection | **Medium: Review** | Compare order details against returned data | | File issues (encrypted, wrong type) | **Low: Resubmit** | Ask applicant to re-upload correct documents | | `no_data` errors | **Low: Resubmit** | Request additional or different documents | *** ## Test fraud scenarios Truv provides test documents in sandbox mode to simulate fraud detection. See [Test Documents](/developers/testing/test-documents) for downloadable files including: * **Tampered documents**: triggers `Possible tampering detected` * **Different SSNs**: triggers SSN mismatch errors * **Different applicant names**: triggers name mismatch errors * **No data / invalid data**: triggers `no_data` scenarios *** ## Next steps Implementation guide for document uploads Test fraud detection with sample documents All connection statuses and error states Complete error code reference Client-side event reference for error handling and fallback routing # Welcome Source: https://docs.truv.com/developers/home Start here to integrate Truv into your application Truv provides instant verification of income, employment, and assets through direct connections to payroll providers and financial institutions. You integrate once and get structured, source-verified data back via API and webhooks. ## New to Truv? Run the [Quickstart](/developers/quickstart) to see a complete integration working in minutes. Then pick a [Demo App](/developers/quickstarts-overview#demo-apps) that matches your use case and use it as your starting point. Quickstart, demo apps, and use case guides *** ## Industry guides If you're building for a specific vertical, start with the industry tab for tailored product recommendations and integration paths. VOIE, VOA, VOE with GSE certification and LOS/POS integrations Benefits eligibility verification for SNAP, Medicaid, TANF Income and asset verification for auto loans, personal loans, credit Direct deposit switching and paycheck-linked lending *** ## Choose your integration method **Recommended for most use cases.** Create an order with applicant details, launch Truv Bridge in your app, and let the user connect their accounts. Supports income, employment, and asset verification. **For deposit switching and paycheck-linked lending.** Create a user and bridge token directly. No orders needed. The user connects their payroll account through Bridge. **No frontend required.** Create an order via API or Dashboard and Truv sends the verification link to the user via email or SMS. They complete Bridge on their own device. **No code at all.** Create and manage orders through the Truv Dashboard UI or CSV bulk upload. Ideal for low-volume or pilot workflows. **No Bridge needed.** Upload pay stubs, W-2s, and tax returns directly. Truv extracts structured income and employment data automatically. *** ## Understand the platform Before building, familiarize yourself with the core concepts that apply to every integration. How Orders, Users, Links, and Tasks relate to each other Processing stages, timing, and what data is available when API keys, base URL, and environment routing Real-time notifications for task and order status changes Client-side callbacks during the user connection flow HTTP error codes, response shapes, rate limits, and 429 backoff *** ## Get help Complete endpoint documentation with schemas Test credentials, sample documents, and sandbox setup SOC 2, GLBA, data protection, and trust center [support@truv.com](mailto:support@truv.com) # Deeplinking Source: https://docs.truv.com/developers/integration/bridge-widget/deeplinking Pre-fill account information in Bridge Widget flows to skip search steps Pre-fill employer or provider information when creating a bridge token to bypass the search screens. Use this for DDS and PLL flows where you already know the user's employer or provider. For Embedded Orders deeplinking (VOIE, VOE, VOA), see [Deeplinking for Embedded Orders](/developers/integration/embedded-orders/deeplinking). ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant Bridge as Truv Bridge Server->>API: Search company mapping API-->>Server: company_mapping_id Server->>API: Create bridge token with company_mapping_id API-->>Server: bridge_token Note over Bridge: User skips search screens Bridge->>Bridge: User lands on login page ``` *** ## Deeplink by employer Use this when you know the user's employer name. Truv maps the employer to the correct payroll provider automatically. ### Find the company mapping ```bash theme={null} curl --request GET \ --url 'https://prod.truv.com/v1/company-mappings-search/?query=Facebook' \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` ```json theme={null} [ { "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456", "name": "Facebook", // ... } ] ``` ### Create a bridge token with the mapping Pass the `company_mapping_id` when creating the bridge token. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "deposit_switch", "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456" }' ``` The user skips the employer search screen and lands directly on the provider login page. *** ## Deeplink by provider Use this when you know the specific payroll provider (e.g. ADP, Workday, Gusto) but not the specific employer. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/bridge-tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "deposit_switch", "provider_id": "adp", "user": { "id": "99dd17074ac94aa9ace2621d657c7610" } }' ``` All providers from the [List all data providers endpoint](/api-reference/data-providers/providers-list) are supported as deeplink targets. *** ## Next steps Find `company_mapping_id` by employer name All supported `provider_id` values Create bridge tokens with deeplink parameters Deeplinking for VOIE, VOE, and VOA flows # New User Source: https://docs.truv.com/developers/integration/bridge-widget/new-user Direct API integration for Deposit Switch and Paycheck Linked Lending Bridge Widget flow provides direct control over payroll connections, specifically designed for Deposit Switch and Paycheck Linked Lending use cases. **Bridge Widget is only for Deposit Switch and Paycheck Linked Lending.** For Income & Employment, Assets, or Employment verification, use [Embedded Orders](/developers/integration/embedded-orders/overview) instead. *** ## When to Use Bridge Widget ```mermaid theme={null} graph TD A[What are you building?] --> B{Use case?} B -->|Mortgage / Consumer Credit| C[Use Embedded Orders] B -->|Tenant Screening| C B -->|Government / Social Services| C B -->|Deposit Switch| D[Use Bridge Widget] B -->|Paycheck Linked Lending| D ``` | Use Case | Recommended Method | | ----------------------- | ------------------ | | Deposit Switch | **Bridge Widget** | | Paycheck Linked Lending | **Bridge Widget** | | Income & Employment | Embedded Orders | | Assets | Embedded Orders | | Employment | Embedded Orders | *** ## Token flow The Widget-only flow uses a three-token exchange to securely connect users: ```text theme={null} bridge_token → public_token → access_token ``` | Token | Created By | Lifetime | Purpose | | -------------- | ------------------------ | ----------- | ------------------------------------ | | `bridge_token` | Your server (via API) | 6 hours | Initialize Truv Bridge on the client | | `public_token` | Truv Bridge (on success) | Short-lived | Temporary token for exchange | | `access_token` | Token exchange (via API) | Persistent | Configure DDS/PLL and retrieve data | *** ## Implementation ### Step 1: Create a user \[Server-side] Create a user to associate with this connection. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "external_user_id": "your-internal-user-id", "first_name": "John", "last_name": "Doe" }' ``` Save the `id` from the response to use in the next step. ### Step 2: Create a bridge token \[Server-side] Create a bridge token with the user ID and your product configuration. Pass the `account` details for the destination bank account. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "deposit_switch", "allowed_products": ["deposit_switch"], "account": { "account_number": "151251215", "account_type": "checking", "routing_number": "12027471412", "bank_name": "AcmeBank" } }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "pll", "account": { "action": "create", "account_type": "savings", "bank_name": "Acme Bank", "routing_number": "12345678219", "account_number": "16002622100", "deposit_type": "amount", "deposit_value": "50.00" } }' ``` ### Step 3: Initialize Bridge Widget \[Client-side] Pass the `bridge_token` to Truv Bridge. When the user connects successfully, Bridge returns a `public_token` via the `onSuccess` callback. ```html theme={null} ``` See [Bridge Events](/developers/sdks/bridge-events) for all callback events, error codes, and payload shapes. ### Step 4: Exchange token and retrieve data \[Server-side] Exchange the `public_token` for a persistent `access_token`: ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/link-access-tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "public_token": "PUBLIC_TOKEN_FROM_BRIDGE" }' ``` Store the returned `access_token` securely. Use it to fetch data and manage the connection. *** ## Webhooks Listen for these server-side [webhook events](/api-reference/webhooks) to track connection status: * `task-status-updated` with `status: done` — task completed successfully * `task-status-updated` with error statuses — connection failed (see [Task lifecycle](/api-reference/tasks/lifecycle)) See [Webhooks](/api-reference/webhooks) for the full event reference. *** ## Best practices * Always wait for `task-status-updated` webhook with `status: done` before treating a connection as complete * Handle errors with user-friendly messaging * Store `link_id` and `access_token` for future reference [View best practices guide →](/developers/best-practices/bridge-token) *** ## Next steps Direct Deposit Switch integration for Retail Banking Complete Paycheck Linked Lending setup guide Client-side event types and error codes Widget-only implementation guidelines # Bridge Widget Overview Source: https://docs.truv.com/developers/integration/bridge-widget/overview The client-side widget for secure account connections Widget - income verification Truv Bridge is a drop-in client-side widget that handles the entire account connection flow: employer/bank search, credential entry, multi-factor authentication, and error handling. You embed it in your frontend; Truv manages the UI. Bridge is used in two ways: | Integration | Use case | How Bridge gets a token | | ------------------------------------------------------------------- | ------------------------------------------------------------------------------ | --------------------------------------- | | [Embedded Orders](/developers/integration/embedded-orders/overview) | Income, employment, assets (multi-connection) | Order API returns `bridge_token` | | [Bridge Widget](/developers/integration/bridge-widget/new-user) | Direct Deposit Switch (DDS), Paycheck Linked Lending (PLL) (single connection) | Bridge Token API returns `bridge_token` | *** ## Platform support | Platform | Package | | ---------------- | ----------------------------------------------- | | **Web** | ` ``` *** ## Parameters | Parameter | Required | Description | | ------------- | -------- | ----------------------------------------------------------------------------------------------------- | | `bridgeToken` | Yes | The `bridge_token` value returned by [Create Bridge Token](/api-reference/bridge-token/users_tokens). | | `position` | No | Display mode configuration. Default is `dialog`. See [Set the position](#set-the-position). | *** ## Set the position The `position` parameter controls how Bridge renders on the page. Bridge: Dialog mode vs. Inline mode ### Dialog (default) Bridge opens as a centered overlay and disables page scrolling. ```javascript theme={null} const bridge = TruvBridge.init({ bridgeToken: bridgeToken, position: { type: 'dialog' }, // callbacks... }); ``` ### Inline Bridge embeds inside an existing DOM element. Use this for seamless page layouts. ```javascript theme={null} const container = document.getElementById('bridge-container'); const bridge = TruvBridge.init({ bridgeToken: bridgeToken, position: { type: 'inline', container: container }, // callbacks... }); ``` Inline mode requires the container element to exist in the DOM before calling `TruvBridge.init`. *** ## Close Bridge programmatically Call `bridge.close()` to dismiss the widget from your code. ```javascript theme={null} const bridge = TruvBridge.init({ bridgeToken: bridgeToken, // callbacks... }); // Close the widget after a timeout or user action bridge.close(); ``` ### Close options `bridge.close()` accepts an optional `{ mode }` parameter that controls which frames are dismissed. | `mode` | Behavior | | ----------------- | ------------------------------------------------------------------------------- | | `'all'` (default) | Closes the widget unconditionally. Equivalent to `bridge.close()`. | | `'onlyModal'` | Closes only frames rendered as a modal/dialog. Inline frames are left in place. | ```javascript theme={null} bridge.close(); // closes everything bridge.close({ mode: 'all' }); // same as bridge.close() bridge.close({ mode: 'onlyModal' }); // dismisses modal layers only ``` Behavior matrix:
isOrder position.type mode: 'all' mode: 'onlyModal'
false dialog Closes the modal Bridge Closes the modal Bridge
false inline Removes the inline Bridge from the page **No-op**
true dialog Closes the modal order page and the inner connection widget Closes the modal order page and the inner connection widget
true inline Removes the inline order page and closes the inner connection widget **Closes the inner connection widget; leaves the inline order page mounted**
Use `mode: 'onlyModal'` when your app needs to display its own modal (for example, a session-timeout dialog) on top of an inline Embedded Order. Without dismissing the inner connection widget first, your dialog would be unreachable behind it. *** ## Callbacks | Callback | When it fires | | ----------- | --------------------------------------- | | `onSuccess` | User successfully connected an account | | `onLoad` | Bridge widget finished loading | | `onClose` | User closed the widget | | `onEvent` | Any interaction event, including errors | Errors surface through `onEvent` with `type=ERROR` and an [`ErrorData`](/developers/sdks/bridge-events#errordata) payload — there is no separate `onError` callback. See [Bridge events](/developers/sdks/bridge-events) for the full list of event types and payloads. *** ## Customize the widget Customize Bridge appearance through [Customization Templates](/developers/customization) in the Dashboard: company branding, search experience, success pages, document upload settings, and privacy agreements. *** ## Next steps Multi-connection verification (VOIE, VOA, VOE) Single-connection flow (DDS, PLL) Bundle income, deposit switch, and PLL in one Bridge session Platform-specific installation guides # Returning User Source: https://docs.truv.com/developers/integration/bridge-widget/returning-user Re-authenticate expired connections and refresh data When a user's session expires or they change credentials, data refresh requests return `login_error` or `mfa_error`. Use Bridge update mode to prompt the user to re-authenticate their existing connection. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant App as Your App participant Bridge as Truv Bridge Server->>API: Data refresh request API-->>Server: login_error / mfa_error Server->>API: Create bridge token (with access_token) API-->>Server: bridge_token Server->>App: Pass bridge_token App->>Bridge: TruvBridge.init() + open() Bridge->>Bridge: User re-authenticates Bridge-->>App: onSuccess API-->>Server: Webhook (task-status-updated, done) Server->>API: Retrieve updated data ``` *** ## When to use | Issue | Description | Refresh status | | ------------------- | ----------------------------------------------- | -------------- | | Changed credentials | User updated their username or password | `login_error` | | MFA required | Session expired, provider requires new MFA code | `mfa_error` | *** ## Re-authenticate \[Server-side] Create a new bridge token using the `access_token` from the original connection. This puts Bridge in update mode. The user re-enters credentials without going through employer search. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/USER_ID/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "product_type": "income", "access_token": "48427a36d43c4d5aa6324bc06c692456" }' ``` ```json theme={null} { "bridge_token": "2f67984a110747d190c39e1022c81837" } ``` ## Re-authenticate with Bridge \[Client-side] ```html theme={null} ``` *** ## Retrieve updated data \[Server-side] After successful re-authentication, retrieve the refreshed data. ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/links/d8a8945ee2b049b193110cfba643f5df/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Accept: application/json' ``` *** ## Next steps Refresh data without re-authentication Understand connection statuses Create bridge tokens Client-side events and error codes # Document Processing Implementation Source: https://docs.truv.com/developers/integration/document-processing Upload, validate, classify, and verify borrower documents through the Truv API and get the same income and employment report as a live payroll connection Verify income and employment from documents your users already have — pay stubs, W-2s, 1099s, and tax returns — by sending them to the Truv API. Truv validates each file, classifies it with AI, extracts the data, and returns the **same income and employment report schema as a live payroll connection**. Use Document Processing as a fallback when a borrower can't connect their payroll provider, or as a standalone way to turn a pile of uploaded files into structured, verified data. Everything on this page is server-side and language-agnostic — you upload Base64-encoded files over JSON and poll or listen for results. This guide covers the **server-side API**, where your backend uploads files and finalizes the collection. It's a separate integration path from [Truv Bridge](/developers/integration/bridge-widget/overview) — the client-side widget where users connect a payroll or bank account directly. Run the [Document Processing demo](/developers/quickstarts-overview#demo-apps) first to watch the full upload → validate → classify → finalize → report flow end to end, then come back here to build it. *** ## Intelligent intake Document Processing handles whatever your users actually have. Instead of forcing them to label each file or upload one document at a time, you collect everything they send and Truv sorts out what counts. * **Upload anything, get feedback up front.** Users submit any mix of supported files — including phone photos. Truv checks each file on upload and reports problems through the `validations` flags and file `status` you poll in [Step 4](#step-4-monitor-validation-and-classification-server-side): an unreadable file returns `is_readable: false`, an oversized one returns `is_viable_size: false`, and its `status` becomes `invalid`. Surface that feedback so a user can retake a blurry photo before they finish, instead of failing verification hours later. * **Truv recognizes what each file is.** Every uploaded file is classified into recognized `documents`, each with a `document_type`. Files that aren't a verification document are classified as `OTHER` and left out of finalization. The user doesn't label anything. * **Proceed as soon as the minimum is met.** Because every document is classified, your app can check the recognized `documents` against your requirement, finalize only the documents that matter, and let the user continue once it's satisfied. **Example — SNAP income verification.** A requirement of two recent pay stubs is met even if the applicant uploads five files. Truv recognizes the two pay stubs among them; you finalize those two `document_id`s and let the applicant proceed, ignoring the rest. *** ## How document processing works Document Processing is a **collection-based** workflow. You group a user's files into a collection, Truv recognizes what each file is, and you finalize the documents you want into a report. | Object | What it is | | ----------------------- | -------------------------------------------------------------------------------------------------------------- | | **Collection** | The container for one or more users' uploaded files. Created once, then reused for every call. | | **Uploaded file** | A raw file you sent (`is_valid`, `is_readable`, size, type checks). One file can contain several documents. | | **Recognized document** | An AI-classified document found inside a file — a `PAYSTUB`, a `W2`, a page range, and the user it belongs to. | | **Link** | The result of finalizing documents. Processed asynchronously into the standard income/employment report. | The lifecycle is always the same: **create a collection → monitor validation and classification → finalize → retrieve the report.** The steps below walk through each call. *** ## Step 1: Identify or create a user \[Server-side] Retrieve an existing `user_id` or create a new user. If AIM Check will be used, ensure at least the last 4 digits of the SSN are included during user creation. **Find an existing user:** ```bash theme={null} curl -X GET https://prod.truv.com/v1/users/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" ``` **Or create a new user:** ```bash theme={null} curl -X POST https://prod.truv.com/v1/users/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "external_user_id": "your-internal-id", "first_name": "John", "last_name": "Doe", "ssn": "1234" }' ``` Save the returned `id`. You'll need it in subsequent steps. *** ## Step 2: Create a document collection \[Server-side] Initialize the collection and upload documents in a single call. Each file is Base64-encoded and queued for validation and AI classification automatically. ```bash theme={null} curl -X POST https://prod.truv.com/v1/documents/collections/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "documents": [ { "mime_type": "application/pdf", "filename": "most-recent-paystub.pdf", "content": "{{base64_encoded_file}}", "user_id": "{{user_id}}" }, { "mime_type": "image/jpeg", "filename": "prior-paystub-photo.jpg", "content": "{{base64_encoded_file}}", "user_id": "{{user_id}}" } ] }' ``` The response includes a `collection_id`. Save this for all subsequent calls. ### Accepted formats and limits Users rarely have a clean PDF. Truv accepts photos taken on a phone alongside scanned documents: | Constraint | Value | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | File formats (`mime_type`) | `application/pdf`, `image/jpeg`, `image/png`, `image/tiff`, `image/webp`, `image/x-ms-bmp`, `image/heic`, `image/heif` | | File size | 1 KB – 10 MB per file | | Files per request | Up to 10 | A single file can hold more than one document — a multi-page PDF of two pay stubs and a W-2 is split into three recognized documents automatically. ### Assign documents to users Each document can be tied to a user with either `user_id` (Truv ID) or `external_user_id` (your system's ID) — never both on the same document. To create or update users in the same call, pass a `users` array; Truv can also match documents to those users by name. ```bash theme={null} curl -X POST https://prod.truv.com/v1/documents/collections/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "users": [ { "external_user_id": "case-12345", "full_name": "John Doe", "ssn": "1234" } ], "documents": [ { "mime_type": "application/pdf", "filename": "household-docs.pdf", "content": "{{base64_encoded_file}}", "external_user_id": "case-12345" } ] }' ``` *** ## Step 3: Add files incrementally (Optional) \[Server-side] For save-and-resume workflows, add up to 10 more files to an existing collection: ```bash theme={null} curl -X POST https://prod.truv.com/v1/documents/collections/{collection_id}/upload/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "documents": [ { "mime_type": "application/pdf", "filename": "w2-2023.pdf", "content": "{{base64_encoded_file}}", "user_id": "{{user_id}}" } ] }' ``` *** ## Step 4: Monitor validation and classification \[Server-side] Document processing is asynchronous. Poll the collection until every uploaded file reaches a terminal `status`. ```bash theme={null} curl -X GET https://prod.truv.com/v1/documents/collections/{collection_id}/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" ``` The response has two sections. **`uploaded_files`** — file-level validation. Each file carries a `validations` object: | Field | Meaning | | ------------------- | ------------------------------------------------- | | `is_valid` | Overall validation status | | `is_unique` | Not a duplicate of another file in the collection | | `is_readable` | File can be opened and parsed | | `is_accessible` | File is not password-protected | | `is_viable_size` | File is within the 1 KB – 10 MB range | | `is_supported_type` | MIME type is on the accepted list | A file's `status` moves through these values: | Status | Meaning | | --------------------------------------- | -------------------------------------------------------- | | `pending` / `validating` / `processing` | Still in flight — keep polling | | `validated` | Passed validation, classification in progress | | `successful` | Validated and classified — ready to finalize | | `invalid` | Failed one or more validation checks (see `validations`) | | `duplicate` | Matches a file already in the collection | | `failed` | Could not be processed | **`documents`** — AI-recognized records, each with a `document_type` (and `document_subtype` where relevant), the borrower's name, page range, and the user it's matched to. A recognized document's `status` is `successful`, `failed`, or `rejected`. **Example response:** ```json theme={null} { "collection_id": "f1f63754e72a44b4805a4d16380cd833", "uploaded_files": [ { "file_id": "9efadd7fb43c4598b02fe79bd7e31fd7", "filename": "most-recent-paystub.pdf", "mime_type": "application/pdf", "validations": { "is_valid": true, "is_unique": true, "is_readable": true, "is_accessible": true, "is_viable_size": true, "is_supported_type": true }, "status": "successful", "user_id": "c87e695081704310b15d59ee1640b1aa" } ], "documents": [ { "document_id": "b1091a2ddc5d428c9c8af66dbc8b0556", "file_id": "9efadd7fb43c4598b02fe79bd7e31fd7", "document_type": "PAYSTUB", "document_subtype": null, "status": "successful", "first_name": "John", "last_name": "Doe", "start_page": 1, "end_page": 1 } ] } ``` ### How duplicate detection works Truv flags duplicates by **file content, not file name**. A file is marked `is_unique: false` with `status: "duplicate"` when its content matches another file already in the same collection. * **Identical content, different file names** — flagged as duplicates. * **Same file name, different content** — both treated as unique. * Detection is scoped to a **single collection**: Truv compares each file against the others in that collection only. Truv keeps one file as the original (`is_unique: true`) and flags every additional copy as a duplicate. A duplicate is not an error — the file is returned in the normal response, and you choose which documents to process by passing their `document_id`s to [finalize](#step-5-finalize-the-collection-server-side). This is **production** behavior. In the [sandbox](/developers/testing/test-documents), duplicate detection is **file-name-driven** — the test scenario is keyed off the filename and file content is not parsed. Sandbox results for renamed or identically-named files won't match production's content-based matching, so validate duplicate handling against production data. *** ## Step 5: Finalize the collection \[Server-side] Once documents are validated, finalize to trigger report generation. Finalize the whole collection, or pass `document_ids` to select only the documents you need — this is how you proceed with the valid documents and ignore everything else a user uploaded. **Use all recognized documents:** ```bash theme={null} curl -X POST https://prod.truv.com/v1/documents/collections/{collection_id}/finalize/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "product_type": "income" }' ``` **Or select specific documents:** ```bash theme={null} curl -X POST https://prod.truv.com/v1/documents/collections/{collection_id}/finalize/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "document_ids": [ "b1091a2ddc5d428c9c8af66dbc8b0556", "1cbb5f9bb6f345059af491917179c80b" ], "product_type": "income" }' ``` `product_type` is `income` (default) or `employment`. The response groups results by user and returns a `link_id` for each: ```json theme={null} { "users": [ { "id": "21ae68826be042e5ab410e531dc40889", "links": [ { "link_id": "1995e2fc5e374beb955ae81276294815", "status": "new", "documents": [ { "id": "ad568bb5c117439e9c00df738052c653", "document_type": "PAYSTUB", "document_subtype": null }, { "id": "769014511ed748d0a650a73759d06127", "document_type": "PAYSTUB", "document_subtype": null } ] } ] } ] } ``` Save the `link_id`. *** ## Step 6: Retrieve verified data \[Server-side] Truv processes the Link asynchronously. Wait for the Task to complete before fetching the report. **Recommended: Listen for a webhook** Wait for a `task-status-updated` webhook with `status: done` and the matching `link_id`, then fetch the report. **Alternative: Poll finalization status** ```bash theme={null} curl -X GET https://prod.truv.com/v1/documents/collections/{collection_id}/finalize/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" ``` A Link `status` of `done` means the report is ready. `no_data`, `config_error`, `error`, and `unavailable` are the other terminal states. **Fetch the report:** ```bash theme={null} curl -X GET https://prod.truv.com/v1/links/{link_id}/income/report/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" ``` ```bash theme={null} curl -X GET https://prod.truv.com/v1/links/{link_id}/employment/report/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" ``` The report schema is identical to a live payroll connection. *** ## Supported document types AI classification returns a `document_type` for each recognized document. Income and employment documents drive verification reports; the remaining types are recognized for routing and identity workflows. | `document_type` | Description | | ------------------------ | -------------------------------------------------- | | `PAYSTUB` | Pay statements / pay stubs | | `W2` | W-2 wage and tax statements | | `F1099` | 1099 forms (see subtypes below) | | `F1040` | Individual income tax return | | `BANK_STATEMENT` | Bank statements | | `DRIVER_LICENSE` | Driver's licenses | | `PASSPORT` | Passports | | `GREEN_CARD` | Permanent resident cards | | `UTILITY_BILL` | Utility bills | | `LEASE_AGREEMENT` | Lease agreements | | `INSURANCE_HOME_POLICY` | Home insurance policies | | `INSURANCE_AUTO_POLICY` | Auto insurance policies | | `LETTER_OF_VERIFICATION` | Letters of verification | | `VOLUNTEER_LETTER` | Volunteer / community service letters | | `OTHER` | Recognized file that isn't a verification document | ### Document subtypes When Truv recognizes a more specific variant, the recognized document also carries a `document_subtype`: | `document_subtype` | Description | | ------------------ | -------------------------------------------- | | `F1099_MISC` | 1099-MISC — miscellaneous income | | `F1099_NEC` | 1099-NEC — nonemployee compensation | | `F1099_DIV` | 1099-DIV — dividends and distributions | | `F1099_INT` | 1099-INT — interest income | | `F1099_G` | 1099-G — government payments | | `F1099_R` | 1099-R — retirement distributions | | `F_SSA1099` | SSA-1099 — Social Security benefit statement | | `VOL_TRANSCRIPT` | Volunteer transcript | | `VOL_HOURS_LOG` | Volunteer hours log | For sandbox testing, use the [test documents](/developers/testing/test-documents) — the sandbox uses file names to determine results rather than actual file contents. *** ## Detect suspicious documents Truv runs fraud detection on every document and may set `is_suspicious: true` on the report while still returning results, or fail the document outright for high-confidence fraud. See [Fraud and Manual Review](/developers/fraud-and-manual-review) for how to handle flagged and failed documents. *** ## API Reference Initialize a document collection Add files to an existing collection Check validation and AI classification status Trigger report generation *** ## Next steps Sample PDFs for sandbox testing Interpret income and employment data from reports Set up notifications for processing completion Upload pay stubs, W-2s, and tax returns. See structured data extraction in action. # Add Employer Source: https://docs.truv.com/developers/integration/embedded-orders/add-employer Add a new employer to an existing order after it has been created Add a new employer to an existing order when additional employment connections are needed after the order was originally created. The order must not be expired or canceled. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant Bridge as Truv Bridge Server->>API: Add employer (POST /v1/orders/{id}/employers/) API-->>Server: New employer added to order API->>Bridge: User receives notification Bridge->>Bridge: User connects new employer API-->>Server: Webhook (task-status-updated, done) ``` *** ## When to use | Scenario | Example | | ------------------- | ---------------------------------------------------------------- | | Missing employer | User disclosed an additional employer after initial verification | | Seasonal employment | User has a second job that wasn't initially included | *** ## Add an employer \[Server-side] Send a `POST` request to the order's `/employers/` endpoint with the employer details. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/employers/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "company_name": "Facebook Demo", "company_domain": "facebook.com", "start_date": "2019-08-24", "company_address": { "street": "1 Hacker Way", "city": "Menlo Park", "state": "CA", "zip": "94025" } }' ``` ### Request fields | Field | Type | Required | Description | | ----------------- | ------ | -------- | ------------------------------------------------------ | | `company_name` | string | No | Employer name | | `company_domain` | string | No | Company website domain | | `start_date` | date | No | Job start date (YYYY-MM-DD) | | `end_date` | date | No | Job end date (YYYY-MM-DD) | | `suborder_number` | string | No | Your external ID for tracking | | `company_address` | object | No | Employer address with `street`, `city`, `state`, `zip` | The order must be in an active state, not expired or canceled. Check the order status before adding employers. *** ## What happens next After adding the employer, Truv extends the order to include the new employer. The user receives a notification (if configured) to connect their additional employer through Bridge. Listen for `task-status-updated` webhooks to know when the new employer's data is ready. *** ## Next steps Pull updated data without user re-authentication Re-engage users who didn't finish verification Let users review and confirm retrieved data # Data Refresh Source: https://docs.truv.com/developers/integration/embedded-orders/data-refresh Refresh verification data from a completed order without requiring the user to reconnect Create a data refresh order to pull updated income, employment, or asset data from an existing order's connections. The user does not need to re-authenticate. Truv reuses the existing account links. Data refresh works only when the original account connections are still active. If a connection has expired or the user changed their credentials, use [Bridge Update Mode](/developers/integration/bridge-widget/returning-user) to re-authenticate. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API Server->>API: Create refresh order (POST /v1/orders/{id}/) API-->>Server: New order_id Note over API: Truv pulls fresh data from existing connections API-->>Server: Webhook (task-status-updated, done) Server->>API: Retrieve refreshed order (GET /v1/orders/{new_id}/) API-->>Server: Updated employer data, reports ``` *** ## Refresh vs new order | | Data Refresh | New Order | | --------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | | **User action** | None. Truv reuses existing connections. | User must reconnect through Bridge | | **When to use** | Data is stale but connections are still active | Original connections expired, credentials changed, or new employer | | **Limits** | 3 refreshes per access\_token per 24 hours; 5 re-verifications within 90 days for GSE | No limit | | **Cost** | Free for GSE orders (up to 5 within 90 days) | Standard pricing | | **MFA** | Fails if provider requires MFA. User must reconnect. | User handles MFA during connection | *** ## When to use | Scenario | Example | | ----------------- | -------------------------------------------------------- | | Stale data | Original verification is older than your policy window | | Updated pay stubs | Need the most recent pay period before closing | | Re-verification | Underwriting requires a fresh pull before final approval | | Monitoring | Periodic income checks on active loans | *** ## Create a data refresh order \[Server-side] Send a `POST` request to the original order's endpoint. Specify which `products` to refresh and optionally which `employers` or `financial_accounts` to include. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"] }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["assets"] }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "employers": [ { "id": "ad9f14440d624ec3b0f66e81e44518c7" } ] }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["employment"] }' ``` ### Request fields | Field | Type | Description | | -------------------- | ----- | --------------------------------------------------------------------------------------------------------------- | | `products` | array | Product to refresh: `income`, `employment`, `assets`, `insurance`, or `transactions`. One product per request. | | `employers` | array | Employers to include. Each object takes `id` or `suborder_number` from the original order. Omit to refresh all. | | `financial_accounts` | array | Financial accounts to include. Each object takes `id` or `suborder_number`. Omit to refresh all. | For `income` type orders, the refresh can request `income` or `employment` products. For `employment` type orders, the refresh can only request `employment`. The refresh creates a **new order** with a new `id`. Use this new order ID for all subsequent operations — the original order ID is not updated. If you pass an `order_number` when creating the original order, it persists through to the refresh order. Use this to correlate refresh orders with your internal tracking system. *** ## Handle the response Listen for the `order-status-updated` webhook to know when the refreshed data is ready. ```json theme={null} { "webhook_id": "17a80437ce23411dbfd656694d19a8c6", "event_type": "order-status-updated", "event_created_at": "2024-07-11T21:43:08.073930Z", "order_id": "NEW_ORDER_ID", "status": "completed", "updated_at": "2024-07-11T21:43:08.075540+00:00" } ``` Retrieve the refreshed data using the new order ID. ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/orders/NEW_ORDER_ID/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Accept: application/json' ``` If the refresh fails (e.g., expired session), Truv fires an `order-refresh-failed` [webhook event](/api-reference/webhooks). Handle this by prompting the user to re-authenticate through Bridge. See [Order object](/api-reference/orders/object) for the full response schema. *** ## Handle failed refreshes Refreshes can fail when the user's credentials have changed or the provider requires MFA. Check the task status in the webhook payload. | Status | Cause | Resolution | | ------------- | -------------------------------------------------------------- | ------------------------ | | `login_error` | User changed their password | Re-authenticate the user | | `mfa_error` | Provider requires MFA that can't be completed without the user | Re-authenticate the user | Other common failure causes: * **OAuth token expired (\~180 days)**: Financial institutions using OAuth typically expire tokens after \~180 days. The user must reconnect. * **Provider unavailable**: The payroll provider may be temporarily down. Retry after some time. * **Account locked**: Too many failed attempts may have locked the user's account at the provider. The user needs to unlock it with the provider first. ### Re-authenticate with Bridge Update Mode Create a new bridge token using the `access_token` from the original connection, then initialize Truv Bridge for the user to re-authenticate. ```bash theme={null} curl -X POST https://prod.truv.com/v1/users/{user_id}/tokens/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "product_type": "income", "access_token": "ACCESS_TOKEN_FROM_ORIGINAL_CONNECTION" }' ``` Pass the new `bridge_token` to your frontend and re-initialize Bridge. The user logs in again, and fresh data becomes available through the existing Link. Sessions are determined by the payroll provider. Data refreshes succeed automatically during active sessions. If the session has expired, re-authentication is required. See [Bridge Update Mode](/developers/integration/bridge-widget/returning-user) for the full returning-user flow. *** ## Next steps Receive notifications when refreshed data is ready Understand connection status transitions Re-engage users who didn't finish verification # Deeplinking Source: https://docs.truv.com/developers/integration/embedded-orders/deeplinking Pre-fill account information (employer, bank, etc.) to skip search steps and maximize conversion Deeplinking lets you pre-fill account information (employer, bank, or other provider) when creating an order, bypassing the search screens entirely. When you already know the user's provider, deeplinking sends them directly to the login screen. **Deeplinking is one of the highest-impact conversion improvements you can make.** Removing the search step eliminates friction and reduces drop-off. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant Bridge as Truv Bridge Server->>API: Search company mapping (GET /v1/company-mappings-search/) API-->>Server: company_mapping_id Server->>API: Create order with company_mapping_id API-->>Server: bridge_token Note over Bridge: User skips search screens Bridge->>Bridge: User lands on login page ``` *** ## How it works Truv Bridge normally shows two search screens before login: 1. **Employer selection**: user searches for their employer by name 2. **Provider selection**: user selects their payroll provider (e.g. ADP, Workday) With deeplinking, you provide this information when creating the order and users land directly on the credential entry screen. *** ## Deeplink by employer Use this when you know the user's employer name. Truv maps the employer to the correct payroll provider automatically. ### Find the company mapping Call the [Search companies endpoint](/api-reference/companies/company_mapping) with the employer name from your application. ```bash theme={null} curl --request GET \ --url 'https://prod.truv.com/v1/company-mappings-search/?query=Facebook' \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` ```json theme={null} [ { "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456", "name": "Facebook", // ... } ] ``` ### Create an order with the mapping Pass the `company_mapping_id` in the `employers` array when creating the order. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "employers": [ { "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456" } ] }' ``` The user skips the employer search screen and lands directly on the provider login page. ### Alternative: Deeplink by company name If you don't have a `company_mapping_id` but have the employer name on hand, pass `company_name` instead. Truv will attempt to match the employer automatically. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "employers": [ { "company_name": "facebook" } ] }' ``` This is a best-effort match. For the highest accuracy, use `company_mapping_id` from the [company search endpoint](/api-reference/companies/company_autocomplete_search). *** ## Deeplink by provider Use this when you know the specific payroll provider (e.g. ADP, Workday, Gusto) but not the specific employer. Pass the `provider_id` in the `employers` array. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "employers": [ { "provider_id": "adp" } ] }' ``` All providers from the [List all data providers endpoint](/api-reference/data-providers/providers-list) are supported as deeplink targets. *** ## Testing deeplinking Use the [Truv Dashboard Emulator](https://dashboard.truv.com/app/emulator) to test deeplinks before deploying. Enter a `company_mapping_id` or `provider_id` in the emulator settings to verify the user lands on the correct screen. *** ## Best practices for conversion If your application collects employer name (nearly every mortgage application does), always resolve and pass `company_mapping_id`. Each extra screen costs conversion. Call the company mapping API when the borrower enters their employer name in your form. Don't wait until they open Truv Bridge. If a company mapping isn't found, fall back to launching Bridge without a deeplink. The user can still search and connect manually. Company mappings don't change frequently. Cache results for common employers to avoid redundant API calls. *** ## Next steps Full embedded orders implementation guide Find `company_mapping_id` by employer name Deeplinking for Bridge widget flows Create orders with employer pre-fill # Display Modes Source: https://docs.truv.com/developers/integration/embedded-orders/display-modes Control how the embedded order appears: as an overlay dialog or inline within your page Set the order's display mode with the `position` property when you initialize Truv Bridge. Bridge in dialog mode versus inline mode ## Dialog (default) Bridge opens as a centered overlay and disables page scrolling. ```javascript theme={null} var bridge = TruvBridge.init({ isOrder: true, bridgeToken: bridgeToken }); ``` ## Inline Bridge embeds inside an existing DOM element. Use this for seamless page layouts. ```javascript theme={null} var bridge = TruvBridge.init({ isOrder: true, bridgeToken: bridgeToken, position: { type: 'inline', container: document.querySelector('#order-container') } }); ``` When using inline mode: 1. The container element must remain stable. Do not unmount or reparent it while the bridge is open. 2. Manually close the bridge before removing the container (e.g., on SPA navigation). 3. Only one bridge instance can be open at a time. Both behaviors are account-level settings. New accounts default to the simpler setup; existing accounts may keep the previous one. | Behavior | Values | | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Frame sizing** | • [**Automatic height**](#frame-sizing) — default for new accounts
• [**Fixed height**](#alternative-frame-sizing-fixed-height) — use only if automatic height isn't suitable (was default until June 18, 2026) | | [**Suborder launch**](#suborder-launch) | • **As a modal** — default for new accounts
• **Inside the inline frame** — deprecated as of June 18, 2026; was the previous default | To change either behavior, contact your Truv representative or [support@truv.com](mailto:support@truv.com) — your `TruvBridge.init` call stays the same. ### Frame sizing By default the inline frame height follows its content. We recommend automatic height: it takes the least effort to embed correctly. Set only `width` on the container and let the frame grow to fit. The page keeps a single scrollbar, with no double-scroll. Inline order page embedded in a host page, sized to its content, with a single page scrollbar The minimum supported width is **320** pixels. Provide a wider container whenever possible for a comfortable experience. Don't set `height` on the container. The frame sizes itself to its content — a fixed height would clip or stretch it. With automatic height, the frame expands to its full content height and the page provides the scroll. Make sure the parent elements scroll correctly — don't clip the container or trap the scroll inside it. ### Alternative frame sizing: fixed height With fixed height, you set an explicit `height` on the container and the frame doesn't resize itself. This was the previous default; new accounts use automatic height instead. Use fixed height only if automatic height isn't suitable for your layout. Fixed-height inline frame sized to the viewport, shown on a large screen and a tall, narrow viewport Fixed height needs a few conditions to keep the UI usable: * Set an explicit `height` on the container, ideally relative to the viewport so the frame adapts to the screen. * Don't place the container inside a scrollable parent — this creates a double-scroll. Test the frame across the full range of viewports — narrow and wide, short and tall. The minimum supported size is **320×240** pixels. ### Suborder launch When the applicant starts a verification — a suborder — Bridge opens as a modal on top of the page instead of inside the inline frame. The order page stays inline in your container. The modal gives Bridge more room and avoids scroll and virtual-keyboard issues on mobile. Opening Bridge inside the inline frame (legacy suborder mode) was the previous default and is deprecated as of June 18, 2026. Comparison: Bridge sign-in as a modal on top of the inline order page, versus the legacy suborder mode with sign-in docked inside the inline frame # Follow-up Source: https://docs.truv.com/developers/integration/embedded-orders/follow-up Let Truv handle email and SMS reminders when users leave without finishing verification When a user leaves your application without finishing verification, Truv can automatically send email and SMS reminders to bring them back. Toggle notifications on and off using the order's `notification_settings`. Truv handles the messaging. ```mermaid theme={null} sequenceDiagram participant App as Your App participant API as Truv API participant User as User App->>API: Create order (notifications suppressed) App->>User: User starts verification in-app User-->>App: User leaves without finishing App->>API: Update order (enable notifications) API->>User: Truv sends email/SMS reminders User->>API: User clicks link, completes verification API-->>App: Webhook (order-status-updated) ``` *** ## How it works 1. Create the order with `suppress_user_notifications: true` while the user is in your app 2. When the user leaves without finishing, update the order to enable notifications 3. Truv sends email and SMS reminders on your behalf 4. When the user returns and completes verification, you receive a webhook *** ## Suppress notifications while user is in-app While the user is active in your application, suppress Truv notifications. Your app controls the experience. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "4155554193", "notification_settings": { "suppress_user_notifications": true } }' ``` *** ## Enable notifications when user leaves When the user leaves your app without completing verification, update the order to turn on notifications. Truv takes over and sends email/SMS reminders to bring them back. ```bash theme={null} curl --request PATCH \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "notification_settings": { "suppress_user_notifications": false } }' ``` You can also delay the first notification instead of sending it immediately. ```bash theme={null} curl --request PATCH \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "notification_settings": { "suppress_user_notifications": false, "first_notification_delay_hours": 24 } }' ``` *** ## Configure notifications | Field | Type | Default | Description | | -------------------------------- | ------- | ------- | -------------------------------------------------------- | | `suppress_user_notifications` | boolean | `false` | Suppress all Truv email/SMS notifications for this order | | `first_notification_delay_hours` | integer | `0` | Hours to delay the first notification after enabling | *** ## Reminders Truv automatically sends an initial notification and up to three reminders via email and/or SMS. Each reminder includes the original order link. Reminders are distributed evenly from order creation until expiration. Once an order reaches a terminal status (completed, canceled, expired), reminders stop. SMS reminders require account-level enablement. Contact [support@truv.com](mailto:support@truv.com) to activate. SMS reminders are only sent between 10am–6pm ET. | Link Expiration | Order Lifespan | Initial Notification | Reminders | | --------------- | -------------------- | -------------------- | ------------------------------------------------------ | | 1 day | 24 hours + weekends | 30 seconds | 1st: 6 hours
2nd: 16 hours
3rd: 22 hours | | 2 days | 48 hours + weekends | 30 seconds | 1st: 6 hours
2nd: 24 hours | | 3 days | 72 hours + weekends | 30 seconds | 1st: 24 hours
2nd: 48 hours
3rd: 66 hours | | 1 week | 168 hours + weekends | 30 seconds | 1st: 24 hours
2nd: 72 hours
3rd: 120 hours | | 2 weeks | 336 hours + weekends | 30 seconds | 1st: 96 hours
2nd: 192 hours
3rd: 288 hours | | 3 weeks | 504 hours + weekends | 30 seconds | 1st: 264 hours
2nd: 384 hours
3rd: 456 hours | | 4 weeks | 672 hours + weekends | 30 seconds | 1st: 312 hours
2nd: 432 hours
3rd: 624 hours | Order expiration periods exclude weekends, but reminders continue being sent during weekends. Customize expiration times and reminder schedules in the [Truv Dashboard](https://dashboard.truv.com). Combining email and SMS improves completion rates. High-intent borrowers complete over 50% of verifications within 2 hours. *** ## Next steps Pull updated data without user re-authentication Let users review and confirm retrieved data Receive notifications when order status changes # Embedded Orders Source: https://docs.truv.com/developers/integration/embedded-orders/overview Create an order when you don't know the user's employer or provider Start here when you have a new user and don't know their employer, payroll provider, or bank upfront. Truv Bridge presents a search screen where the user finds and connects their accounts. Embedded order and widget Embedded Orders support the following data source types: | Data source | Products | Use case | | ------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------- | | **Payroll** | `income`, `employment` | Income verification, employment history. **Note:** `income` auto-includes employment data. You don't need to request both. | | **Bank** | `transactions`, `assets` | Asset verification, transaction history | | **Documents** | `income`, `employment` | Document upload verification (pay stubs, W-2s, tax forms) | | **Tax** | `income` | Tax return verification | If you already know the user's employer or provider, use [deeplinking](/developers/integration/embedded-orders/deeplinking) to skip the search screen and go directly to the login flow. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant Browser as Your App participant Bridge as Truv Bridge Server->>API: 1. Create Order (POST /v1/orders/) API-->>Server: order_id, bridge_token Server->>Browser: 2. Pass bridge_token Browser->>Bridge: 3. Initialize widget (TruvBridge.init) Bridge->>Browser: User searches & connects accounts Bridge-->>Browser: onSuccess / onClose callbacks API-->>Server: 4. Webhook (task-status-updated) Server->>API: 5. Retrieve data (GET /v1/orders/{id}/) API-->>Server: Order with employer data, reports ``` *** ## How it works 1. **Create an order** via API with desired products 2. **User opens the widget** using the bridge token 3. **User connects accounts** (payroll, banks) 4. **Receive data** via webhook notifications 5. **Retrieve results** using the order ID *** ## Implement ### Step 1: Create an order \[Server-side] Create an [Order](/api-reference/orders/object) to link different data providers. The response includes a `bridge_token` to initialize Truv Bridge. ```bash theme={null} curl -X POST https://prod.truv.com/v1/orders/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "products": ["income"], "first_name": "John", "last_name": "Doe" }' ``` ```bash theme={null} curl -X POST https://prod.truv.com/v1/orders/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "products": ["assets"], "first_name": "John", "last_name": "Doe" }' ``` ```bash theme={null} curl -X POST https://prod.truv.com/v1/orders/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" \ -H "Content-Type: application/json" \ -d '{ "products": ["income", "assets"], "first_name": "John", "last_name": "Doe" }' ``` When you include `income` in the products array, employment data is automatically included. You do not need to pass both `income` and `employment`. **Best practice:** Include `email` and `phone` on the order along with `notification_settings` to send a delayed notification if the user doesn't complete verification during the embedded session: ```json theme={null} { "notification_settings": { "suppress_user_notifications": false, "first_notification_delay_hours": 6 } } ``` This gives the user time to finish in-app, then sends a reminder if they haven't completed within 6 hours. The create order endpoint accepts additional fields to customize the verification: | Field | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `employers` | Pre-populate the employer in Bridge so the user doesn't have to search. Pass `company_name` and optionally `company_address`. | | `notification_settings` | Suppress emails/SMS to the user with `suppress_user_notifications: true`, or delay the first notification with `first_notification_delay_hours`. | | `loan` | Attach loan metadata: `loan_number` (required), `originator_name`, `originator_email`, `loan_processor_name`, `loan_processor_email`. | | `external_user_id` | Your internal identifier for the user. | | `order_number` | Your internal reference number for this order. | | `ssn` | Last 4 or full 9 digits. Enables SSN matching on the verification. | | `email` / `phone` | Contact info for sending the order link via email or SMS. | | `template_id` | [Customization template](/developers/customization) to apply. | [Explore the full request schema →](/api-reference/orders/orders_create) Orders can be configured in two modes that control how users interact with pre-populated employers: | Mode | Behavior | Best for | | ---------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------- | | **Open order** | User can skip pre-populated employers and add new ones not on the original order | Flexible flows where users may have changed jobs | | **Closed order** | User must attempt all pre-populated employers. Cannot add new ones. | Strict verification where specific employers are required | Within open orders, two skip behaviors are available: * **Require attempt, then allow skip** — User must try connecting before they can skip * **Allow skip without attempting** — User can skip immediately This is an account-level setting. Contact your Truv representative or [support@truv.com](mailto:support@truv.com) to configure. Extract the `bridge_token` from the response. ```json theme={null} { "id": "39aa1486ccca4bc19cda071ffc1ba392", "order_number": "truv-o-39aa1486", // ... additional order fields "user_id": "b1e24b60b8d84b9da11e13f46a830f41", "bridge_token": "93be103a3ccd4d4fa38af0b1bfcf3be8" // ... full response includes status, timestamps, share_url, and more } ``` ### Step 2: Initialize widget \[Client-side] Load Truv Bridge and pass the `bridge_token` from Step 1. `isOrder: true` is required for Embedded Orders. Initializing without it causes unexpected behavior. ```html theme={null} ``` Wait for the `COMPLETED` event with `source: "order"` before advancing the user in your application. This event fires when the order reaches its final state: all connections succeeded or were skipped. Do **not** use `onSuccess` or `onClose` to advance the user, as the order may still have pending connections. #### Callbacks | Callback | Description | Required | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | | `onLoad` | Bridge finished loading the order page | Optional | | `onSuccess` | User connected all accounts and clicked "I'm done" | Optional | | `onClose` | Bridge closed the order page | Optional | | `onEvent` | Receives events from the order page (`source: "order"`) and the connection widget (`source: "bridge"`). See [Bridge Events](/developers/sdks/bridge-events#callbacks) for all types. | Optional | #### Display modes By default the widget opens as a centered dialog. To embed it inline inside your own container, see [Display Modes](/developers/integration/embedded-orders/display-modes). When the user picks an employer, the connection widget opens as a modal on top of the inline order page. To show your own modal (for example, a session-timeout dialog) without it being hidden behind that widget, call `bridge.close({ mode: 'onlyModal' })`. The inline order page stays mounted; only the modal connection widget is dismissed. See [Close options](/developers/integration/bridge-widget/overview#close-options). ### Step 3: Test in sandbox Test your implementation with sandbox credentials. | Username | Password | Description | | ---------------------- | -------------- | ---------------------------- | | `goodlogin` | `goodpassword` | Full-time current employment | | `hourly.part-time` | `goodpassword` | Hourly part-time worker | | `multiple.employments` | `goodpassword` | Multiple employers | See [Test Credentials](/developers/testing/test-credentials) for all scenarios. ### Step 4: Monitor webhooks \[Server-side] [Webhooks](/api-reference/webhooks) notify you when task and order statuses change. Use `user_id` to match events to a specific order. ```mermaid theme={null} sequenceDiagram participant User participant Bridge as Truv Bridge participant API as Truv API participant Server as Your Server User->>Bridge: Connects account Bridge->>API: Creates task API-->>Server: task-status-updated (login) API-->>Server: task-status-updated (parse) API-->>Server: task-status-updated (done) User->>Bridge: Clicks "I'm done" API-->>Server: order-status-updated (completed) ``` Task-level webhook, fires as each connection progresses. ```json theme={null} { "webhook_id": "17a80437ce23411dbfd656694d19a8c6", "event_type": "task-status-updated", "event_created_at": "2024-07-11T21:43:08.073930Z", "product": "income", "link_id": "d8a8945ee2b049b193110cfba643f5df", "user_id": "adbe707dddee4334bffaeb5866272740", "data_source": "payroll", "task_id": "871fef2e79ea444ea2019c8845305d31", "tracking_info": null, "status": "done", "template_id": null, "updated_at": "2024-07-11T21:43:08.075540+00:00" } ``` Order-level webhook, fires when the user finishes the order. ```json theme={null} { "webhook_id": "0aac461e7b774a38a72fd9c7c0eef8ee", "event_type": "order-status-updated", "event_created_at": "2024-07-11T21:40:48.424610Z", "product": "income", "link_id": "d8a8945ee2b049b193110cfba643f5df", "user_id": "adbe707dddee4334bffaeb5866272740", "data_source": "payroll", "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "4138538", "employer_id": "d7166cffbfef4bd6a9e830cf5508e615", "status": "completed", "template_id": null, "updated_at": "2024-07-11T21:40:48.424655+00:00" } ``` See [Task lifecycle](/api-reference/tasks/lifecycle) for all status transitions. ### Step 5: Retrieve data \[Server-side] Fetch order details using the `order_id`. The response includes employer data, employment history, income statements, and report IDs. ```bash theme={null} curl https://prod.truv.com/v1/orders/{order_id}/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" ``` See [Order object](/api-reference/orders/object) for the full response schema. *** ## Content Security Policy (CSP) If your application uses a Content Security Policy, you must allow these domains for the embedded widget to load and function correctly: | Domain | Purpose | | -------------- | -------------------------- | | `my.truv.com` | Truv Bridge application | | `cdn.truv.com` | Truv Bridge JavaScript SDK | ```text theme={null} Content-Security-Policy: frame-src my.truv.com; script-src cdn.truv.com; ``` Missing CSP configuration is one of the most common causes of the widget failing to load in embedded contexts. If the widget doesn't appear or shows a blank frame, check your CSP settings first. *** ## Demo apps Applicant verifies income, employment, or assets through Bridge in a single session. Applicant returns to complete multiple verification tasks tied to one file. *** ## Next steps Add additional employers to an existing order Pull updated data without user re-authentication Skip employer search for higher conversion # Self-Certification Source: https://docs.truv.com/developers/integration/embedded-orders/self-certification Retrieve user self-certification results for employments and accounts in an order Self-certification allows users to review and confirm (or reject) the employment and account data retrieved during verification. Retrieve the certification results to see whether the user confirmed the data as representative or flagged discrepancies. ```mermaid theme={null} sequenceDiagram participant Bridge as Truv Bridge participant User participant Server as Your Server participant API as Truv API Bridge->>User: Verification data retrieved User->>Bridge: Reviews and certifies data API-->>Server: Webhook (order-status-updated) Server->>API: GET /v1/orders/{id}/certifications/ API-->>Server: Certification results (representative / not_representative) ``` *** ## When to use | Scenario | Example | | ----------------------- | ---------------------------------------------------------------- | | Income verification | Borrower confirms retrieved income matches their actual earnings | | Employment confirmation | Borrower validates employer name, start date, and pay rate | | Asset verification | Borrower reviews account balances and ownership details | | Dispute handling | Borrower flags incorrect or outdated data with a reason | *** ## Retrieve certification results \[Server-side] Send a `GET` request to the order's `/certifications/` endpoint after the user completes their review. ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/certifications/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Accept: application/json' ``` ### Response structure Each result contains a `decision` and either an `employment` or `account` object. ```json theme={null} { "results": [ { "decision": "representative", "employment": { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "start_date": "2018-01-01", "pay_rate": "25.50", "pay_date": "2023-12-15", "company": { "name": "Facebook" } } }, { "decision": "not_representative", "rejection_reason": "incorrect_amount", "rejection_comment": "Balance is outdated", "account": { "id": "bc917458a3da4b2c8cc8282aa1707aaa", "type": "CHECKING", "mask": "1234", "routing_number": "021000021", "balance": "1500.25", "owners": [ { "full_name": "John Doe" } ] } } ] } ``` *** ## Decision values | Decision | Meaning | | -------------------- | --------------------------------------- | | `representative` | Borrower confirmed the data is accurate | | `not_representative` | Borrower flagged the data as inaccurate | ### Rejection reasons When the decision is `not_representative`, the result includes a `rejection_reason`: | Reason | Description | | ----------------------------- | ------------------------------------------------------------- | | `employment_no_longer_active` | Borrower is no longer employed at this company | | `incorrect_amount` | Income or balance amount is wrong | | `duplicate_entry` | Employer or account appears more than once | | `outdated_information` | Data is stale or no longer current | | `other` | Borrower provided a custom explanation in `rejection_comment` | *** ## Next steps Re-engage users who didn't finish verification Full embedded orders implementation guide # Add Employer Source: https://docs.truv.com/developers/integration/hosted-orders/add-employer Add a new employer to an existing order after it has been created Add a new employer to an existing hosted order when additional employment connections are needed after the order was originally created. The order must not be expired or canceled. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant User as User Server->>API: Add employer (POST /v1/orders/{id}/employers/) API-->>Server: New employer added to order API->>User: Email/SMS notification User->>API: User connects new employer API-->>Server: Webhook (task-status-updated, done) ``` *** ## When to use | Scenario | Example | | ------------------- | ---------------------------------------------------------------- | | Missing employer | User disclosed an additional employer after initial verification | | Seasonal employment | User has a second job that wasn't initially included | *** ## Add an employer \[Server-side] Send a `POST` request to the order's `/employers/` endpoint with the employer details. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/employers/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "company_name": "Facebook Demo", "company_domain": "facebook.com", "start_date": "2019-08-24", "company_address": { "street": "1 Hacker Way", "city": "Menlo Park", "state": "CA", "zip": "94025" } }' ``` ### Request fields | Field | Type | Required | Description | | ----------------- | ------ | -------- | ------------------------------------------------------ | | `company_name` | string | No | Employer name | | `company_domain` | string | No | Company website domain | | `start_date` | date | No | Job start date (YYYY-MM-DD) | | `end_date` | date | No | Job end date (YYYY-MM-DD) | | `suborder_number` | string | No | Your external ID for tracking | | `company_address` | object | No | Employer address with `street`, `city`, `state`, `zip` | The order must be in an active state, not expired or canceled. Check the order status before adding employers. *** ## What happens next After adding the employer, Truv extends the order to include the new employer. The user receives a notification to connect their additional employer through the hosted verification page. Listen for `task-status-updated` webhooks to know when the new employer's data is ready. *** ## Next steps Pull updated data without user re-authentication Create a hosted order from scratch Pre-fill employer info to skip search # Data Refresh Source: https://docs.truv.com/developers/integration/hosted-orders/data-refresh Refresh verification data from a completed order without requiring the user to reconnect Create a data refresh order to pull updated income, employment, or asset data from an existing order's connections. The user does not need to re-authenticate. Truv reuses the existing account links. Data refresh works only when the original account connections are still active. If a connection has expired or the user changed their credentials, use [Bridge Update Mode](/developers/integration/bridge-widget/returning-user) to re-authenticate. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API Server->>API: Create refresh order (POST /v1/orders/{id}/) API-->>Server: New order_id Note over API: Truv pulls fresh data from existing connections API-->>Server: Webhook (task-status-updated, done) Server->>API: Retrieve refreshed order (GET /v1/orders/{new_id}/) API-->>Server: Updated employer data, reports ``` *** ## When to use | Scenario | Example | | ----------------- | -------------------------------------------------------- | | Stale data | Original verification is older than your policy window | | Updated pay stubs | Need the most recent pay period before closing | | Re-verification | Underwriting requires a fresh pull before final approval | | Monitoring | Periodic income checks on active loans | *** ## Create a data refresh order \[Server-side] Send a `POST` request to the original order's endpoint. Specify which `products` to refresh and optionally which `employers` or `financial_accounts` to include. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"] }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["assets"] }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "employers": [ { "id": "ad9f14440d624ec3b0f66e81e44518c7" } ] }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["employment"] }' ``` ### Request fields | Field | Type | Description | | -------------------- | ----- | --------------------------------------------------------------------------------------------------------------- | | `products` | array | Product to refresh: `income`, `employment`, `assets`, `insurance`, or `transactions`. One product per request. | | `employers` | array | Employers to include. Each object takes `id` or `suborder_number` from the original order. Omit to refresh all. | | `financial_accounts` | array | Financial accounts to include. Each object takes `id` or `suborder_number`. Omit to refresh all. | For `income` type orders, the refresh can request `income` or `employment` products. For `employment` type orders, the refresh can only request `employment`. The refresh creates a **new order** with a new `id`. Use this new order ID for all subsequent operations — the original order ID is not updated. If you pass an `order_number` when creating the original order, it persists through to the refresh order. Use this to correlate refresh orders with your internal tracking system. *** ## Handle the response Listen for the `order-status-updated` webhook to know when the refreshed data is ready. ```json theme={null} { "webhook_id": "17a80437ce23411dbfd656694d19a8c6", "event_type": "order-status-updated", "order_id": "NEW_ORDER_ID", "status": "completed", "updated_at": "2024-07-11T21:43:08.075540+00:00" } ``` Retrieve the refreshed data using the new order ID. ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/orders/NEW_ORDER_ID/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Accept: application/json' ``` If the refresh fails (e.g., expired session), Truv fires an `order-refresh-failed` [webhook event](/api-reference/webhooks). Handle this by sending the user a new verification link. See [Order object](/api-reference/orders/object) for the full response schema. *** ## Next steps Receive notifications when refreshed data is ready Understand connection status transitions # Deeplinking Source: https://docs.truv.com/developers/integration/hosted-orders/deeplinking Pre-fill account information (employer, bank, etc.) to skip search steps and maximize conversion Pre-fill account information (employer, bank, or other provider) when creating a hosted order to bypass the search screens. When the user clicks the verification link, they land directly on the login screen. **Deeplinking is one of the highest-impact conversion improvements you can make.** Removing the search step eliminates friction and reduces drop-off. ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant User as User Server->>API: Search company mapping (GET /v1/company-mappings-search/) API-->>Server: company_mapping_id Server->>API: Create order with company_mapping_id API-->>Server: order_id, share_url API->>User: Email/SMS with verification link Note over User: User skips search screens User->>User: Lands directly on login page ``` *** ## How it works Truv's hosted verification page normally shows two search screens before login: 1. **Employer selection**: user searches for their employer by name 2. **Provider selection**: user selects their payroll provider (e.g. ADP, Workday) With deeplinking, you provide this information when creating the order and users land directly on the credential entry screen. *** ## Deeplink by employer Use this when you know the user's employer name. Truv maps the employer to the correct payroll provider automatically. ### Find the company mapping Call the [Search companies endpoint](/api-reference/companies/company_mapping) with the employer name from your application. ```bash theme={null} curl --request GET \ --url 'https://prod.truv.com/v1/company-mappings-search/?query=Facebook' \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` ```json theme={null} [ { "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456", "name": "Facebook", // ... } ] ``` ### Create an order with the mapping Pass the `company_mapping_id` in the `employers` array when creating the order. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "employers": [ { "company_mapping_id": "48427a36d43c4d5aa6324bc06c692456" } ] }' ``` The user skips the employer search screen and lands directly on the provider login page. ### Alternative: Deeplink by company name If you don't have a `company_mapping_id` but have the employer name on hand, pass `company_name` instead. Truv will attempt to match the employer automatically. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "employers": [ { "company_name": "facebook" } ] }' ``` This is a best-effort match. For the highest accuracy, use `company_mapping_id` from the [company search endpoint](/api-reference/companies/company_autocomplete_search). *** ## Deeplink by provider Use this when you know the specific payroll provider (e.g. ADP, Workday, Gusto) but not the specific employer. Pass the `provider_id` in the `employers` array. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "employers": [ { "provider_id": "adp" } ] }' ``` All providers from the [List all data providers endpoint](/api-reference/data-providers/providers-list) are supported as deeplink targets. *** ## Next steps Create a hosted order from scratch Find `company_mapping_id` by employer name Deeplinking for Bridge widget flows Create orders with employer pre-fill # New User Source: https://docs.truv.com/developers/integration/hosted-orders/new-user Create an order where Truv contacts the user via email or SMS to complete verification Hosted orders let Truv handle user outreach. Create an order with the user's contact information, and Truv sends an email or SMS with a link to complete verification. No app or widget integration required. At least one of `email` or `phone` is required. Truv needs a way to contact the user. Providing both maximizes success rates. | Creation method | Best for | | ------------------- | -------------------------------------------- | | **API** | Programmatic workflows, automated pipelines | | **Dashboard** | Manual order creation, one-off verifications | | **CSV bulk upload** | High-volume batch processing | ```mermaid theme={null} sequenceDiagram participant Server as Your Server participant API as Truv API participant User as User Server->>API: 1. Create Order (POST /v1/orders/) API-->>Server: order_id, share_url API->>User: 2. Email/SMS with verification link User->>API: 3. User clicks link, connects accounts API-->>Server: 4. Webhook (task-status-updated) Server->>API: 5. Retrieve data (GET /v1/orders/{id}/) API-->>Server: Order with employer data, reports ``` *** ## How it works 1. **Create an order** via API with the user's contact information 2. **Truv sends a notification** (email, SMS, or both) with a link to the hosted verification page 3. **User connects accounts** on Truv's hosted page (payroll, banks) 4. **Receive data** via webhook notifications 5. **Retrieve results** using the order ID *** ## Implement ### Step 1: Create an order \[Server-side] Create an [Order](/api-reference/orders/object) with the user's name and contact information. Truv sends the verification link automatically. ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "4155554193", "ssn": "222233333" }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["assets"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "4155554193" }' ``` ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/orders/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Content-Type: application/json' \ --data '{ "products": ["income", "assets"], "first_name": "John", "last_name": "Doe", "email": "john@example.com", "phone": "4155554193", "ssn": "222233333" }' ``` The response includes a `short_share_url`, the hosted verification link to send to the user. ```json theme={null} { "id": "39aa1486ccca4bc19cda071ffc1ba392", "products": ["income"], "first_name": "John", "last_name": "Doe", "user_id": "99dd17074ac94aa9ace2621d657c7610", "bridge_token": "e4100fccdae94691b4414c7306220c06", // ... additional fields "short_share_url": "https://truv.link/abc123", // ... status, timestamps, employers } ``` Specify only the products your use case requires. | Field | Type | Required | Description | | ------------------ | ------ | -------- | ------------------------------------------------------------ | | `products` | array | Yes | Products to request: `income`, `employment`, `assets` | | `first_name` | string | Yes | User's first name | | `last_name` | string | Yes | User's last name | | `email` | string | Yes\* | User's email for notifications | | `phone` | string | No | User's phone for SMS notifications | | `ssn` | string | No | SSN for identity matching (4 or 9 digits) | | `external_user_id` | string | No | Your internal user/application identifier | | `template_id` | string | No | [Customization template](/developers/customization) to apply | If you already know the user's employer, use [deeplinking](/developers/integration/hosted-orders/deeplinking) to skip the search screen. ### Step 2: Test in sandbox Test your implementation with sandbox credentials. | Username | Password | Description | | ---------------------- | -------------- | ---------------------------- | | `goodlogin` | `goodpassword` | Full-time current employment | | `hourly.part-time` | `goodpassword` | Hourly part-time worker | | `multiple.employments` | `goodpassword` | Multiple employers | See [Test Credentials](/developers/testing/test-credentials) for all scenarios. ### Step 3: Monitor webhooks \[Server-side] [Webhooks](/api-reference/webhooks) notify you when task and order statuses change. Use `user_id` to match events to a specific order. ```mermaid theme={null} sequenceDiagram participant User participant API as Truv API participant Server as Your Server User->>API: Connects account via hosted page API-->>Server: task-status-updated (login) API-->>Server: task-status-updated (parse) API-->>Server: task-status-updated (done) User->>API: Clicks "I'm done" API-->>Server: order-status-updated (completed) ``` Task-level webhook, fires as each connection progresses. ```json theme={null} { "webhook_id": "17a80437ce23411dbfd656694d19a8c6", "event_type": "task-status-updated", "event_created_at": "2024-07-11T21:43:08.073930Z", "product": "income", "link_id": "d8a8945ee2b049b193110cfba643f5df", "user_id": "adbe707dddee4334bffaeb5866272740", "data_source": "payroll", "task_id": "871fef2e79ea444ea2019c8845305d31", "tracking_info": null, "status": "done", "template_id": null, "updated_at": "2024-07-11T21:43:08.075540+00:00" } ``` Order-level webhook, fires when the user finishes the order. ```json theme={null} { "webhook_id": "0aac461e7b774a38a72fd9c7c0eef8ee", "event_type": "order-status-updated", "event_created_at": "2024-07-11T21:40:48.424610Z", "product": "income", "link_id": "d8a8945ee2b049b193110cfba643f5df", "user_id": "adbe707dddee4334bffaeb5866272740", "data_source": "payroll", "order_id": "ddd192646b3c48be96651a0ff25cef85", "order_number": "4138538", "employer_id": "d7166cffbfef4bd6a9e830cf5508e615", "status": "completed", "template_id": null, "updated_at": "2024-07-11T21:40:48.424655+00:00" } ``` See [Task lifecycle](/api-reference/tasks/lifecycle) for all status transitions. ### Step 4: Retrieve data \[Server-side] Fetch order details using the `order_id`. The response includes employer data, employment history, income statements, and report IDs. ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Accept: application/json' ``` See [Order object](/api-reference/orders/object) for the full response schema. *** ## Order statuses | Status | Description | | ------------- | ------------------------------------------------ | | **Pending** | Order created, system processing | | **Sent** | Email or SMS sent to the user | | **Completed** | User connected their account | | **Error** | Notification delivery failed | | **Canceled** | Order manually canceled | | **Expired** | Order exceeded its expiration window | | **Skipped** | User opened the link but did not complete | | **No Data** | User connected but the provider returned no data | *** ## No-code alternative Create orders through the Dashboard UI without any API integration: single orders or bulk via CSV. See [Manual Orders](/developers/integration/manual-orders/new-user). *** ## Set expiration and reminders The default expiration window is **72 hours**, configurable from 1 day to 12 weeks. Expiration periods do not count weekends. Configure expiration and automatic reminders in the [Dashboard](/developers/dashboard) under **Customization**, or set `expired_at` when creating orders via API. *** ## Next steps Add additional employers to an existing order Refresh data from existing connections Pre-fill employer info to skip search Let users review and confirm retrieved data Send verification links via email/SMS. The applicant completes Bridge on their own device. # Self-Certification Source: https://docs.truv.com/developers/integration/hosted-orders/self-certification Retrieve user self-certification results for employments and accounts in an order Self-certification allows users to review and confirm (or reject) the employment and account data retrieved during verification. Retrieve the certification results to see whether the user confirmed the data as representative or flagged discrepancies. ```mermaid theme={null} sequenceDiagram participant User participant Hosted as Hosted Page participant Server as Your Server participant API as Truv API Hosted->>User: Verification data retrieved User->>Hosted: Reviews and certifies data API-->>Server: Webhook (order-status-updated) Server->>API: GET /v1/orders/{id}/certifications/ API-->>Server: Certification results (representative / not_representative) ``` *** ## When to use | Scenario | Example | | ----------------------- | ------------------------------------------------------------ | | Income verification | User confirms retrieved income matches their actual earnings | | Employment confirmation | User validates employer name, start date, and pay rate | | Asset verification | User reviews account balances and ownership details | | Dispute handling | User flags incorrect or outdated data with a reason | *** ## Retrieve certification results \[Server-side] Send a `GET` request to the order's `/certifications/` endpoint after the user completes their review. ```bash theme={null} curl --request GET \ --url https://prod.truv.com/v1/orders/39aa1486ccca4bc19cda071ffc1ba392/certifications/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'Accept: application/json' ``` ### Response structure Each result contains a `decision` and either an `employment` or `account` object. ```json theme={null} { "results": [ { "decision": "representative", "employment": { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "start_date": "2018-01-01", "pay_rate": "25.50", "pay_date": "2023-12-15", "company": { "name": "Facebook" } } }, { "decision": "not_representative", "rejection_reason": "incorrect_amount", "rejection_comment": "Balance is outdated", "account": { "id": "bc917458a3da4b2c8cc8282aa1707aaa", "type": "CHECKING", "mask": "1234", "routing_number": "021000021", "balance": "1500.25", "owners": [ { "full_name": "John Doe" } ] } } ] } ``` *** ## Decision values | Decision | Meaning | | -------------------- | ----------------------------------- | | `representative` | User confirmed the data is accurate | | `not_representative` | User flagged the data as inaccurate | ### Rejection reasons When the decision is `not_representative`, the result includes a `rejection_reason`: | Reason | Description | | ----------------------------- | --------------------------------------------------------- | | `employment_no_longer_active` | User is no longer employed at this company | | `incorrect_amount` | Income or balance amount is wrong | | `duplicate_entry` | Employer or account appears more than once | | `outdated_information` | Data is stale or no longer current | | `other` | User provided a custom explanation in `rejection_comment` | *** ## Next steps Create a hosted order from scratch Refresh data when certifications flag outdated info # CSV Upload Source: https://docs.truv.com/developers/integration/manual-orders/csv-upload Create verification orders in bulk by uploading a CSV file through the Dashboard For high-volume order creation without API integration, upload a CSV file through the Dashboard. Each row creates a separate order. Truv sends notifications to all users automatically. ```mermaid theme={null} sequenceDiagram participant Dashboard as Truv Dashboard participant API as Truv API participant Users as Users Dashboard->>API: 1. Upload CSV file API->>API: Validate rows API->>Users: 2. Email/SMS to each user Users->>API: 3. Users complete verifications API-->>Dashboard: 4. Status updates per order ``` *** ## Upload orders 1. Go to **Activity > Orders** and click **Upload Order** 2. Select the product type (income, employment, assets) ![Upload orders](https://files.readme.io/300294d-126.png) 3. Download the sample CSV template provided 4. Fill in the template with applicant details, one row per order 5. Drag-and-drop or browse to upload the completed file ![CSV file upload](https://files.readme.io/c847552-image.png) 6. Truv validates mandatory fields before processing Audit your CSV file to ensure all details are accurately filled out before uploading. Rows with missing mandatory fields (first name, last name) are rejected. *** ## CSV template fields | Column | Required | Description | | ------------------ | -------- | -------------------------------------- | | `first_name` | Yes | User's first name | | `last_name` | Yes | User's last name | | `email` | No\* | User's email for notifications | | `phone` | No\* | User's phone for SMS notifications | | `ssn` | No | Social security number (4 or 9 digits) | | `employer_name` | No | Pre-fill employer for deeplinking | | `loan_number` | No | Loan identifier for tracking | | `external_user_id` | No | Your internal identifier | At least one of `email` or `phone` is recommended per row. Otherwise Truv cannot send notifications and you must share the verification link manually. *** ## After upload Each row creates a separate order visible in the **Activity > Orders** table. Filter by source to see only CSV-uploaded orders. Track individual order statuses and view results as users complete their verifications. See [Manage Orders](/developers/integration/manual-orders/manage-orders) for filtering, searching, and exporting. *** ## Next steps Filter, search, and export order data Create a single order through the Dashboard # Manage Orders Source: https://docs.truv.com/developers/integration/manual-orders/manage-orders Filter, search, export, and customize the orders table in the Dashboard The Orders dashboard provides a centralized view of all verification orders, whether created manually, via CSV, or through the API. Filter, search, and export to manage your verification pipeline. Orders table *** ## Filter orders Narrow the orders table using these filters: | Filter | Options | | ---------------- | -------------------------------------------------------------------- | | **Date range** | Custom start and end dates | | **Status** | Pending, Sent, Completed, Error, Canceled, Expired, Skipped, No Data | | **Product type** | Income, Employment, Assets | | **Source** | Dashboard, API, CSV upload | | **Creator** | Team member who created the order | *** ## Search orders Search across multiple fields to find specific orders: | Search field | Example | | --------------- | ------------------------------------------------------------- | | Order ID | `39aa1486ccca4bc19cda071ffc1ba392` | | Applicant name | `John Doe` | | Email | `john@example.com` | | Phone | `4155554193` | | Employer | `Facebook` | | Loan number | `LN-2024-001` | | Tracking number | Custom tracking identifiers | | Report ID | Income & Employment (VOIE) or Assets (VOA) report identifiers | *** ## Export orders Export filtered order data as a CSV file. 1. Apply your desired filters 2. Click **Export CSV** 3. The file downloads with all visible columns Large exports (10,000+ rows) may take a few minutes to generate. *** ## Customize columns Control which columns appear in the orders table. 1. Click **Edit Columns** above the table 2. Toggle columns on or off 3. Drag to reorder columns Available columns include order ID, applicant name, status, product type, employer, creation date, completion date, source, creator, loan number, and custom fields. *** ## Order statuses | Status | Description | Terminal | | ------------- | ------------------------------------------------ | -------- | | **Pending** | Order created, system processing | No | | **Sent** | Email or SMS sent to the user | No | | **Completed** | User connected their account | Yes | | **Error** | Notification delivery failed | Yes | | **Canceled** | Order manually canceled | Yes | | **Expired** | Order exceeded its expiration window | Yes | | **Skipped** | User opened the link but did not complete | Yes | | **No Data** | User connected but the provider returned no data | Yes | *** ## Expiration & reminders ### Expiration The default expiration window is **72 hours**, configurable in your account settings from 1 day to 12 weeks. Expiration periods **do not count weekends**. An order created on Friday with a 2-day expiration expires on Tuesday, not Sunday. ### Automatic reminders Truv automatically sends an initial notification and up to three reminders via email and/or SMS. Each reminder includes the original order link. Reminders are distributed evenly from order creation until expiration. Once an order reaches a terminal status (completed, canceled, expired), reminders stop. SMS reminders require account-level enablement. Contact [support@truv.com](mailto:support@truv.com) to activate. SMS reminders are only sent between 10am–6pm ET. | Link Expiration | Order Lifespan | Initial Notification | Reminders | | --------------- | -------------------- | -------------------- | ------------------------------------------------------ | | 1 day | 24 hours + weekends | 30 seconds | 1st: 6 hours
2nd: 16 hours
3rd: 22 hours | | 2 days | 48 hours + weekends | 30 seconds | 1st: 6 hours
2nd: 24 hours | | 3 days | 72 hours + weekends | 30 seconds | 1st: 24 hours
2nd: 48 hours
3rd: 66 hours | | 1 week | 168 hours + weekends | 30 seconds | 1st: 24 hours
2nd: 72 hours
3rd: 120 hours | | 2 weeks | 336 hours + weekends | 30 seconds | 1st: 96 hours
2nd: 192 hours
3rd: 288 hours | | 3 weeks | 504 hours + weekends | 30 seconds | 1st: 264 hours
2nd: 384 hours
3rd: 456 hours | | 4 weeks | 672 hours + weekends | 30 seconds | 1st: 312 hours
2nd: 432 hours
3rd: 624 hours | Order expiration periods exclude weekends, but reminders continue being sent during weekends. Customize expiration times and reminder schedules in the [Truv Dashboard](https://dashboard.truv.com). Combining email and SMS improves completion rates. High-intent borrowers complete over 50% of verifications within 2 hours. *** ## Cancel an order Cancel an active order from the Dashboard when it's no longer needed. Open the order and click **Cancel**. If the order is partially completed, previously verified data remains accessible. Once canceled, the verification link is deactivated. The user can no longer complete the order. *** ## Next steps Create orders in bulk via CSV Create a single order through the Dashboard Full Dashboard overview and backend integration # New Order Source: https://docs.truv.com/developers/integration/manual-orders/new-user Create a verification order through the Truv Dashboard without writing any code Create orders directly in the Truv Dashboard. No API integration required. Enter the user's details, select a product, and Truv sends an email or SMS with a link to complete verification. Providing both email and phone maximizes success rates. High-intent users complete over 50% of verifications within 2 hours. ```mermaid theme={null} sequenceDiagram participant Dashboard as Truv Dashboard participant API as Truv API participant User as User Dashboard->>API: 1. Create Order API->>User: 2. Email/SMS with verification link User->>API: 3. User clicks link, connects accounts API-->>Dashboard: 4. Status updates in Dashboard ``` *** ## Create an order 1. Go to **Activity > Orders** in the [Dashboard](https://dashboard.truv.com) and click **Create Order** Dashboard - Orders 2. Select the product type (income, employment, assets) 3. Enter applicant details. First and last name are required. 4. Choose how to reach the user: send via email, SMS, or generate a shareable link Dashboard - Create an order 5. Click **Create**. Truv sends the notification automatically. ### Required fields | Field | Description | | -------------- | ----------------------------- | | `First name` | User's first name | | `Last name` | User's last name | | `Product type` | Income, employment, or assets | ### Recommended fields | Field | Description | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `Email` | User's email for notifications | | `Phone` | User's phone for SMS notifications | | `SSN` | Social security number (4 or 9 digits). Used for identity matching. | | `Loan number` | Loan identifier for tracking | | `Employer` | Pre-fill employer info to skip search (up to 5 employers) | | `Template` | [Customization template](/developers/customization) for branding | | `Custom field` | Custom metadata field to associate with the order. Configure custom fields in your [customization template](/developers/customization). | If both email and phone are left blank, Truv cannot send notifications. Retrieve the verification link from the order details and share it manually. *** ## Track order status After creating an order, track its progress directly in the Dashboard. The order card shows the current status, notification history, and connection results. Subscribe to email alerts for order status changes in **Settings > Notifications** to get notified when orders complete or fail without checking the Dashboard. | Status | Description | | ------------- | ------------------------------------------------ | | **Pending** | Order created, system processing | | **Sent** | Email or SMS sent to the user | | **Completed** | User connected their account | | **Error** | Notification delivery failed | | **Canceled** | Order manually canceled | | **Expired** | Order exceeded its expiration window | | **Skipped** | User opened the link but did not complete | | **No Data** | User connected but the provider returned no data | *** ## Set expiration and reminders The default expiration window is **72 hours**, configurable from 1 day to 12 weeks. Expiration periods do not count weekends. Configure expiration and automatic reminders in the [Dashboard](/developers/dashboard) under **Customization**. *** ## View results Once the user completes verification: 1. Open the order in **Activity > Orders** 2. View employer data, income, and employment details 3. Download PDF reports for each verified employer 4. Export data as needed Dashboard - Order details *** ## Next steps Filter, search, and export order data Create orders in bulk via CSV Full Dashboard overview and backend integration # Login Source: https://docs.truv.com/developers/login Log into the Truv Dashboard using email, SSO, or a social provider Sign into the Truv Dashboard with email/password, SSO, Google, or Microsoft. Go to [dashboard.truv.com](https://dashboard.truv.com) and click **Login**. *** ## Authentication methods | Method | How to use | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | **Email and password** | Enter your work email, press **Continue**, then enter your password | | **One-time passcode** | If configured, choose this option after entering your email to receive a passcode instead of a password | | **Google** | Click **Continue with Google** to authenticate with your Google Workspace account | | **Microsoft** | Click **Continue with Microsoft** to authenticate with your Microsoft account | | **Single sign-on (SSO)** | If your company has SAML 2.0 or OIDC SSO configured, entering your work email automatically redirects you to your identity provider | If you're not sure which method you used previously, enter your work email and press **Continue** — Truv redirects you to the last successfully used login method. *** ## SSO If your organization uses a centralized identity provider (Okta, Azure AD, etc.), Truv supports SAML 2.0 and OIDC. Contact [Truv Support](mailto:support@truv.com) to enable SSO for your company. Once SSO is active: * Users enter their work email and are automatically redirected to the identity provider * MFA is enforced at the identity provider level * Deprovisioning a user in your IdP immediately revokes their Truv Dashboard access See [SSO Configuration](/developers/sso) for setup instructions. *** ## Next steps Set up single sign-on for your team Add team members and assign roles # Multi-Tenancy Source: https://docs.truv.com/developers/multi-tenancy Manage separate Dashboard instances for different business units Multi-tenancy allows your organization to manage multiple separate [Dashboard](/developers/dashboard) instances, each with its own orders, customization templates, API keys, and team configuration. Team members can belong to multiple companies and switch between them instantly. This is useful for: * **Business unit separation**: distinct divisions operating independently * **Brand management**: different brands with separate branding and templates * **Per-environment isolation**: a separate company per customer-side environment (Dev / UAT / Prod) so orders, templates, and webhooks never cross * **Testing isolation**: separating sandbox and production setups across teams *** ## How it works ### Company Toggle A company toggle appears in the bottom-left of the Dashboard Home page. It shows your current company and an expandable list of all companies you belong to, with member counts and owner email addresses. Multi-tenancy dropdown list ### Shared Credentials Team members use the **same login credentials** across all assigned companies. No separate accounts needed. When access to a company is removed, it simply disappears from the toggle list. Members can have **different roles** in each company. For example, you could be an Owner in one company and a Developer in another. See [Team Roles & Permissions](/developers/dashboard#team-roles-and-permissions) for the full roles matrix. ### Company Identification A static company tile appears in the header on key pages (Create Order, New Template, Add Member) so you always know which company context you're working in. Multi-tenancy order creation *** ## Set up multi-tenancy For customers running separate Dev / UAT / Prod environments on their side (common for large financial institutions and state agencies), provision one Truv company per environment with its own designated owner. Each company has independent API keys, webhook URLs, customization templates, and order history — preventing UAT traffic from contaminating production order data. Provide the following for each new company: * Company name (include the environment in the name when relevant, e.g., "Acme — UAT") * Designated owner (one owner per company) * Billing rollup preferences * Any specific configuration requirements Your CSM creates the company and sends invitations. Existing active members get automatic access without needing a new invite email. For each new company, you'll need to: * Request production API keys * Set up [customization templates](/developers/customization) with the correct branding * Configure [webhooks](/api-reference/webhooks) and data settings as needed *** ## Manage teams Add members to any company via **Settings > Team > Add member**. When adding a member, specify: * Name and email * Role for this specific company * Available order templates Adding a member who already has a Truv account automatically grants them access to the new company through their existing login. *** ## Next steps Navigate the Dashboard interface Manage API credentials for each company Set up branding per company # Quickstart Source: https://docs.truv.com/developers/quickstart Run a complete Truv integration in minutes with Python, Ruby, Go, Node.js, or C# The [quickstart](https://github.com/truvhq/quickstart) repo runs a complete Truv integration end-to-end: create a user, launch Bridge, receive webhooks, and fetch reports. Available in five server-side languages, plus separate iOS and Android apps. *** ## Setup ### Prerequisites * [Docker](https://www.docker.com/) and Docker Compose * A [Truv sandbox account](https://dashboard.truv.com/app/development/keys) * API credentials from the [Truv Dashboard API Keys page](https://dashboard.truv.com/app/development/keys) ### Clone and configure ```bash theme={null} git clone https://github.com/truvhq/quickstart.git cd quickstart make env ``` Open `.env` and add your credentials from the [Dashboard API Keys page](https://dashboard.truv.com/app/development/keys): ``` API_CLIENT_ID=your_client_id API_SECRET=your_secret ``` Set `IS_ORDER=true` to use the Orders API instead of the Users API. The Orders API lets you pre-configure employer and account information. The quickstart also supports `API_PRODUCT_TYPE` values such as `income`, `employment`, `deposit_switch`, `pll`, and `admin`. Choose the product flow you want to exercise before starting the app. ### Environments All environments use the same base URL: `https://prod.truv.com/v1/`. Your credentials determine which environment you're using. | Environment | Purpose | | -------------- | ----------------------------------------------------- | | **Sandbox** | Test with sandbox credentials and simulated providers | | **Production** | Live user traffic and billed activity | *** ## Languages and repos ### Server-side quickstarts | Language | Repo | Port | | -------- | ------------------------------------------------------------------------------ | ---- | | Node.js | [quickstart/node](https://github.com/truvhq/quickstart/tree/master/node) | 5004 | | Python | [quickstart/python](https://github.com/truvhq/quickstart/tree/master/python) | 5001 | | Ruby | [quickstart/ruby](https://github.com/truvhq/quickstart/tree/master/ruby) | 5002 | | Go | [quickstart/golang](https://github.com/truvhq/quickstart/tree/master/golang) | 5003 | | C# | [quickstart/c-sharp](https://github.com/truvhq/quickstart/tree/master/c-sharp) | 5005 | *** ## Webhooks with ngrok To receive webhooks locally, start ngrok in a separate terminal: ```bash theme={null} ngrok http 3001 ``` Copy the forwarding URL into `.env`: ``` NGROK_URL=https://xxxx-xxxx-xxxx.ngrok-free.app ``` Restart the app. It automatically registers a sandbox webhook and cleans it up on exit. *** ## Run Pick your language and run with Docker: ```bash theme={null} make node_docker # http://localhost:5004 make python_docker # http://localhost:5001 make ruby_docker # http://localhost:5002 make golang_docker # http://localhost:5003 make csharp_docker # http://localhost:5005 ``` To run all languages simultaneously: `docker-compose up` *** Providers and credentials ## Sandbox data Use `goodlogin` / `goodpassword` to test a standard login flow, or `goodlogin` / `mfa` (MFA code: `12345`) to test the MFA flow. See [Test Credentials](/developers/testing/test-credentials) for all scenarios including error states, pay frequencies, and financial accounts. # Start Building Source: https://docs.truv.com/developers/quickstarts-overview Quickstart for basics, demo apps for real integration patterns ## Quickstart Run a minimal Truv integration end-to-end in Python, Ruby, Go, Node.js, or C#. Create a user, launch Bridge, receive a webhook, and fetch a report. Use this to verify your API keys work and understand the core flow before building anything. Clone, configure, and run in minutes with Docker. Five languages available. *** ## Demo apps The [demo-apps](https://github.com/truvhq/demo-apps) repo implements 12 real integration patterns across four verticals. Each makes live API calls, launches Bridge, receives webhooks, and fetches reports. Pick the demo that matches your use case and use it as a starting point. ### Prerequisites * [Node.js](https://nodejs.org/) 18+ * [ngrok](https://ngrok.com/) (free tier) for receiving webhooks locally * A [Truv sandbox account](https://dashboard.truv.com/app/development/keys) ### Setup ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install cp .env.example .env ``` Open `.env` and add your Truv API credentials: ``` API_CLIENT_ID=your_client_id API_SECRET=your_secret ``` Start ngrok in a separate terminal to receive webhooks: ```bash theme={null} ngrok http 3000 ``` Copy the `https://...ngrok-free.dev` URL into `.env`: ``` NGROK_URL=https://your-tunnel.ngrok-free.dev ``` Run the app: ```bash theme={null} npm start # Express server on :3000 npm run dev # Vite dev server on :5173 ``` Open `http://localhost:5173` and pick a demo. ### Choose a demo | Vertical | Demo | Pattern | Products | | --------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ------------------- | | Mortgage | [POS Application](/developers/demos/mortgage/pos-application) | [Embedded Orders](/developers/integration/embedded-orders/overview) | VOIE, VOA | | Mortgage | [POS Tasks](/developers/demos/mortgage/pos-tasks) | [Embedded Orders](/developers/integration/embedded-orders/overview) (multi-task) | VOIE, VOE, VOA | | Mortgage | [LOS](/developers/demos/mortgage/los) | [Hosted Orders](/developers/integration/hosted-orders/new-user) | VOIE, VOE | | Mortgage | [Document Processing](/developers/demos/mortgage/document-processing) | [Document Processing](/developers/integration/document-processing) | Document extraction | | Public Sector | [Customer Portal](/developers/demos/public-sector/customer-portal) | [Embedded Orders](/developers/integration/embedded-orders/overview) | VOIE, VOE | | Public Sector | [Document Processing](/developers/demos/public-sector/document-processing) | [Document Processing](/developers/integration/document-processing) | Document extraction | | Public Sector | [Case Worker Portal](/developers/demos/public-sector/case-worker-portal) | [Hosted Orders](/developers/integration/hosted-orders/new-user) | VOIE, VOE | | Consumer Credit | [Smart Routing](/developers/demos/consumer-credit/smart-routing) | [Bridge Widget](/developers/integration/bridge-widget/overview) | VOIE | | Consumer Credit | [Bank Income](/developers/demos/consumer-credit/bank-income) | [Bridge Widget](/developers/integration/bridge-widget/overview) | Income Insights | | Consumer Credit | [Payroll Income](/developers/demos/consumer-credit/payroll-income) | [Bridge Widget](/developers/integration/bridge-widget/overview) | VOIE | | Consumer Credit | [Paycheck-Linked Loans](/developers/demos/consumer-credit/paycheck-linked-loans) | [Bridge Widget](/developers/integration/bridge-widget/overview) | PLL | | Retail Banking | [Direct Deposit Switch](/developers/demos/retail-banking/direct-deposit-switch) | [Bridge Widget](/developers/integration/bridge-widget/overview) | DDS | ### Which demo fits your use case? | If you're building… | Start with | | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | Mortgage origination (purchase, refi, HELOC) | [POS Application](/developers/demos/mortgage/pos-application) | | Consumer lending (auto, personal, BNPL) | [Payroll Income](/developers/demos/consumer-credit/payroll-income) or [Smart Routing](/developers/demos/consumer-credit/smart-routing) | | Co-borrower or multi-product verification | [POS Tasks](/developers/demos/mortgage/pos-tasks) | | Loan processor or caseworker portal | [LOS](/developers/demos/mortgage/los) or [Case Worker Portal](/developers/demos/public-sector/case-worker-portal) | | Account funding / direct deposit capture | [Direct Deposit Switch](/developers/demos/retail-banking/direct-deposit-switch) | | Earned wage access or loan repayment | [Paycheck-Linked Loans](/developers/demos/consumer-credit/paycheck-linked-loans) | | Income from bank when payroll unavailable | [Bank Income](/developers/demos/consumer-credit/bank-income) | | Benefits eligibility (SNAP, Medicaid, TANF) | [Customer Portal](/developers/demos/public-sector/customer-portal) | | Pay stub / W-2 / tax return processing | [Document Processing](/developers/demos/mortgage/document-processing) | See [Test Credentials](/developers/testing/test-credentials) for sandbox login scenarios. # Android SDK Source: https://docs.truv.com/developers/sdks/android Truv Bridge SDK for Android (Kotlin) **Package:** `com.truv.sdk:android_sdk` | [Maven Central](https://central.sonatype.com/artifact/com.truv.sdk/android_sdk) | [Demo app](https://github.com/truvhq/demo-android) ## Install Add the Truv SDK to your module's `build.gradle`: ```gradle theme={null} dependencies { implementation "com.truv.sdk:android_sdk:LATEST_VERSION" } ``` Make sure `mavenCentral()` is included in your project's repository configuration. Add the `INTERNET` permission to your `AndroidManifest.xml`: ```xml theme={null} ``` *** ## Embedded Orders Use `TruvOrderView` to embed an Order, a multi-connection verification workflow that supports multiple data sources and product types. Add to your layout XML: ```xml theme={null} ``` Or create programmatically: ```kotlin theme={null} val orderView = TruvOrderView(context) ``` Initialize and load: ```kotlin theme={null} import com.truv.models.TruvEventPayload import com.truv.models.TruvOrderEvent import com.truv.webview.TruvOrderEventsListener import com.truv.webview.TruvOrderView class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val orderView = view.findViewById(R.id.orderView) orderView.addEventListener(object : TruvOrderEventsListener { override fun onOrderEvent(event: TruvOrderEvent) { when (event) { is TruvOrderEvent.Load -> { // Order page finished loading } is TruvOrderEvent.Close -> { // User closed the Order } is TruvOrderEvent.Success -> { // A task within the Order completed successfully. // The Order is still open at this point — it may show // a success screen or a self-certification screen // depending on the configuration. } is TruvOrderEvent.Completed -> { // The entire Order is complete (all tasks finished) } } } override fun onBridgeEvent(event: TruvEventPayload) { // Fired when the user interacts with the Bridge for a // sub-order (task) within the Order. // Equivalent to TruvEventsListener.onEvent(). } }) orderView.loadOrderUrl(orderToken) } } ``` *** ## Bridge Widget Use `TruvBridgeView` for single-connection flows like Direct Deposit Switch and Paycheck Linked Lending. Add to your layout XML: ```xml theme={null} ``` Or create programmatically: ```kotlin theme={null} val bridgeView = TruvBridgeView(context) ``` Initialize and load: ```kotlin theme={null} import com.truv.models.TruvEventPayload import com.truv.models.TruvSuccessPayload import com.truv.webview.TruvBridgeView import com.truv.webview.TruvEventsListener class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val bridgeView = view.findViewById(R.id.bridgeView) bridgeView.addEventListener(object : TruvEventsListener { override fun onLoad() { // Bridge finished loading } override fun onClose() { // User closed the Bridge } override fun onSuccess(payload: TruvSuccessPayload) { // Called when the Bridge closes after a successful task. // payload.publicToken — use this to retrieve data server-side. // payload.metadata.taskId — the task identifier. } override fun onEvent(event: TruvEventPayload) { // Lifecycle event — see Bridge Events for all types. } }) bridgeView.loadBridgeTokenUrl(bridgeToken) } } ``` See [Bridge Events](/developers/sdks/bridge-events) for all event types, payloads, and error codes. *** ## Sample app Kotlin demo using the Truv Android SDK Clone the demo app from GitHub and install dependencies. Copy your **Client ID** and **Access Secret** from the [Dashboard](https://dashboard.truv.com) into the app's configuration file. Use [sandbox test credentials](/developers/testing/test-credentials) to simulate a full verification flow. Use the demo app as a reference to understand how the SDK works. Follow the implementation guide above to add Truv Bridge to your own application. Swap in production credentials in your app when ready. # Bridge Events Source: https://docs.truv.com/developers/sdks/bridge-events Complete reference for Truv Bridge JavaScript callbacks, onEvent types, event data payloads, and error codes Truv Bridge emits client-side events during the user's connection flow. These are JavaScript callbacks configured when you initialize `TruvBridge.init()`. They are distinct from [server-side webhook events](/api-reference/webhooks). * [Callbacks](#callbacks): Responses for specific Truv Bridge actions * [Event data](#event-data): `onEvent` types and their payload shapes * [Errors](#errors): Bridge error objects, types, and codes *** ## Callbacks ```javascript theme={null} const bridge = TruvBridge.init({ bridgeToken: bridgeToken, onSuccess(publicToken, metadata) {}, // required onLoad() {}, // optional onEvent(type, payload) {}, // optional onClose() {}, // optional }) ``` | Callback | Required | Description | | ----------- | -------- | -------------------------------------------------------------------------------------------------------------------- | | `onSuccess` | Required | User successfully connected to a payroll provider and closed Bridge. Receives `publicToken` and a `metadata` object. | | `onLoad` | Optional | Truv Bridge finished loading. | | `onEvent` | Optional | A specific event occurred within Bridge. See [Event data](#event-data) for all types. | | `onClose` | Optional | Truv Bridge was closed by the user. | The Embedded Orders flow uses a different callback signature. See [Embedded Orders](/developers/integration/embedded-orders/overview) for the correct initialization pattern when using `isOrder: true`. *** ## Event data ### onEvent Types | Event Type | Payload | Description | | --------------------- | ----------------------- | --------------------------------------------------------- | | `LOAD` | None | Bridge module finished loading | | `OPEN` | `CommonEventData` | Bridge is ready and visible | | `SCREEN_VIEW` | `ScreenViewData` | A Bridge screen was viewed | | `EMPLOYER_SELECTED` | `EmployerSelectedData` | Employer or provider selected | | `DOC_UPLOAD_OPENED` | `CommonEventData` | Document upload screen opened | | `DOCUMENTS_UPLOADED` | `DocumentsUploadedData` | Specific document types uploaded | | `LINK_CREATED` | `TaskData` | User logging in as a new Link | | `LOGIN_COMPLETE` | `TaskData` | User successfully logged in | | `SUCCESS` | `TaskData` | Data successfully retrieved | | `ERROR` | `ErrorData` | Error during connection process | | `UNSUPPORTED_BROWSER` | None | Browser is not supported | | `CLOSE` | `CloseData` | Bridge was closed | | `MANUAL_DDS` | `ManualDDSData` | Manual Direct Deposit Switch (DDS) operation submitted | | `OAUTH_OPENED` | `OAuthEventData` | User redirected to OAuth login (assets/transactions only) | *** ### CommonEventData Present on `OPEN` and `DOC_UPLOAD_OPENED` events. | Field | Type | Description | | -------------- | ------ | ---------------------------------------------------------------------------------------------- | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type (`income`, `employment`, `assets`, etc.). May be `undefined` if token is expired. | | `data_source` | string | Underlying data source: `payroll`, `docs`, `financial_accounts`, `tax`, or `insurance` | ```json theme={null} { "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "income", "data_source": "payroll" } ``` *** ### ScreenViewData | Field | Type | Description | | -------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | `view_name` | string | Screen viewed: `SELECT_EMPLOYER`, `PROVIDER_LIST`, `PROVIDER_LOGIN`, `PROVIDER_ORG_ID`, `ERROR`, `SUCCESS`, `DOC_UPLOAD`, `DOC_UPLOAD_TYPES` | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type | | `doc_type` | string | Applicable only for `DOC_UPLOAD`: `paystub`, `w2`, or `f1099` | | `data_source` | string | Underlying data source: `payroll`, `docs`, `financial_accounts`, `tax`, `scoring_attributes`, or `insurance` | ```json theme={null} { "view_name": "PROVIDER_LOGIN", "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "income", "data_source": "payroll" } ``` *** ### EmployerSelectedData | Field | Type | Description | | -------------- | ------ | -------------------------------------------------------------- | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type | | `employer` | object | Employer object with `name` property. `null` if none selected. | | `provider` | string | ID of the selected provider. `null` if none selected. | | `data_source` | string | Underlying data source | ```json theme={null} { "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "income", "employer": { "name": "Acme Corp" }, "provider": "workday", "data_source": "payroll" } ``` *** ### DocumentsUploadedData | Field | Type | Description | | -------------- | ------ | ------------------------------------------------------ | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type | | `doc_type` | string | Type of document uploaded: `paystub`, `w2`, or `f1099` | | `data_source` | string | Always `docs` for document upload events | ```json theme={null} { "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "income", "doc_type": "paystub", "data_source": "docs" } ``` *** ### TaskData Present on `LINK_CREATED`, `LOGIN_COMPLETE`, and `SUCCESS` events. | Field | Type | Description | | -------------- | ------ | ------------------------------------------------------------------ | | `public_token` | string | Exchange for `access_token` on your server | | `task_id` | string | Unique task identifier. Include in support tickets. | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type | | `employer` | object | Employer data object. May be `undefined` for `admin` product type. | | `provider_id` | string | Unique identifier for the selected provider | | `data_source` | string | Underlying data source | ```json theme={null} { "public_token": "d80ec8255dc54c5eb7cc03ac05d18ebd", "task_id": "2b0e7a7dec1d47678fec4e02af621cc0", "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "income", "provider_id": "adp", "employer": { "name": "Acme Corp" }, "data_source": "payroll" } ``` *** ### ErrorData | Field | Type | Description | | -------------- | ------ | ------------------------------------------------------------------------------------------ | | `error` | object | Error object. See [Errors](#errors). | | `public_token` | string | Associated `public_token`. Only present if error is tied to a specific connection attempt. | | `task_id` | string | Task identifier. Include in support tickets. | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type | | `data_source` | string | Underlying data source | ```json theme={null} { "error": { "error_code": "LOGIN_ERROR", "error_message": "Username or password is incorrect", "error_type": "LINK_ERROR" }, "task_id": "5ad1938450c54024bbc967a3a7dc9020", "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "income", "data_source": "payroll" } ``` *** ### CloseData | Field | Type | Description | | ---------- | ------ | ------------------------------------------------------------------------ | | `employer` | object | Employer selected before closing. `undefined` if no employer was chosen. | ```json theme={null} { "employer": { "name": "Acme Corp" } } ``` *** ### ManualDDSData | Field | Type | Description | | ------------- | ------ | ----------------------------------------------------------------------------------------- | | `action` | string | Operation type: `EMAIL`, `DOWNLOAD`, `SHARE`, or `EXTERNAL_FLOW` | | `depositType` | string | Deposit type selected: `entire`, `percent`, or `amount`. Not present for `EXTERNAL_FLOW`. | ```json theme={null} { "depositType": "entire", "action": "EMAIL" } ``` *** ### OAuthEventData | Field | Type | Description | | -------------- | ------ | ---------------------------------------------- | | `bridge_token` | string | The `bridge_token` passed to `TruvBridge.init` | | `product_type` | string | Product type | | `task_id` | string | Task identifier | | `provider_id` | string | Unique identifier for the selected provider | | `url` | string | OAuth URL the user is redirected to | ```json theme={null} { "bridge_token": "b5cb1933e43043a792a9b337af5824e2", "product_type": "assets", "provider_id": "truv_bank_oauth", "task_id": "5ad1938450c54024bbc967a3a7dc9020", "url": "https://www.truv.com/oauth-login.html?..." } ``` *** ## Errors ```json theme={null} { "error": { "error_code": "LOGIN_ERROR", "error_message": "Username or password is incorrect", "error_type": "LINK_ERROR" } } ``` Design your UX to surface login errors to borrowers in real time. When `onEvent` fires with type `ERROR` and `error_code: LOGIN_ERROR`, prompt the user to re-enter their credentials rather than silently failing. ### Error Object | Field | Type | Description | | --------------- | ------ | -------------------------- | | `error_type` | string | Category of error | | `error_code` | string | Specific error code | | `error_message` | string | Human-readable description | ### Error Types | Type | Description | | ------------ | ------------------------ | | `LINK_ERROR` | Generic link-level error | ### Error Codes | Code | Description | | ------------- | ------------------------------------- | | `ERROR` | Generic error occurred | | `LINK_EXISTS` | User's account is already connected | | `LOGIN_ERROR` | Incorrect username, password, or both | | `MFA_ERROR` | Invalid MFA input | | `NO_DATA` | User account has no data available | | `UNAVAILABLE` | Payroll provider is unreachable | *** ## Route errors to manual fallback When Bridge encounters an error, intercept it client-side and route the user to a manual verification workflow instead of dead-ending the experience. 1. **Detect the error.** Register an `onEvent` callback when initializing Truv Bridge. When `onEvent` fires with type `ERROR`, inspect the `error_code` in the payload. 2. **Close Bridge.** After capturing the error details, close the Bridge widget programmatically or wait for the user to close it via `onClose`. 3. **Route to fallback.** Based on the error type, redirect the user to your manual process -- document upload, paper form submission, or a support contact flow. | `error_code` | Meaning | Recommended fallback | | ------------- | ------------------------------- | --------------------------------------------------------------------------------------------- | | `LOGIN_ERROR` | Incorrect credentials | Prompt the user to retry. After repeated failures, offer document upload. | | `MFA_ERROR` | Invalid MFA input | Prompt the user to retry. After repeated failures, offer document upload. | | `UNAVAILABLE` | Payroll provider is unreachable | Route directly to document upload or manual process. The provider outage is not user-fixable. | | `NO_DATA` | Account has no data | Route to document upload. The connected account lacks the required records. | | `ERROR` | Generic error | Log the `task_id` for debugging. Offer document upload as a fallback. | Track which `error_code` values trigger manual fallbacks in your analytics. A high rate of `UNAVAILABLE` errors for a specific provider may indicate a temporary outage, while frequent `LOGIN_ERROR` events may point to a UX issue in your credential entry flow. Bridge errors are client-side events, distinct from server-side [webhook events](/api-reference/webhooks) and task status changes. Use both in combination: Bridge `onEvent` for real-time UX routing, and webhooks for backend workflow orchestration. *** ## Next steps Install Truv Bridge for web and mobile Server-side event reference for task and data-object events Task status flow referenced by Bridge events Skip employer search to improve conversion # Flutter SDK Source: https://docs.truv.com/developers/sdks/flutter Truv Bridge SDK for Flutter **Package:** `truv_flutter` | [pub.dev](https://pub.dev/packages/truv_flutter) | [Demo app](https://github.com/truvhq/demo-flutter) ## Install ```bash theme={null} flutter pub add truv_flutter ``` *** ## Embedded Orders Use `TruvOrder` to embed an Order, a multi-connection verification workflow that supports multiple data sources and product types. ```dart theme={null} import 'package:flutter/widgets.dart'; import 'package:truv_flutter/truv_event.dart'; import 'package:truv_flutter/truv_flutter.dart'; class OrderScreen extends StatelessWidget { final String bridgeToken; const OrderScreen({super.key, required this.bridgeToken}); @override Widget build(BuildContext context) { return TruvOrder( bridgeToken: bridgeToken, onOrderEvent: (TruvOrderBridgeEvent event) { switch (event) { case TruvOrderBridgeLoad(): // Order page finished loading break; case TruvOrderBridgeClose(): // User closed the Order break; case TruvOrderBridgeSuccess(): // A task within the Order completed successfully. // The Order is still open at this point — it may show // a success screen or a self-certification screen // depending on the configuration. break; case TruvOrderBridgeCompleted(): // The entire Order is complete (all tasks finished) break; } }, onBridgeEvent: (TruvEventEvent event) { // Fired when the user interacts with the Bridge for a // sub-order (task) within the Order. // Equivalent to TruvBridge onEvent. }, ); } } ``` *** ## Bridge Widget Use `TruvBridge` for single-connection flows like Direct Deposit Switch and Paycheck Linked Lending. ```dart theme={null} import 'package:flutter/widgets.dart'; import 'package:truv_flutter/truv_event.dart'; import 'package:truv_flutter/truv_flutter.dart'; class BridgeScreen extends StatelessWidget { final String bridgeToken; const BridgeScreen({super.key, required this.bridgeToken}); @override Widget build(BuildContext context) { return TruvBridge( bridgeToken: bridgeToken, onEvent: (TruvEvent event) { switch (event) { case TruvEventLoad(): // Bridge finished loading break; case TruvEventClose(): // User closed the Bridge break; case TruvEventSuccess(:final publicToken, :final metadata): // Called when the Bridge closes after a successful task. // publicToken — use this to retrieve data server-side. // metadata.taskId — the task identifier. break; case TruvEventEvent(:final eventType, :final payload): // Lifecycle event — see Bridge Events for all types. break; case TruvEventError(): // An error occurred in the Bridge break; } }, ); } } ``` See [Bridge Events](/developers/sdks/bridge-events) for all event types, payloads, and error codes. *** ## Sample app Cross-platform with a single codebase Clone the demo app from GitHub and install dependencies. Copy your **Client ID** and **Access Secret** from the [Dashboard](https://dashboard.truv.com) into the app's configuration file. Use [sandbox test credentials](/developers/testing/test-credentials) to simulate a full verification flow. Use the demo app as a reference to understand how the SDK works. Follow the implementation guide above to add Truv Bridge to your own application. Swap in production credentials in your app when ready. # iOS SDK Source: https://docs.truv.com/developers/sdks/ios Truv Bridge SDK for iOS (Swift) **Package:** `TruvSDK` | [Swift Package](https://github.com/truvhq/ios-sdk) | [CocoaPods](https://cocoapods.org/pods/TruvSDK) | [Demo app](https://github.com/truvhq/demo-ios) ## Install ### Swift Package Manager 1. In Xcode, go to **File > Add Package Dependencies** 2. Enter the package URL: ``` https://github.com/truvhq/ios-sdk.git ``` 3. Select the version and add `TruvSDK` to your target ### CocoaPods [CocoaPods trunk becomes read-only on December 2, 2026](https://blog.cocoapods.org/CocoaPods-Specs-Repo/). No new library versions can be published after that date. Truv plans to stop publishing CocoaPods updates in December 2026. Swift Package Manager is recommended for new projects. Add to your `Podfile`: ```ruby theme={null} pod 'TruvSDK' ``` Then run: ```bash theme={null} pod install ``` *** ## Embedded Orders Use `TruvOrderController` to present an Order, a multi-connection verification workflow that supports multiple data sources and product types. ```swift theme={null} import TruvSDK class ViewController: UIViewController { func openOrder(token: String) { let order = TruvOrderController(token: token, delegate: self) order.modalPresentationStyle = .fullScreen present(order, animated: true) } } extension ViewController: TruvOrderDelegate { func onOrderEvent(_ event: TruvOrderEvent) { switch event { case .load: // Order page finished loading break case .close: // User closed the Order break case .success: // A task within the Order completed successfully. // The Order is still open at this point — it may show // a success screen or a self-certification screen // depending on the configuration. break case .completed: // The entire Order is complete (all tasks finished) break } } func onBridgeEvent(_ event: TruvEventPayload) { // Fired when the user interacts with the Bridge for a // sub-order (task) within the Order. // Equivalent to TruvDelegate.onEvent(.onEvent(payload)). } } ``` *** ## Bridge Widget Use `TruvBridgeController` for single-connection flows like Direct Deposit Switch and Paycheck Linked Lending. ```swift theme={null} import TruvSDK class ViewController: UIViewController { func openBridge(token: String) { let bridge = TruvBridgeController(token: token, delegate: self) bridge.modalPresentationStyle = .fullScreen present(bridge, animated: true) } } extension ViewController: TruvDelegate { func onEvent(_ event: TruvEvent) { switch event { case .onLoad: // Bridge finished loading break case .onClose: // User closed the Bridge break case .onSuccess(let payload): // Called when the Bridge closes after a successful task. // payload?.publicToken — use this to retrieve data server-side. // payload?.metadata.taskId — the task identifier. break case .onEvent(let payload): // Lifecycle event — see Bridge Events for all types. break } } } ``` See [Bridge Events](/developers/sdks/bridge-events) for all event types, payloads, and error codes. *** ## Sample app Swift demo using `TruvSDK` Clone the demo app from GitHub and install dependencies. Copy your **Client ID** and **Access Secret** from the [Dashboard](https://dashboard.truv.com) into the app's configuration file. Use [sandbox test credentials](/developers/testing/test-credentials) to simulate a full verification flow. Use the demo app as a reference to understand how the SDK works. Follow the implementation guide above to add Truv Bridge to your own application. Swap in production credentials in your app when ready. # Vanilla JS SDK Source: https://docs.truv.com/developers/sdks/javascript Truv Bridge SDK for vanilla JavaScript **Package:** `@truv/bridge` | [npm](https://www.npmjs.com/package/@truv/bridge) | [GitHub](https://github.com/truvhq) ## Install ```bash theme={null} npm install @truv/bridge ``` Or with yarn: ```bash theme={null} yarn add @truv/bridge ``` *** ## Embedded Orders Use `isOrder: true` when initializing Bridge for multi-connection verification workflows (VOIE, VOE, VOA). ```javascript theme={null} import TruvBridge from '@truv/bridge'; const bridge = TruvBridge.init({ bridgeToken: 'your_bridge_token', isOrder: true, onLoad: function () { console.log('Order page loaded'); }, onSuccess: function () { console.log('User connected all accounts'); }, onClose: function () { console.log('Order page closed'); }, onEvent: function (type, payload, source) { console.log('Event:', type, 'Source:', source); if (type === 'COMPLETED' && source === 'order') { // Order reached final state — advance the user navigateToNextStep(); } } }); bridge.open(); ``` Wait for the `COMPLETED` event with `source: "order"` before advancing the user in your application. Do **not** use `onSuccess` or `onClose` to advance. The order may still have pending connections. The `onEvent` callback receives a third `source` parameter that distinguishes order-page events from connection-widget events. **Order page events** (`source: "order"`): ```javascript theme={null} onEvent('LOAD', undefined, 'order') // Fires same time as onLoad() onEvent('CLOSE', undefined, 'order') // Fires same time as onClose() onEvent('SUCCESS', undefined, 'order') // Fires same time as onSuccess() onEvent('COMPLETED', undefined, 'order') // Fires on final state (success or skipped) ``` **Connection widget events** (`source: "bridge"`): ```javascript theme={null} onEvent(bridgeEventType, bridgeEventPayload, 'bridge'); ``` See [Bridge Events](/developers/sdks/bridge-events) for the full list of connection widget event types and payloads. ### Position The `position` parameter controls how the embedded order page is displayed. The default type is `'dialog'`. * `{ type: 'dialog' }`: The bridge appears as a dialog window, which overlays the rest of the interface and disables scrolling. * `{ type: 'inline', container: HTMLElement }`: The embedded order page is integrated within an existing element, allowing the interface to function without blocking the rest of the interface or global scrolling. Ensure that your interface functions seamlessly across various devices, particularly on mobile devices such as iPhones and Androids, including compatibility with virtual keyboards. ```javascript theme={null} const bridge = TruvBridge.init({ bridgeToken: '', isOrder: true, position: { type: 'inline', container: document.querySelector('#inline-order-container') } }); ``` There are important requirements when using inline position: 1. The container element must remain stable while the bridge is open. The container and all its parent elements must not be unmounted or moved to a different parent node. 2. You must manually close the bridge before removing the parent container, for example when navigating to another page in a single-page application without a full reload. 3. Only one bridge instance can be open on the page at a time. For inline frame sizing, automatic height, and modal launch behavior, see [Display Modes](/developers/integration/embedded-orders/display-modes). *** ## Bridge Widget Use the Bridge Widget flow (without `isOrder`) for single-connection flows like Direct Deposit Switch and Paycheck Linked Lending. ```javascript theme={null} import TruvBridge from '@truv/bridge'; const bridge = TruvBridge.init({ bridgeToken: 'your_bridge_token', onSuccess: (publicToken, metaData) => { console.log('public_token:', publicToken); // Send publicToken to your backend for exchange }, onClose: () => { console.log('Widget closed'); } }); bridge.open(); ``` # SDK Overview Source: https://docs.truv.com/developers/sdks/overview Truv Bridge SDKs for web and mobile Embed Truv Bridge to let users connect their payroll, employment, and financial accounts. Load the SDK straight from the CDN, or install a framework-specific wrapper that handles initialization and events for your platform. For a plain web page, drop in the script tag and call `TruvBridge.init()`: ```html theme={null} ``` Alongside this direct import, you can use one of the SDKs below. ## Web `@truv/bridge` for plain web pages — or load it directly from the CDN. `@truv/react` hooks and components for React apps. ## Mobile `TruvSDK` Swift package for native iOS apps. `com.truv.sdk:android_sdk` for native Kotlin apps. `@truv/react-native` for cross-platform React Native apps. `truv_flutter` for cross-platform Flutter apps. ## Events Client-side callbacks, `onEvent` types, event payloads, and error codes. # React SDK Source: https://docs.truv.com/developers/sdks/react Truv Bridge SDK for React **Package:** `@truv/react` | [npm](https://www.npmjs.com/package/@truv/react) | [GitHub](https://github.com/truvhq) ## Install ```bash theme={null} npm install @truv/react ``` Or with yarn: ```bash theme={null} yarn add @truv/react ``` *** ## Embedded Orders Use `isOrder={true}` when rendering the Bridge component for multi-connection verification workflows (VOIE, VOE, VOA). ```jsx theme={null} import { useState } from 'react'; import { TruvBridge } from '@truv/react'; function VerificationFlow({ bridgeToken }) { const [isOpen, setIsOpen] = useState(false); return ( <> setIsOpen(false)} onSuccess={() => { console.log('User connected all accounts'); }} onEvent={(type, payload, source) => { if (type === 'COMPLETED' && source === 'order') { navigateToNextStep(); } }} /> ); } ``` Wait for the `COMPLETED` event with `source: "order"` before advancing the user in your application. Do **not** use `onSuccess` or `onClose` to advance. The order may still have pending connections. The `onEvent` callback receives a third `source` parameter. See [Bridge Events](/developers/sdks/bridge-events) for all event types, payloads, and error codes. *** ## Bridge Widget Use the Bridge component without `isOrder` for single-connection flows like Direct Deposit Switch and Paycheck Linked Lending. ```jsx theme={null} import { useState } from 'react'; import { TruvBridge } from '@truv/react'; function DepositSwitch({ bridgeToken }) { const [isOpen, setIsOpen] = useState(false); return ( <> setIsOpen(false)} onSuccess={(publicToken, metaData) => { console.log('public_token:', publicToken); }} /> ); } ``` # React Native SDK Source: https://docs.truv.com/developers/sdks/react-native Truv Bridge SDK for React Native **Package:** `@truv/react-native` | [npm](https://www.npmjs.com/package/@truv/react-native) | [Demo app](https://github.com/truvhq/demo-react-native) ## Install ```bash theme={null} npm install @truv/react-native ``` Or with yarn: ```bash theme={null} yarn add @truv/react-native ``` Run CocoaPods install for iOS after adding the package: ```bash theme={null} cd ios && pod install ``` *** ## Embedded Orders Use `TruvOrder` to embed an Order, a multi-connection verification workflow that supports multiple data sources and product types. ```typescript theme={null} import { FC } from 'react'; import { StyleSheet, View } from 'react-native'; import { TruvOrder, TruvEventPayload, TruvOrderEventPayload } from '@truv/react-native'; const OrderScreen: FC<{ bridgeToken: string }> = ({ bridgeToken }) => { return ( { switch (payload.eventType) { case "LOAD": // Order page finished loading break; case "CLOSE": // User closed the Order break; case "SUCCESS": // A task within the Order completed successfully. // The Order is still open at this point — it may show // a success screen or a self-certification screen // depending on the configuration. break; case "COMPLETED": // The entire Order is complete (all tasks finished) break; } }} onWidgetEvent={(payload: TruvEventPayload) => { // Fired when the user interacts with the Bridge for a // sub-order (task) within the Order. // Equivalent to TruvBridge onEvent. }} /> ); }; const styles = StyleSheet.create({ order: { flex: 1 }, }); ``` *** ## Bridge Widget Use `TruvBridge` for single-connection flows like Direct Deposit Switch and Paycheck Linked Lending. ```typescript theme={null} import { FC } from 'react'; import { StyleSheet, View } from 'react-native'; import TruvBridge, { TruvEventPayload, TruvSuccessPayload } from '@truv/react-native'; const BridgeScreen: FC<{ bridgeToken: string }> = ({ bridgeToken }) => { return ( { // Bridge finished loading }} onClose={() => { // User closed the Bridge }} onSuccess={(payload: TruvSuccessPayload) => { // Called when the Bridge closes after a successful task. // payload.publicToken — use this to retrieve data server-side. // payload.metadata.taskId — the task identifier. }} onEvent={(payload: TruvEventPayload) => { // Lifecycle event — see Bridge Events for all types. // payload.eventType — one of TruvEventType enum values }} /> ); }; const styles = StyleSheet.create({ bridge: { flex: 1 }, }); ``` See [Bridge Events](/developers/sdks/bridge-events) for all event types, payloads, and error codes. *** ## Sample app Cross-platform demo for iOS and Android Clone the demo app from GitHub and install dependencies. Copy your **Client ID** and **Access Secret** from the [Dashboard](https://dashboard.truv.com) into the app's configuration file. Use [sandbox test credentials](/developers/testing/test-credentials) to simulate a full verification flow. Use the demo app as a reference to understand how the SDK works. Follow the implementation guide above to add Truv Bridge to your own application. Swap in production credentials in your app when ready. # SSO Configuration Source: https://docs.truv.com/developers/sso Set up single sign-on with SAML 2.0, OIDC, or Azure AD Truv supports single sign-on (SSO) so your team can authenticate to the [Dashboard](/developers/dashboard) through your organization's identity provider. Once enabled, users sign in with their corporate credentials instead of a separate Truv password. SSO works with [multi-tenancy](/developers/multi-tenancy) setups. Users authenticate once and access all assigned companies. *** ## Supported protocols HTTP Redirect binding (SP → IdP) and HTTP POST binding (IdP → SP) Requires Issuer URL and Client ID. Client Secret is optional. Requires Azure AD Domain, Client ID, and Client Secret. *** ## Supported identity providers * Okta * Azure Active Directory * Google Workspace * Ping Identity * Auth0 * Custom SAML providers *** ## Benefits Manage all Dashboard access through your existing identity provider. When a user's account is deactivated at the IdP, they immediately lose Dashboard access. Enforce multi-factor authentication and conditional access policies at the IdP level. Comprehensive audit trail of all SSO authentication events for compliance. *** ## Set up SSO Contact your Technical Account Manager (TAM) to request SSO setup for your organization. Truv generates a secure self-service configuration link for your IT team to set up the connection in your IdP. Let your TAM know when the IdP configuration is complete so Truv can validate the connection. Truv activates SSO organization-wide. Production clients validate via a call; onboarding clients validate via email. Once SSO is activated, all team members authenticate through your IdP. Any MFA or conditional access policies you've configured apply automatically. *** ## User experience After SSO is enabled: 1. Users navigate to the Dashboard login page 2. They enter their work email address 3. They're redirected to your identity provider for authentication 4. After successful authentication, they're returned to the Dashboard with full access based on their [assigned role](/developers/dashboard#team-roles-and-permissions) *** ## Next steps Data protection, encryption, and compliance certifications Navigate the Dashboard interface API credentials and access management # Assets Testing Source: https://docs.truv.com/developers/testing/assets Sandbox credentials, account variants, and bank income source scenarios for VOA integrations Test Verification of Assets (VOA) and bank-derived income scenarios in sandbox using the credentials below. Pass `product_type: assets` on the bridge token or order, and search for **Truv Bank OAuth** or **Truv Bank non-OAuth** in Truv Bridge. For additional login fields, use **Phone:** `(111)111-1111` and **Email:** `goodlogin@domain.com`. *** ## Quick start | Credential | Provider | What you get | | ---------------------------- | -------------------------------------- | ------------------------------------------------------------------------------ | | `goodlogin` / `goodpassword` | Truv Bank OAuth or Truv Bank non-OAuth | Complete asset data — accounts, balances, transactions, derived income sources | For the underlying JSON shape, see the [User Assets Report object](/api-reference/user-asset-verification-reports/object). **Sample response** — captured from a live sandbox order. Expand a credential to see the response it returns. The complete assets payload a successful bank connection returns: every connected `account` with balances and owners, plus the bank income engine's `bank_income_sources` (income classification, cadence, forecasted monthly income, and a sample of the monthly `historical_summary`). Captured from a live sandbox order; per-month transaction arrays are truncated for length. ```json theme={null} { "id": "aab7df0b814c4b5e9f8cde4b8a9d094a", "product_type": "assets", "status": "sent", "link_id": "7e625245547044ff9ab460048b8096ea", "data_source": "financial_accounts", "provider": { "logo_url": "https://d1uvo9h6rsmxet.cloudfront.net/provider_logos/truv_bank.svg", "id": "truv_bank", "name": "Truv Bank (non-oAuth)" }, "is_suspicious": false, "last_task_status": "done", "accounts": [ { "id": "56140694b55c4f83ac6e8abc1148c320", "type": "CHECKING", "subtype": null, "mask": "0685", "balance": "49635.00", "owners": [ { "full_name": "John Doe" } ] }, { "id": "7ba7a2aa0cb843f0906865515c02dd10", "type": "INVESTMENT", "subtype": null, "mask": "9950", "balance": "1000.00", "owners": [ { "full_name": "John Doe" } ] }, { "id": "cc4c1b7c79c243afb2477d192dfd2ad1", "type": "SAVINGS", "subtype": null, "mask": "3248", "balance": "5000.00", "owners": [ { "full_name": "John Doe" } ] } ], "bank_income_sources": [ { "start_date": "2024-06-18", "end_date": "2026-06-17", "account_id": "56140694b55c4f83ac6e8abc1148c320", "income_description": "doordashinc", "income_category": "GIG_ECONOMY", "pay_frequency": "BW", "next_payment_date": "2026-06-29", "total_amount": "29122.79", "iso_currency_code": "USD", "transaction_count": 52, "historical_summary": [ { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "1125.28", "iso_currency_code": "USD", "transactions": [ { "amount": "528.79", "iso_currency_code": "USD", "date": "2026-06-15", "description": "doordashinc visa direct", "pending": false, "transaction_id": "45539b6e22814796924a71a15e855f6c", "check_number": null }, { "amount": "596.49", "iso_currency_code": "USD", "date": "2026-06-01", "description": "doordashinc visa direct", "pending": false, "transaction_id": "9c7abe1751dd426bbf109aa1c410d3cf", "check_number": null } ] }, { "start_date": "2026-05-01", "end_date": "2026-05-31", "total_amount": "1085.51", "iso_currency_code": "USD", "transactions": [ { "amount": "556.72", "iso_currency_code": "USD", "date": "2026-05-18", "description": "doordashinc visa direct", "pending": false, "transaction_id": "bbe1ad37001548d8a2f2a25c650f8e05", "check_number": null }, { "amount": "528.79", "iso_currency_code": "USD", "date": "2026-05-04", "description": "doordashinc visa direct", "pending": false, "transaction_id": "4b7a7e2f764b4f6a86f4580ba9da273d", "check_number": null } ] }, "...and 22 more monthly periods (omitted for brevity)" ], "historical_average_monthly_income": "1217.28", "historical_average_monthly_gross_income": "1217.28", "forecasted_average_monthly_income": "1217.28", "avg_deposit_amount": "556.11", "avg_gross_deposit_amount": "556.11", "employer": { "id": "d7e91477807442c8ac6d6a818d163ece", "name": "DoorDash" } } ] } ``` *** ## Credential scenarios Every credential here connects through **Truv Bank OAuth** or **Truv Bank non-OAuth** and returns the same shape as [Quick start](#quick-start) — the **Sample responses** panels show only the fields that differ. Each credential string is a stable test-case identifier you can cite in tickets. ### Account types | Scenario | Credential | Account types returned | | -------- | --------------------------------------------- | ------------------------------------- | | `VOA-A1` | `goodlogin.checking` / `goodpassword` | Checking | | `VOA-A2` | `goodlogin.checking.savings` / `goodpassword` | Checking, Savings | | `VOA-A3` | `goodlogin.card` / `goodpassword` | Checking, Savings | | `VOA-A4` | `goodlogin.inv` / `goodpassword` | Investment | | `VOA-A5` | `goodlogin.all` / `goodpassword` | Checking, Savings, Investment | | `VOA-A6` | `sit` / `goodpassword` | Certificate of Deposit, Stocks, Bonds | Use these to validate your handling of `accounts[].type` and `accounts[].subtype` across the common shapes. Returns a single Checking account. ```json theme={null} { "accounts": [ { "type": "CHECKING", "subtype": null, "mask": "6447", "balance": "16595.84" } ] } ``` Returns Checking + Savings. ```json theme={null} { "accounts": [ { "type": "SAVINGS", "subtype": null, "mask": "5341", "balance": "12635.78" }, { "type": "CHECKING", "subtype": null, "mask": "6447", "balance": "16595.84" } ] } ``` Returns Checking + Savings. ```json theme={null} { "accounts": [ { "type": "SAVINGS", "subtype": null, "mask": "5341", "balance": "12635.78" }, { "type": "CHECKING", "subtype": null, "mask": "6447", "balance": "16595.84" } ] } ``` Returns an Investment account (subtype `IRA`) with balances populated and no transactions. ```json theme={null} { "accounts": [ { "type": "INVESTMENT", "subtype": "IRA", "mask": "0244", "balance": "10398.52" } ] } ``` Returns Investment + Savings + Checking across multiple `account_id` values. ```json theme={null} { "accounts": [ { "type": "INVESTMENT", "subtype": "IRA", "mask": "0244", "balance": "10398.52" }, { "type": "SAVINGS", "subtype": null, "mask": "5341", "balance": "12635.78" }, { "type": "CHECKING", "subtype": null, "mask": "6447", "balance": "16595.84" } ] } ``` Returns a Certificate of Deposit (Savings subtype `CERTIFICATE_OF_DEPOSIT`) and a Brokerage investment account alongside Checking. ```json theme={null} { "accounts": [ { "type": "INVESTMENT", "subtype": "BROKERAGE", "mask": "2422", "balance": "56780.00" }, { "type": "SAVINGS", "subtype": "CERTIFICATE_OF_DEPOSIT", "mask": "2112", "balance": "7500.00" }, { "type": "CHECKING", "subtype": null, "mask": "6789", "balance": "14500.00" } ] } ``` `goodlogin.all` returns income sources spread across multiple `account_id` values (not all attributed to one account). Use this credential when you need to validate handling of the same applicant having recurring activity on more than one connected account — for example, paycheck deposit on checking + gig income on a separate savings account. ### Bank income sources Each credential drives the bank income engine's `income_category` classification. Use these to validate your decisioning across the categories Truv classifies bank deposits into. | Scenario | Credential | `income_category` returned | | --------- | ----------------------------------------- | -------------------------- | | `VOA-I1` | `goodlogin.gig` / `goodpassword` | `GIG_ECONOMY` | | `VOA-I2` | `goodlogin.gov.employee` / `goodpassword` | `GOVERNMENT_EMPLOYMENT` | | `VOA-I3` | `goodlogin.ewa` / `goodpassword` | `EWA_PAYROLL` | | `VOA-I4` | `goodlogin.retirement` / `goodpassword` | `RETIREMENT` | | `VOA-I5` | `goodlogin.rental` / `goodpassword` | `RENTAL` | | `VOA-I6` | `goodlogin.unemployment` / `goodpassword` | `UNEMPLOYMENT` | | `VOA-I7` | `goodlogin.gov.benefits` / `goodpassword` | `GOVERNMENT_BENEFITS` | | `VOA-I8` | `goodlogin.benefits` / `goodpassword` | `PRIVATE_BENEFITS` | | `VOA-I9` | `goodlogin.tax.credits` / `goodpassword` | `PAYCHECK` | | `VOA-I10` | `goodlogin.interest` / `goodpassword` | `PAYCHECK` | Bank income classified as `GIG_ECONOMY` (DoorDash deposits). ```json theme={null} { "bank_income_sources": [ { "income_category": "GIG_ECONOMY", "income_description": "DoorDash, Inc.", "pay_frequency": "SM", "total_amount": "17436.56", "transaction_count": 34, "next_payment_date": "2026-07-01", "historical_average_monthly_income": "1025.68", "forecasted_average_monthly_income": "1025.68", "avg_deposit_amount": "512.84", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "1025.68", "iso_currency_code": "USD", "transactions": [ { "amount": "512.84", "iso_currency_code": "USD", "date": "2026-06-15", "description": "DoorDash, Inc. DES:DoorDash, ID:XXXXXXXXXX INDN:XXXXXXXXXX CO ID:XXXXXXXXXX CCD", "pending": false, "transaction_id": "0615692c9b60429c9a8ee019115b17ab", "check_number": null }, { "amount": "512.84", "iso_currency_code": "USD", "date": "2026-06-01", "description": "DoorDash, Inc. DES:DoorDash, ID:XXXXXXXXXX INDN:XXXXXXXXXX CO ID:XXXXXXXXXX CCD", "pending": false, "transaction_id": "3daa89b553df4a0f9c0081fd4b46af08", "check_number": null } ] } } ] } ``` Bank income classified as `GOVERNMENT_EMPLOYMENT`. ```json theme={null} { "bank_income_sources": [ { "income_category": "GOVERNMENT_EMPLOYMENT", "income_description": "U.S. Department Of The Treasury", "pay_frequency": null, "total_amount": "234169.38", "transaction_count": 53, "next_payment_date": null, "historical_average_monthly_income": "9585.64", "forecasted_average_monthly_income": null, "avg_deposit_amount": "4747.50", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "5393.77", "iso_currency_code": "USD", "transactions": [ { "amount": "5393.77", "iso_currency_code": "USD", "date": "2026-06-02", "description": "Salary/Regular Income from U.S. Department Of The Treasury", "pending": false, "transaction_id": "25fecd1582ec4dab85a83e5915b95958", "check_number": null } ] } } ] } ``` Returns `EWA_PAYROLL` (earned wage access) alongside a `PAYCHECK` source. ```json theme={null} { "bank_income_sources": [ { "income_category": "EWA_PAYROLL", "income_description": "PAYACTIV JOHN DOE", "pay_frequency": null, "total_amount": "11126.00", "transaction_count": 31, "next_payment_date": null, "historical_average_monthly_income": "1022.50", "forecasted_average_monthly_income": null, "avg_deposit_amount": "433.54", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-03-01", "end_date": "2026-03-31", "total_amount": "676.00", "iso_currency_code": "USD", "transactions": [ { "amount": "211.00", "iso_currency_code": "USD", "date": "2026-03-16", "description": "UKG26322 PAYACTIV 8328 JOHN DOE ACH CREDIT", "pending": false, "transaction_id": "8a7d14367e3d4b9d9c52fdaa6471776a", "check_number": null }, { "amount": "465.00", "iso_currency_code": "USD", "date": "2026-03-09", "description": "UKG26244 PAYACTIV 0667 JOHN DOE ACH CREDIT", "pending": false, "transaction_id": "2accd056c1bc46febf18d60397415629", "check_number": null } ] } }, { "income_category": "PAYCHECK", "income_description": "Home Depot Payroll", "pay_frequency": "BW", "total_amount": "69047.68", "transaction_count": 52, "next_payment_date": "2026-06-29", "historical_average_monthly_income": "2886.61", "forecasted_average_monthly_income": "2886.61", "avg_deposit_amount": "1327.84", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "2655.68", "iso_currency_code": "USD", "transactions": [ { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-15", "description": "Home Depot Payroll", "pending": false, "transaction_id": "cd1c90f41e104c67b23adff277ade255", "check_number": null }, { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-01", "description": "Home Depot Payroll", "pending": false, "transaction_id": "acfe1ca8f11241a8951a24612eb78460", "check_number": null } ] } } ] } ``` Bank income classified as `RETIREMENT`. ```json theme={null} { "bank_income_sources": [ { "income_category": "RETIREMENT", "income_description": "OHIO PERS RETIREMENT", "pay_frequency": "M", "total_amount": "91529.03", "transaction_count": 23, "next_payment_date": "2026-06-01", "historical_average_monthly_income": "3979.52", "forecasted_average_monthly_income": "3979.52", "avg_deposit_amount": "4051.00", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-04-01", "end_date": "2026-04-30", "total_amount": "4108.61", "iso_currency_code": "USD", "transactions": [ { "amount": "4108.61", "iso_currency_code": "USD", "date": "2026-04-30", "description": "OHIO PERS RETIREMENT PPD ID: 1110111111", "pending": false, "transaction_id": "8b82b8b53d8540168662e78b2bee70b7", "check_number": null } ] } } ] } ``` Returns a `RENTAL` source alongside a `PAYCHECK` source. ```json theme={null} { "bank_income_sources": [ { "income_category": "RENTAL", "income_description": "AIRBNB", "pay_frequency": "SM", "total_amount": "54687.33", "transaction_count": 29, "next_payment_date": "2026-07-01", "historical_average_monthly_income": "3771.54", "forecasted_average_monthly_income": "3771.54", "avg_deposit_amount": "1885.77", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "3771.54", "iso_currency_code": "USD", "transactions": [ { "amount": "1885.77", "iso_currency_code": "USD", "date": "2026-06-15", "description": "AIRBNB 4977 DES:AIRBNB ID:XXXXXXXXXX INDN:XXXXXXXXXX CO ID:XXXXXXXXXX PPD PMT INFO:TRN*1*G-XXXXXXXXXXXXX", "pending": false, "transaction_id": "466ba8f84ad4465daa14e52c8d921900", "check_number": null }, { "amount": "1885.77", "iso_currency_code": "USD", "date": "2026-06-01", "description": "AIRBNB 4977 DES:AIRBNB ID:XXXXXXXXXX INDN:XXXXXXXXXX CO ID:XXXXXXXXXX PPD PMT INFO:TRN*1*G-XXXXXXXXXXXXX", "pending": false, "transaction_id": "6bacc3d5b5714fd49e8720e0fa25d603", "check_number": null } ] } }, { "income_category": "PAYCHECK", "income_description": "Home Depot Payroll", "pay_frequency": "BW", "total_amount": "69047.68", "transaction_count": 52, "next_payment_date": "2026-06-29", "historical_average_monthly_income": "2886.61", "forecasted_average_monthly_income": "2886.61", "avg_deposit_amount": "1327.84", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "2655.68", "iso_currency_code": "USD", "transactions": [ { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-15", "description": "Home Depot Payroll", "pending": false, "transaction_id": "e80b93c972aa4bef984eded598148a9e", "check_number": null }, { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-01", "description": "Home Depot Payroll", "pending": false, "transaction_id": "ea17a96d5b1747aa94d8c4b6d0090735", "check_number": null } ] } } ] } ``` Bank income classified as `UNEMPLOYMENT`. ```json theme={null} { "bank_income_sources": [ { "income_category": "UNEMPLOYMENT", "income_description": "MA DUA MA UI TAX", "pay_frequency": null, "total_amount": "36039.00", "transaction_count": 41, "next_payment_date": null, "historical_average_monthly_income": "2637.00", "forecasted_average_monthly_income": null, "avg_deposit_amount": "879.00", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "1758.00", "iso_currency_code": "USD", "transactions": [ { "amount": "879.00", "iso_currency_code": "USD", "date": "2026-06-11", "description": "MA DUA MA UI TAX", "pending": false, "transaction_id": "9d95978fffbd477897d74a5109acbc07", "check_number": null }, { "amount": "879.00", "iso_currency_code": "USD", "date": "2026-06-06", "description": "MA DUA MA UI TAX", "pending": false, "transaction_id": "6d63ecaa25ec464ca3dd4da49509219d", "check_number": null } ] } } ] } ``` Bank income classified as `GOVERNMENT_BENEFITS`. ```json theme={null} { "bank_income_sources": [ { "income_category": "GOVERNMENT_BENEFITS", "income_description": "Ssi Treas 310", "pay_frequency": "M", "total_amount": "18373.00", "transaction_count": 19, "next_payment_date": "2026-06-30", "historical_average_monthly_income": "967.00", "forecasted_average_monthly_income": "967.00", "avg_deposit_amount": "967.00", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-05-01", "end_date": "2026-05-31", "total_amount": "967.00", "iso_currency_code": "USD", "transactions": [ { "amount": "967.00", "iso_currency_code": "USD", "date": "2026-05-25", "description": "Ssi Treas 310, Xxsupp Sec", "pending": false, "transaction_id": "a98d8c4fdc4840a6b8f97fa38e745948", "check_number": null } ] } } ] } ``` Bank income classified as `PRIVATE_BENEFITS`. ```json theme={null} { "bank_income_sources": [ { "income_category": "PRIVATE_BENEFITS", "income_description": "WORKERS COMP PAYABLES", "pay_frequency": "SM", "total_amount": "18720.72", "transaction_count": 27, "next_payment_date": "2026-07-01", "historical_average_monthly_income": "1386.72", "forecasted_average_monthly_income": "1386.72", "avg_deposit_amount": "693.36", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "693.36", "iso_currency_code": "USD", "transactions": [ { "amount": "693.36", "iso_currency_code": "USD", "date": "2026-06-05", "description": "WORKERS COMP PAYABLES 010111 1011111 DOE, JOHN", "pending": false, "transaction_id": "106ebf3600fd4f1cbd66abeaae918354", "check_number": null } ] } } ] } ``` The detected income source classifies as `PAYCHECK`. ```json theme={null} { "bank_income_sources": [ { "income_category": "PAYCHECK", "income_description": "Home Depot Payroll", "pay_frequency": "BW", "total_amount": "69047.68", "transaction_count": 52, "next_payment_date": "2026-06-29", "historical_average_monthly_income": "2886.61", "forecasted_average_monthly_income": "2886.61", "avg_deposit_amount": "1327.84", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "2655.68", "iso_currency_code": "USD", "transactions": [ { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-15", "description": "Home Depot Payroll", "pending": false, "transaction_id": "2d7832e4d663445cb4b93dbed6ee8316", "check_number": null }, { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-01", "description": "Home Depot Payroll", "pending": false, "transaction_id": "aa5557d4a3ab4274a07fdd3d45b87d22", "check_number": null } ] } } ] } ``` The detected income source classifies as `PAYCHECK`. ```json theme={null} { "bank_income_sources": [ { "income_category": "PAYCHECK", "income_description": "Home Depot Payroll", "pay_frequency": "BW", "total_amount": "69047.68", "transaction_count": 52, "next_payment_date": "2026-06-29", "historical_average_monthly_income": "2886.61", "forecasted_average_monthly_income": "2886.61", "avg_deposit_amount": "1327.84", "iso_currency_code": "USD", "historical_summary_sample": { "start_date": "2026-06-01", "end_date": "2026-06-30", "total_amount": "2655.68", "iso_currency_code": "USD", "transactions": [ { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-15", "description": "Home Depot Payroll", "pending": false, "transaction_id": "8cf18029ee824f7fa2c9ee392efe442a", "check_number": null }, { "amount": "1327.84", "iso_currency_code": "USD", "date": "2026-06-01", "description": "Home Depot Payroll", "pending": false, "transaction_id": "a1cffb149686473fa2b80b59a04c8811", "check_number": null } ] } } ] } ``` The full `income_category` enum includes `PAYCHECK`, `GOVERNMENT_EMPLOYMENT`, `EWA_PAYROLL`, `GIG_ECONOMY`, `RETIREMENT`, `RENTAL`, `UNEMPLOYMENT`, `GOVERNMENT_BENEFITS`, `PRIVATE_BENEFITS`, `P2P_TRANSFER`, `TAX_CREDITS`, `CASH_OR_CHECK`, `INTEREST`, `INVESTMENT`, and `OTHER`. If your enum validation is strict, allow all of these values. ### Risk profiles Combine the asset credential with these passwords to simulate different consumer risk profiles. Use them to test downstream decisioning that consumes Truv's asset and bank income data. | Scenario | Credential | What it returns | | -------- | -------------------------- | ------------------------------------------------------- | | `VOA-R1` | `goodlogin` / `good_asset` | 30 days of data — use to test recency-based decisioning | | `VOA-R2` | `goodlogin` / `low_risk` | Low-risk consumer profile | | `VOA-R3` | `goodlogin` / `high_risk` | High-risk consumer profile | Recency-limited profile for testing recency-based decisioning. ```json theme={null} { "accounts": [ { "type": "CHECKING", "mask": "8773", "balance": "2283.99" }, { "type": "CHECKING", "mask": "0685", "balance": "5410.36" } ], "bank_income_sources_count": 0, "income_categories": [] } ``` Low-risk consumer profile. ```json theme={null} { "accounts": [ { "type": "SAVINGS", "mask": "0684", "balance": "15000.00" }, { "type": "CHECKING", "mask": "0685", "balance": "6000.00" } ], "bank_income_sources_count": 2, "income_categories": [ "OTHER", "PAYCHECK" ] } ``` High-risk consumer profile. ```json theme={null} { "accounts": [ { "type": "CHECKING", "mask": "0685", "balance": "0.00" }, { "type": "CHECKING", "mask": "8773", "balance": "0.00" } ], "bank_income_sources_count": 1, "income_categories": [ "PAYCHECK" ] } ``` *** ## Error scenarios VOA shares the universal authentication-error credentials. Use these to test your error handling and retry UX. | Scenario | Credential | Task status | | -------- | ------------------------------- | ----------------------------------- | | `VOA-X1` | `goodlogin` / `no_data` | `no_data` | | `VOA-X2` | `goodlogin` / `mfa` | `mfa` → `done` (enter code `12345`) | | `VOA-X3` | `error.user` / `login_error` | `login_error` | | `VOA-X4` | `error.user` / `account_locked` | `account_locked` | | `VOA-X5` | `error.user` / `unavailable` | `unavailable` | | `VOA-X6` | `error.user` / `error` | `error` | See [Task lifecycle](/api-reference/tasks/lifecycle) for the full status reference. *** ## Recurring transactions endpoint The [recurring transactions endpoint](/api-reference/recurring-transactions/applicant-recurring-transactions) (`GET /v1/users/{user_id}/transactions/recurring/`) runs on top of the same assets connection — once an applicant has completed a VOA verification, you can call the endpoint to retrieve detected recurring inflows and outflows on the connected accounts. | Credential | Returns | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `goodlogin` / `goodpassword` | A single recurring inflow (gig income), 53 historical transactions, one `account_id`. Suitable for basic happy-path testing. | | `goodlogin.all` / `goodpassword` | Multiple recurring inflow sources distributed across multiple `account_id` values — paycheck and gig income land on different accounts. Use this when validating multi-account aggregation. | **Sandbox seeds recurring inflows only.** Sandbox responses populate the `inflows[]` array; the `outflows[]` array (subscriptions, recurring expenses, loan payments) returns empty across every documented login variant today. Validate your inflow-handling logic end to end in sandbox, but plan to test outflow handling against production data or a controlled test in your production environment. We're tracking this gap internally. The endpoint requires the `is_recurring_transactions_detection_enabled` UWS flag to be on for your account. If you call it and receive empty arrays for both inflows and outflows with `goodlogin` / `goodpassword`, contact [support@truv.com](mailto:support@truv.com) to confirm the flag is enabled on your sandbox. For the full endpoint contract — `source_id` vs `account_id`, status semantics, historical transactions per source — see the [Recurring Transactions API reference](/api-reference/recurring-transactions/applicant-recurring-transactions). *** ## Accounts without transactions Sandbox connections occasionally return bank accounts that have no transactions on them yet — a recently opened checking account, an investment account that hasn't seen activity in the lookback window, etc. This is a valid scenario, not an error. To confirm your integration handles it: pass `goodlogin.inv` / `goodpassword` and inspect the response. The investment account is returned with balance fields populated but an empty or sparse `transactions[]` array. Validate that your decisioning logic treats `transactions: []` as a real signal (e.g., "this account exists but has no income evidence") rather than treating it as a failed connection. *** ## Sample VOA reports Truv's VOA report format is the same whether the report is consumed by a non-GSE lender or submitted to Fannie Mae DU / Freddie Mac LPA. The PDFs linked from the GSE pages are the canonical sample VOA report references today. Sample VOA PDFs tied to Fannie Mae D1C borrower scenarios Sample VOA PDFs tied to Freddie Mac AIM borrower scenarios *** ## Webhook events When testing VOA end to end, your webhook endpoint receives a `task-status-updated` event for the financial-accounts task plus per-resource events as accounts, transactions, and bank income are extracted. ```json theme={null} { "webhook_id": "609a82aab21e4d9ba2569f35e9e8f26a", "event_type": "task-status-updated", "updated_at": "2026-04-26T13:02:20.369267+00:00", "task_id": "67f2924530564282bbaf6d27655e94a4", "link_id": "64f8e374949c4b769706028022626bf1", "product": "assets", "tracking_info": "your-applicant-id", "status": "done" } ``` Other events you may receive during a VOA flow include `bank-accounts-created`, `transactions-created`, and (for derived bank income) updates that surface through the standard task lifecycle. See [Webhook Events](/api-reference/webhook-events) for the full catalog. *** ## Next steps Product overview for transactions and bank income Integration guide for bank-derived income AIM-VOA submission flow with Freddie Mac JSON schema for the VOA report # Direct Deposit Switch Testing Source: https://docs.truv.com/developers/testing/direct-deposit-switch Sandbox credentials, allocation scenarios, and webhook flow for DDS integrations Test Direct Deposit Switch (DDS) flows in sandbox using the credentials below. Pass `product_type: deposit_switch` on the bridge token along with the `account` block, and search for **Truv Payroll Provider** in Truv Bridge. For additional login fields, use **Phone:** `(111)111-1111` and **Email:** `goodlogin@domain.com`. The `account` block is functionally required at bridge-token creation for `deposit_switch`. The widget writes the new allotment into the payroll provider during the customer's authenticated session, so the destination must be in hand before Bridge launches. See [DDS implementation](/banking/integration/dds#configure-account-details) for the full constraint set. *** ## Quick start Use `goodlogin` / `goodpassword` against Truv Payroll Provider with this bridge token payload: ```bash theme={null} curl --request POST \ --url https://prod.truv.com/v1/users/{user_id}/tokens/ \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' \ --header 'content-type: application/json' \ --data '{ "product_type": "deposit_switch", "tracking_info": "your-applicant-id", "account": { "account_number": "16002600", "routing_number": "123456789", "bank_name": "Your Bank", "account_type": "checking", "deposit_type": "entire" } }' ``` A successful switch transitions the task through `parse` → `full_parse` → `switch_deposit` → `done`. Retrieve the confirmation with [GET /v1/users/\{user\_id}/deposit\_switch/report/](/api-reference/dds-reports/dds-report-retrieve). *** ## Allocation type scenarios DDS supports three allocation types. Each behaves differently on the payroll-provider side, so test all three. | Scenario | `deposit_type` | `deposit_value` | Behavior | | -------- | -------------- | ------------------------------- | ----------------------------------------------------- | | `DDS-A1` | `entire` | Not required | Routes the entire paycheck to the destination account | | `DDS-A2` | `amount` | Dollar amount (e.g. `"500.00"`) | Routes a fixed dollar amount per pay cycle | | `DDS-A3` | `percent` | Percentage (e.g. `"50"`) | Routes a percentage of the paycheck | Sample DDS report response after a successful switch: ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "done", "finished_at": "2026-05-15T11:30:00Z", "completed_at": "2026-05-15T11:30:00Z", "access_token": "48427a36d43c4d5aa6324bc06c692456", "tracking_info": "your-applicant-id", "deposit_details": { "account_number": "16002600", "account_type": "checking", "routing_number": "123456789", "bank_name": "Your Bank", "deposit_type": "percent", "deposit_value": "50.00" }, "initial_accounts": [ { "account_number": "16001234", "routing_number": "55999876" } ] } ``` *** ## Error scenarios DDS surfaces a number of payroll-provider-side validation failures as `config_error`. The most common ones to test: | Scenario | Credential / setup | Task status | What it simulates | | -------- | ----------------------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DDS-X1` | `goodlogin` / `goodpassword`, customer already at 100% allocation | `config_error` | Payroll provider rejects the new allotment because total distribution already equals 100%. The customer must reduce or remove an existing allotment before retry. | | `DDS-X2` | `error.user` / `config_error` | `config_error` | Organization ID configuration failure | | `DDS-X3` | `error.user` / `login_error` | `login_error` | Incorrect credentials | | `DDS-X4` | `error.user` / `mfa_error` | `mfa_error` | MFA verification failed | | `DDS-X5` | `error.user` / `account_locked` | `account_locked` | Account locked by provider | For the "already at 100%" scenario, Truv surfaces the payroll provider's exact rejection message in the task `error_message` field. Render that message back to the customer rather than a generic error — it tells them exactly which existing allotment to adjust. See [Task lifecycle](/api-reference/tasks/lifecycle) for the full status reference. *** ## Already-connected employers When the same applicant (same `external_user_id`) attempts a second connection to the same employer they've already verified at, Truv blocks the duplicate by default — controlled by the `is_same_account_connection_restricted` UWS flag, which is **on** for most accounts. In Bridge, the applicant sees an **"Already connected"** screen with an option to update the existing connection rather than creating a new one. From the API side, this means: * Creating a new order with the same `external_user_id` and routing the applicant back through Bridge for the same employer does **not** produce a second link or a second `switch_deposit` task. * To programmatically refresh a DDS connection's data (without the applicant re-authenticating), use the [refresh order endpoint](/api-reference/orders/orders_create_refresh_order) on the original order. * To re-allocate to a **different** destination account for the same applicant + same employer, you'll need to either disable the restriction on your account (contact [support@truv.com](mailto:support@truv.com)) or update the existing allotment via the same provider session. For QA test plans that exercise "applicant reconnects after disconnecting": use a fresh `external_user_id` per test run, since the same `external_user_id` will be treated as a returning user. *** ## Webhook events DDS includes one status that other products don't: `switch_deposit`. This indicates Truv is actively writing the new allotment into the payroll provider after parsing completed. ```json theme={null} { "webhook_id": "609a82aab21e4d9ba2569f35e9e8f26a", "event_type": "task-status-updated", "updated_at": "2026-04-26T13:02:20.369267+00:00", "task_id": "67f2924530564282bbaf6d27655e94a4", "link_id": "64f8e374949c4b769706028022626bf1", "product": "deposit_switch", "tracking_info": "your-applicant-id", "status": "switch_deposit" } ``` The terminal event arrives with `status: done` (or `status: config_error` if the switch failed at the payroll-provider validation step). *** ## Behavior and limitations ### No PDF report Unlike VOIE and VOA, DDS does not generate a downloadable PDF report. The deliverable is the JSON response from the [DDS Report endpoint](/api-reference/dds-reports/dds-report-retrieve), which confirms the destination Truv wrote and the customer's pre-existing accounts. If you persist switch evidence for audit, store the JSON response alongside your application record at the time `task-status-updated` fires with `status: done`. ### Destination matching When Truv writes the allotment, the match key against existing direct deposit rows is `account_number + routing_number` (with a last-4 fallback when the payroll provider masks the account number). Same destination is a no-op or in-place update; different destination is an insert. There is no source-of-origin marker — Truv cannot distinguish a row it wrote previously from one the customer created manually. See [DDS destination matching](/banking/integration/dds#configure-account-details) for the full match rules. *** ## Next steps Full implementation guide with allocation patterns and constraints Mint a deposit\_switch bridge token Retrieve the switch confirmation Handle task-status-updated through switch\_deposit # GSE Testing Source: https://docs.truv.com/developers/testing/gse-testing Sandbox borrower accounts and pre-generated report IDs for testing Fannie Mae Day 1 Certainty and Freddie Mac AIM submissions Validate your GSE submission flow against Fannie Mae's Desktop Underwriter (DU) and Freddie Mac's Loan Product Advisor (LPA) using the sandbox credentials and report IDs below. Each credential maps to a specific borrower profile, and each report ID maps to a pre-generated Truv report you can submit directly to DU or LPA without re-running the borrower through Bridge. For non-GSE VOIE and VOA testing, see [Income & Employment Testing](/developers/testing/income-employment) and [Assets Testing](/developers/testing/assets). For the underlying D1C and AIM product context, see [Day 1 Certainty (D1C)](/mortgage/d1c-aim/fannie-mae) and [Asset and Income Modeler (AIM)](/mortgage/d1c-aim/freddie-mac). For additional login fields used by any test credential, use **Phone:** `(111)111-1111` and **Email:** `goodlogin@domain.com`. *** ## Fannie Mae (Day 1 Certainty) ### Borrower test accounts Run these usernames against **Truv Payroll Provider** in Truv Bridge to generate a fresh VOIE report for the borrower profile. Each maps to a sample PDF showing the expected output. | Username | Password | SSN | Borrower | Sample report | | ------------------- | -------------- | ------------- | --------------- | ------------------------------------------------------------------------------------ | | `firsttimeborrower` | `goodpassword` | `991-91-9991` | Alice Firstimer | [PDF](https://truv.com/wp-content/uploads/2025/01/report-firsttimeborrower.pdf?v=1) | | `fannie-test.case4` | `goodpassword` | `666-00-6666` | Pitt Rock | [PDF](https://truv.com/wp-content/uploads/2025/01/report-fannie-test.case4_.pdf?v=1) | | `fannie-test.case5` | `goodpassword` | `999-60-6666` | Suzi Builder | [PDF](https://truv.com/wp-content/uploads/2025/01/report-fannie-test.case5_.pdf?v=1) | | `fannie-test.case6` | `goodpassword` | `999-40-5000` | John Homeowner | [PDF](https://truv.com/wp-content/uploads/2025/01/report-fannie-test.case6_.pdf?v=1) | | `fannie-test.case7` | `goodpassword` | `999-42-2345` | Lucky Knowscore | [PDF](https://truv.com/wp-content/uploads/2025/01/report-fannie-test.case7_.pdf?v=1) | ### Pre-generated income and employment report IDs Submit these report IDs directly to Desktop Underwriter — no Bridge run required. DU pulls the VOIE data from Truv using the ID. | `voie_report_id` | SSN | Borrower | Sample report | | ---------------------------------- | ------------- | ---------------- | ---------------------------------------------------------------------------------------------- | | `456bdef4a7e944679c613f03fea436f6` | `999-60-1111` | Homer Loanseeker | [PDF](https://truv.com/wp-content/uploads/2025/07/report-456bdef4a7e944679c613f03fea436f6.pdf) | | `57d2e327e2a5436798519917bf36a958` | `999-00-1147` | Jess Sea | [PDF](https://truv.com/wp-content/uploads/2025/07/report-57d2e327e2a5436798519917bf36a958.pdf) | | `c92799ae5fb541b29c727c35b5433b2f` | `999-00-9066` | Ann Sea | [PDF](https://truv.com/wp-content/uploads/2025/07/report-c92799ae5fb541b29c727c35b5433b2f.pdf) | | `193dba3298c140479172a8129e16c36e` | `999-60-6666` | Suzi Builder | [PDF](https://truv.com/wp-content/uploads/2025/07/report-193dba3298c140479172a8129e16c36e.pdf) | ### Pre-generated assets report IDs Submit these `voa_report_id` values to DU for the assets portion of D1C validation. | `voa_report_id` | SSN | Borrower | Sample report | | ---------------------------------- | ------------- | ------------------ | ---------------------------------------------------------------------------------------------- | | `be953ec913ac4f2b9086529377e087f8` | `999-60-1111` | Homer Loanseeker | [PDF](https://truv.com/wp-content/uploads/2025/07/report-be953ec913ac4f2b9086529377e087f8.pdf) | | `394fe28b784d4f6a96a746e56c575d69` | `999-12-1234` | Patrick Purchaser | [PDF](https://truv.com/wp-content/uploads/2025/07/report-394fe28b784d4f6a96a746e56c575d69.pdf) | | `2a144c7b7af9419692ce6f1661245425` | `999-56-5678` | Lorraine Purchaser | [PDF](https://truv.com/wp-content/uploads/2025/07/report-2a144c7b7af9419692ce6f1661245425.pdf) | | `d3366e56821540f8b00cceafcfdf6944` | `999-60-6666` | Suzi Builder | [PDF](https://truv.com/wp-content/uploads/2025/07/report-d3366e56821540f8b00cceafcfdf6944.pdf) | *** ## Freddie Mac (Asset and Income Modeler) Freddie Mac's AIM uses the same VOIE / VOA report shape as Fannie Mae's D1C — the same `voie_report_id` works for both LPA and DU submissions. The IDs below are pre-generated Freddie-oriented reference cases. ### Pre-generated income and employment report IDs Submit these `voie_report_id` values to LPA for AIM-VOIE assessment. | `voie_report_id` | SSN | Borrower | Sample report | | ---------------------------------- | ------------- | --------------- | ---------------------------------------------------------------------------------------------- | | `5abf3fddc6cd44a38038c0c6bfd4f26f` | `990-50-0005` | Patrick Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-5abf3fddc6cd44a38038c0c6bfd4f26f.pdf) | | `bf23a64ceaf74988b14570a549d0b1c8` | `990-40-0004` | Amy Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-bf23a64ceaf74988b14570a549d0b1c8.pdf) | | `57868adf572f46fb989adf16a30c1ebd` | `990-70-0007` | Suzi Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-57868adf572f46fb989adf16a30c1ebd.pdf) | | `1a531ae648254ec3a27c4e259ab507f3` | `990-11-0011` | Mom Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-1a531ae648254ec3a27c4e259ab507f3.pdf) | | `776f4e58b115428f94776c884c073d4d` | `990-08-0008` | Alice Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-776f4e58b115428f94776c884c073d4d.pdf) | | `729851aad6404bf9b30248a11445fec5` | `990-30-0003` | Andy Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-729851aad6404bf9b30248a11445fec5.pdf) | ### Pre-generated assets report IDs Submit these `voa_report_id` values to LPA for AIM-VOA assessment. | `voa_report_id` | SSN | Borrower | Sample report | | ---------------------------------- | ------------- | ------------- | ---------------------------------------------------------------------------------------------- | | `b8aa127afb1246428f0c8868c863080b` | `990-80-0008` | Alice Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-b8aa127afb1246428f0c8868c863080b.pdf) | | `4f6bfd8bdc6645f199408fd2a35213c4` | `991-10-0011` | Mom Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-4f6bfd8bdc6645f199408fd2a35213c4.pdf) | | `cb893b4564f949bcb20eca3b05c547af` | `991-00-0010` | Dad Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-cb893b4564f949bcb20eca3b05c547af.pdf) | | `415d91bd02a64954a15f254a8b1bb5b5` | `990-20-0002` | Mary Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-415d91bd02a64954a15f254a8b1bb5b5.pdf) | | `668a2ff8101f420e94f0b04c5ada6337` | `990-10-0001` | John Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-668a2ff8101f420e94f0b04c5ada6337.pdf) | | `36d0a637117041c098ee39b8d8f364f1` | `990-70-0007` | Suzi Freddie | [PDF](https://truv.com/wp-content/uploads/2025/07/report-36d0a637117041c098ee39b8d8f364f1.pdf) | *** ## Retrieving a fresh report ID If you generated a new VOIE or VOA report by running a borrower through Bridge against the sandbox accounts above, retrieve the report ID before submitting to DU or LPA. **From an Embedded Order:** ```bash theme={null} curl https://prod.truv.com/v1/orders/{order_id}/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" ``` The response includes `voie_report_id` and `voa_report_id`. **From a Bridge token implementation:** ```bash theme={null} # VOIE curl https://prod.truv.com/v1/users/{user_id}/reports/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" # VOA curl https://prod.truv.com/v1/users/{user_id}/assets/reports/ \ -H "X-Access-Client-Id: YOUR_TRUV_CLIENT_ID" \ -H "X-Access-Secret: YOUR_TRUV_CLIENT_SECRET" ``` To pull the rendered PDF for either, append `?fmt=pdf` to the report retrieval URL (or `?fmt=json` for the structured response). Ensure the borrower has completed every requested verification (income, employment, assets) before submitting the report ID. Partial completions produce partial DU and LPA validation. *** ## Validation checklist Use the latest `voie_report_id` and `voa_report_id` for the borrower. Refreshed data creates new IDs — old IDs are not re-validated by the GSE. For [ICE Encompass](/mortgage/integration/ice-encompass) clients, confirm `GSEVENDOR.X50` (Fannie VOIE), `GSEVENDOR.X37` / `GSEVENDOR.X38` (Fannie VOA), and `GSEVENDOR.X43` / `GSEVENDOR.X44` (Freddie VOA) are populated before submission. Submit the report ID and validate the response — DU Findings for Day 1 Certainty eligibility, LPA Feedback for AIM assessment. Capture the GSE response against each test case for your underwriting QA evidence. *** ## Common issues **Possible causes:** * Submitted an outdated report ID (a refresh produced a newer one). * Borrower verification was partial — VOIE missing, VOA missing, or neither has reached `done`. * Vendor ID isn't set to `Truv` in your LOS or DU/LPA submission. **Solution:** Pull the freshest `voie_report_id` and `voa_report_id` directly from `GET /v1/orders/{order_id}/` and re-submit. Confirm the order shows `status: done` for the relevant products first. **Possible causes:** * Loan profile doesn't meet D1C criteria. * Income type isn't covered by D1C rep and warranty relief. * Data age requirements aren't met (D1C has free re-verifications for 90 days after the initial report). **Solution:** Review D1C eligibility for your loan type on the [Fannie Mae Desktop Underwriter page](https://singlefamily.fanniemae.com/applications-technology/desktop-underwriter). **Possible causes:** * Report IDs written into the wrong `GSEVENDOR` field. * Borrower and coborrower IDs combined incorrectly — the Fannie VOIE field expects `borrower_id,coborrower_id` comma-separated; the VOA fields are split into separate borrower/coborrower fields. **Solution:** Cross-check the field mapping against the [Day 1 Certainty page](/mortgage/d1c-aim/fannie-mae#integrate-with-encompass) and the [AIM page](/mortgage/d1c-aim/freddie-mac#integrate-with-encompass). *** ## Next steps Fannie Mae Desktop Underwriter integration Freddie Mac Loan Product Advisor integration Report retrieval patterns and Encompass mappings Pre-production validation # Income & Employment Testing Source: https://docs.truv.com/developers/testing/income-employment Sandbox credentials, scenarios, and sample reports for VOIE and VOE integrations Test Income & Employment (VOIE) and Employment History (VOE) flows in sandbox using the credentials below. VOIE and VOE share the same payroll credentials — only the `product_type` value on the bridge token or order differs (`income` for VOIE, `employment` for VOE). In Truv Bridge, search for the **Truv Payroll Provider** to use any of these credentials. For additional login fields, use **Phone:** `(111)111-1111` and **Email:** `goodlogin@domain.com`. *** ## Quick start Use `goodlogin` / `goodpassword` for the happy path. A successful login returns a complete VOIE report with bi-weekly paystubs, an annual income summary, W-2s, and bank account allocations. | Credential | Provider | Sample report | | ---------------------------- | --------------------- | ------------------------------------------------------------------------------------------ | | `goodlogin` / `goodpassword` | Truv Payroll Provider | [Bi-weekly VOIE PDF](https://truv.com/wp-content/uploads/2025/11/report-goodlogin.pdf?v=1) | For the underlying JSON shape, see the [User Income and Employment Report object](/api-reference/user-income-and-employment-reports/object). **Sample response** — captured from a live sandbox order. Expand a credential to see the response it returns. The complete report a successful payroll connection returns: employment metadata, an annual income summary, per-pay-period statements (one shown; the rest follow the same shape), W-2s, and bank account allocations. Captured from a live sandbox order. Pay-period, earnings, and deduction arrays are truncated here for length. ```json theme={null} { "report_id": "c219d26c1fc7412fb1d0df36a9652600", "created_at": "2026-06-18T01:43:32.553366Z", "completed_at": "2026-06-18T01:43:32.132883Z", "last_task_at": "2026-06-18T01:43:21.714235Z", "links": [ { "id": "ac978e05483e48379a5ec82b556d20a0", "link_id": "f5ef8b9e1eda4640b38069c9e851bc3a", "tracking_info": "8f50b58e35644bb5bff989341eafcdb5", "data_source": "payroll", "provider": "truv", "provider_name": "Truv payroll provider", "employments": [ { "id": "e803dc34b8184c4a8ada449b42fccc65", "job_title": "PR associate", "job_type": "F", "start_date": "2023-01-01", "end_date": null, "external_last_updated": "2026-06-08", "is_active": true, "manager_name": "Jenny McDouglas", "company": { "name": "Acme", "address": { "zip": "98765", "city": "Anytown", "state": "CA", "street": "123 Main Street", "country": "US" }, "phone": "5555551234", "ein": null }, "profile": { "id": "e776ba2b32bf4e32aece51c5878d3cdd", "created_at": "2026-06-18T01:43:24.784615Z", "updated_at": "2026-06-18T01:43:24.784625Z", "first_name": "John", "last_name": "Doe", "full_name": "John Doe", "middle_initials": null, "email": "john.doe@gmail.com", "ssn": "991919991", "date_of_birth": "1992-03-03", "home_address": { "zip": "94062", "city": "Redwood City", "state": "CA", "street": "35 Dry Ridge Rd", "country": "US" } }, "original_hire_date": "2012-02-01", "derived_fields": [], "missing_data_fields": [], "income": "56269.25", "income_unit": "YEARLY", "pay_rate": "2153.60", "pay_frequency": "BW", "statements": [ { "id": "3a5d6a193fc7491689bc62317f4b046f", "pay_date": "2026-06-08", "net_pay": "1629.98", "net_pay_ytd": "19559.76", "gross_pay": "2157.89", "gross_pay_ytd": "25894.68", "bonus": null, "commission": null, "hours": "80.00", "basis_of_pay": "S", "period_start": "2026-05-26", "period_end": "2026-06-08", "regular": "1935.77", "regular_ytd": "23229.24", "bonus_ytd": null, "commission_ytd": null, "overtime": "222.12", "overtime_ytd": "2665.44", "other_pay": null, "other_pay_ytd": null, "earnings": [ { "name": "Regular", "category": "regular", "amount": "1935.77", "rate": "26.92", "units": "71.90" }, { "name": "Double Time", "category": "overtime", "amount": "161.54", "rate": "53.84", "units": "3.00" }, "...and 1 more earnings lines (omitted for brevity)" ], "earnings_ytd": [ { "name": "Regular", "category": "regular", "amount": "23229.24", "rate": "26.92", "units": "862.80" }, { "name": "Double Time", "category": "overtime", "amount": "1938.48", "rate": "53.84", "units": "36.00" }, "...and 1 more earnings ytd lines (omitted for brevity)" ], "deductions": [ { "name": "Federal Income Tax", "amount": "153.63", "category": "federal" }, { "name": "Social Security Tax", "amount": "133.89", "category": "socialsec" }, "...and 4 more deductions lines (omitted for brevity)" ], "deductions_ytd": [ { "name": "Federal Income Tax", "amount": "1843.56", "category": "federal" }, { "name": "Social Security Tax", "amount": "1606.68", "category": "socialsec" }, { "name": "401K Dollars", "amount": "1553.64", "category": "retirement" }, { "name": "CA State Income Tax", "amount": "631.44", "category": "state" }, { "name": "Medicare Tax", "amount": "375.72", "category": "medicare" }, { "name": "Blue Ash Income Tax", "amount": "323.88", "category": "local" } ], "md5sum": "a9b85d17e3583203a854f85a29f78ed5", "file": "https://citadelid-files.s3.amazonaws.com/sandbox/statements/1194546.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAZWHJR5UGKNMOUOTK%2F20260618%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260618T014334Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=6a0374095c4875ba336efeb045805aa914bd502654874de7b125cc127167f2b1", "derived_fields": [], "missing_data_fields": [], "check_number": null }, "...and 53 more pay statements (omitted for brevity)" ], "annual_income_summary": [ { "id": "3a5d6a193fc7491689bc62317f4b046f", "year": 2026, "regular": "23229.24", "bonus": null, "commission": null, "overtime": "2665.44", "other_pay": null, "net_pay": "19559.76", "gross_pay": "25894.68" }, { "id": "1385cc45e75c474485c10124e306de8b", "year": 2025, "regular": "50330.02", "bonus": null, "commission": null, "overtime": "5775.12", "other_pay": null, "net_pay": "42379.48", "gross_pay": "56105.14" }, { "id": "2556ebea9d454ea18ddaf85a4143a692", "year": 2024, "regular": "50330.02", "bonus": null, "commission": null, "overtime": "5775.12", "other_pay": null, "net_pay": "42379.48", "gross_pay": "56105.14" } ], "bank_accounts": [ { "account_number": "11114623", "routing_number": "101014378", "account_name": null, "account_type": "C", "deposit_type": "A", "deposit_value": "1604.98", "bank_name": "Sandbox Bank" }, { "account_number": "11111308", "routing_number": "101013399", "account_name": null, "account_type": "C", "deposit_type": "A", "deposit_value": "25.00", "bank_name": "Sandbox Bank" } ], "w2s": [ { "file": "https://citadelid-files.s3.amazonaws.com/sandbox/w2s/2560.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAZWHJR5UGKNMOUOTK%2F20260618%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20260618T014334Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=7bcd1e3f77c7f8a105a702f5c5745ddfb0dc02bb08cac464f8cc4a341a68a63a", "md5sum": "385320b9c0f851260e86472707a5de18", "year": 2023, "wages": "56105.14", "federal_tax": "3994.38", "social_security_wages": "56105.14", "social_security_tax": "3481.14", "medicare_wages": "56105.14", "medicare_tax": "814.06", "gross_pay": null }, "...and 2 more W-2s (omitted for brevity)" ], "gse_accepted": true, "last_period_end": "2026-06-08", "last_pay_date": "2026-06-08" } ] } ] } ``` *** ## Credential scenarios Every credential here connects through the **Truv Payroll Provider** and returns the same report shape as [Quick start](#quick-start) — the **Sample responses** panels show only the fields that differ. The `VOIE-*` scenario ID is a stable test-case identifier you can cite in tickets. Every scenario below uses the password `goodpassword` — only the username changes. The [error scenarios](#error-scenarios) are the exception: there the password field carries the trigger. ### Pay frequency All four scenarios return SSN `991-91-9991`; only the pay cadence differs. | Scenario | Username | `pay_frequency` | Sample report | | ---------- | ------------------------ | ------------------- | --------------------------------------------------------------------------------------- | | `VOIE-PF1` | `goodlogin` | `BW` (bi-weekly) | [PDF](https://truv.com/wp-content/uploads/2025/11/report-goodlogin.pdf?v=1) | | `VOIE-PF2` | `goodlogin.weekly` | `W` (weekly) | [PDF](https://truv.com/wp-content/uploads/2025/11/report-goodlogin.weekly.pdf?v=1) | | `VOIE-PF3` | `goodlogin.semimonthly` | `SM` (semi-monthly) | [PDF](https://truv.com/wp-content/uploads/2025/11/report-goodlogin.semimonthly.pdf?v=1) | | `VOIE-PF4` | `goodlogin.monthly` | `M` (monthly) | [PDF](https://truv.com/wp-content/uploads/2025/11/report-goodlogin.monthly.pdf?v=1) | | `VOIE-PF5` | `goodlogin.semiannually` | `SA` (semi-annual) | — | Use these to validate your handling of `pay_frequency` (`W`, `BW`, `SM`, `M`, `SA`) and to confirm your annualization logic across cadences. Same report shape as the quick-start response above; `pay_frequency` is `W` and statements arrive weekly. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "PR associate", "job_type": "F", "is_active": true, "start_date": "2023-01-01", "end_date": null, "pay_frequency": "W", "income": "56104.88", "income_unit": "YEARLY", "pay_rate": "1078.94", "statement_count": 108, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-15", "period_start": "2026-06-09", "period_end": "2026-06-15", "hours": "38.20", "gross_pay": "1078.94", "net_pay": "815.00", "gross_pay_ytd": "25894.56", "net_pay_ytd": "19560.00" } } ] } ] } ``` Same shape; `pay_frequency` is `SM` (twice a month). ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "PR associate", "job_type": "F", "is_active": true, "start_date": "2023-01-01", "end_date": null, "pay_frequency": "SM", "income": "51789.36", "income_unit": "YEARLY", "pay_rate": "2157.89", "statement_count": 50, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-15", "period_start": "2026-06-01", "period_end": "2026-06-15", "hours": "76.40", "gross_pay": "2157.89", "net_pay": "1629.98", "gross_pay_ytd": "23736.79", "net_pay_ytd": "17929.78" } } ] } ] } ``` Same shape; `pay_frequency` is `M`. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "PR associate", "job_type": "F", "is_active": true, "start_date": "2023-01-01", "end_date": null, "pay_frequency": "M", "income": "51789.36", "income_unit": "YEARLY", "pay_rate": "4315.78", "statement_count": 26, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-31", "period_start": "2026-05-01", "period_end": "2026-05-31", "hours": "152.81", "gross_pay": "4315.78", "net_pay": "3259.96", "gross_pay_ytd": "21578.90", "net_pay_ytd": "16299.80" } } ] } ] } ``` Two payments per year. Each statement covers half a year. `income`, `income_unit`, and `pay_rate` come back `null` for this salaried profile. Read the cadence from `pay_frequency` and the statement period. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Timberline Consulting", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2025-06-30", "end_date": null, "pay_frequency": "SA", "income": null, "income_unit": null, "pay_rate": null, "statement_count": 3, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-30", "period_start": "2026-01-01", "period_end": "2026-06-30", "hours": null, "gross_pay": "36000.00", "net_pay": "36000.00", "basis_of_pay": "S" } } ] } ] } ``` ### Earnings composition These credentials connect through the **Truv Payroll Provider**. They return paychecks where pay includes more than base wages. Use them to check how your decisioning reads the `bonus` and `commission` statement fields, their `*_ytd` totals, and the `earnings[].category` on each line. | Scenario | Username | What it returns | | --------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- | | `VOIE-C1` | `goodlogin.bonus` | Wages plus periodic **bonus** payments (`bonus`, `bonus_ytd`, `earnings[].category: "bonus"`) | | `VOIE-C2` | `goodlogin.bonus.commission` | Wages plus **bonus and commission** on the same statements | | `VOIE-C3` | `goodlogin.commission` | **Commission only** earner. `pay_frequency` is `C` and gross pay equals commission, with no hourly or salary base | Bonus payments land on some statements and not others. `bonus` is `null` on a statement with no bonus. `bonus_ytd` adds up across the year, and `annual_income_summary[].bonus` carries the yearly total. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Cascade Logistics", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2026-03-13", "end_date": null, "pay_frequency": "BW", "income": "35.00", "income_unit": "HOURLY", "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-22", "period_start": "2026-05-08", "period_end": "2026-05-22", "hours": "80.00", "gross_pay": "3300.00", "net_pay": "3300.00", "regular": "2800.00", "bonus": "500.00", "bonus_ytd": "1500.00", "gross_pay_ytd": "18300.00" } } ] } ] } ``` Both `bonus` and `commission` appear on the same statement, on top of `regular` wages. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Northwest Sales", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2026-02-28", "end_date": null, "pay_frequency": "SM", "income": "31.25", "income_unit": "HOURLY", "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-15", "period_start": "2026-05-01", "period_end": "2026-05-15", "hours": "80.00", "gross_pay": "4000.00", "net_pay": "4000.00", "bonus": "1000.00", "commission": "500.00" } } ] } ] } ``` A commission only earner. `pay_frequency` is `C`, `gross_pay` equals `commission`, and `income`, `income_unit`, and `hours` are `null`. There is no hourly or salary base. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Pacific Coast Real Estate", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2025-11-01", "end_date": null, "pay_frequency": "C", "income": null, "income_unit": null, "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-01", "period_start": "2026-04-01", "period_end": "2026-04-30", "hours": null, "gross_pay": "5200.00", "net_pay": "5200.00", "commission": "5200.00", "basis_of_pay": "S" } } ] } ] } ``` ### Employment type | Scenario | Username | SSN | What it returns | | --------- | ----------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `VOIE-E1` | `fulltime` | `2211` | Full-time salesperson with regular salaried paystubs | | `VOIE-E2` | `hourly.part-time` | `666382548` | Hourly part-time worker with variable hours per stub | | `VOIE-E3` | `partial.data` | `2222` | Payroll connection succeeds but returns sparse employment metadata — `job_title`, `job_type`, and `original_hire_date` come back `null`. Use to validate your handling of null fields on the employment object. | | `VOIE-E4` | `goodlogin.min-data` | `991-91-9991` | Minimal information returned (no W-2s, sparse statements) | | `VOIE-E5` | `multiple.employments` | — | Multiple different employers attached to one applicant | | `VOIE-E6` | `multiple.employments2` | `7740` | Multiple same-employer positions (e.g. transferred roles) | | `VOIE-E7` | `nonactive` | `1890` | Employment with an `end_date` set and `is_active: false` | Salaried full-time employee with regular paystubs. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Real Estate Business", "job_title": "Sales Associate", "job_type": "F", "is_active": true, "start_date": "2023-03-12", "end_date": null, "pay_frequency": "SM", "income": "88663.20", "income_unit": "YEARLY", "pay_rate": "2812.50", "statement_count": 50, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-15", "period_start": "2026-06-01", "period_end": "2026-06-15", "hours": "86.67", "gross_pay": "3694.30", "net_pay": "3166.39", "gross_pay_ytd": "40637.30", "net_pay_ytd": "34830.29" } } ] } ] } ``` Hourly worker; note variable `hours` across statements. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "Customer Service Representative", "job_type": "P", "is_active": true, "start_date": "2023-01-01", "end_date": null, "pay_frequency": "M", "income": "17.00", "income_unit": "HOURLY", "pay_rate": null, "statement_count": 26, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-31", "period_start": "2026-05-01", "period_end": "2026-05-31", "hours": "145.00", "gross_pay": "2465.00", "net_pay": "2365.00", "gross_pay_ytd": "12325.00", "net_pay_ytd": "11825.00" } } ] } ] } ``` A connection that succeeds but returns sparse employment metadata — here `job_title`, `job_type`, and `original_hire_date` come back `null`. (`missing_data_fields` is empty; the gaps surface as null fields on the employment object.) ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "INITECH", "job_title": null, "job_type": null, "is_active": true, "start_date": "2023-12-15", "end_date": null, "pay_frequency": "SM", "income": "199999.92", "income_unit": "YEARLY", "pay_rate": "8333.33", "statement_count": 58, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-15", "period_start": "2026-06-01", "period_end": "2026-06-15", "hours": null, "gross_pay": "8333.33", "net_pay": "7805.42", "gross_pay_ytd": "91666.63", "net_pay_ytd": "85859.62" } } ] } ] } ``` Minimal information: employment summary only, with no statements and no W-2s. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "PR associate", "job_type": "F", "is_active": true, "start_date": null, "end_date": null, "pay_frequency": "BW", "income": "56269.25", "income_unit": "YEARLY", "pay_rate": "2153.60", "statement_count": 0, "w2_count": 0, "missing_data_fields": [], "latest_statement": null } ] } ] } ``` Two different employers attached to one applicant under a single link — one active, one ended. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "PAPER COMPANY", "job_title": "Senior Engineer", "job_type": "F", "is_active": true, "start_date": "2023-10-18", "end_date": null, "pay_frequency": "BW", "income": "75.96", "income_unit": "HOURLY", "pay_rate": null, "statement_count": 54, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-08", "period_start": "2026-05-26", "period_end": "2026-06-08", "hours": "80.00", "gross_pay": "7807.69", "net_pay": "7807.69", "gross_pay_ytd": "93692.28", "net_pay_ytd": "93692.28" } }, { "company": "TEXTILES", "job_title": "Engineer", "job_type": "F", "is_active": false, "start_date": "2022-06-15", "end_date": "2023-09-30", "pay_frequency": "BW", "income": "149430.58", "income_unit": "YEARLY", "pay_rate": "5747.33", "statement_count": 34, "w2_count": 2, "missing_data_fields": [], "latest_statement": { "pay_date": "2023-09-30", "period_start": "2023-09-19", "period_end": "2023-09-30", "hours": "96.00", "gross_pay": "5819.42", "net_pay": "5819.42", "gross_pay_ytd": "116388.40", "net_pay_ytd": "116388.40" } } ] } ] } ``` Multiple positions at the same employer (e.g. transferred roles). ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Moment Developments", "job_title": "Director, Accounts", "job_type": "F", "is_active": false, "start_date": "2023-07-15", "end_date": "2024-01-15", "pay_frequency": "SM", "income": "60000.00", "income_unit": "YEARLY", "pay_rate": "2500.00", "statement_count": 12, "w2_count": 2, "missing_data_fields": [], "latest_statement": { "pay_date": "2024-01-15", "period_start": "2024-01-01", "period_end": "2024-01-15", "hours": null, "gross_pay": "2500.00", "net_pay": "2500.00", "gross_pay_ytd": "2500.00", "net_pay_ytd": "2500.00" } }, { "company": "Moment Developments", "job_title": "Senior Account Manager", "job_type": null, "is_active": false, "start_date": "2022-11-01", "end_date": "2023-05-01", "pay_frequency": "SM", "income": "54000.00", "income_unit": "YEARLY", "pay_rate": "2250.00", "statement_count": 13, "w2_count": 2, "missing_data_fields": [], "latest_statement": { "pay_date": "2023-05-01", "period_start": null, "period_end": null, "hours": null, "gross_pay": "2250.00", "net_pay": "2250.00", "gross_pay_ytd": "20250.00", "net_pay_ytd": "20250.00" } } ] } ] } ``` Employment with `is_active: false` and an `end_date` set. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Rhode Island Consultants", "job_title": "Admin Services Manager", "job_type": "F", "is_active": false, "start_date": "2023-02-25", "end_date": "2024-06-15", "pay_frequency": "SM", "income": "72450.00", "income_unit": "YEARLY", "pay_rate": "3169.69", "statement_count": 48, "w2_count": 2, "missing_data_fields": [], "latest_statement": { "pay_date": "2024-06-15", "period_start": null, "period_end": null, "hours": "86.66", "gross_pay": "6797.56", "net_pay": "6797.56", "gross_pay_ytd": "81570.72", "net_pay_ytd": "81570.72" } } ] } ] } ``` ### Tenure Use these credentials when your decisioning depends on the borrower's tenure with their current employer — for example, PLL eligibility rules that require a minimum employment length, or income-stability decisioning that looks at months at current employer. | Scenario | Username | Returns | | --------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | | `VOIE-T1` | `goodlogin.tn1` | Active employment with **less than 12 months tenure** at the current employer | | `VOIE-T2` | `goodlogin.tn2` | Active employment with **less than 12 months tenure** at the current employer (alternate profile for multi-applicant test sets) | Both credentials produce the same response shape as `goodlogin` / `goodpassword` — the only difference is that `start_date` is set to a date inside the last 12 months. Use one or the other (or both) when your QA matrix has multiple sub-12-month scenarios that need distinct credentials. `start_date` falls inside the last 12 months. Use to confirm tenure-based eligibility logic. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "PR associate", "job_type": null, "is_active": true, "start_date": "2026-02-02", "end_date": null, "pay_frequency": "SM", "income": "51789.36", "income_unit": "YEARLY", "pay_rate": "2157.89", "statement_count": 9, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-15", "period_start": "2026-06-01", "period_end": "2026-06-15", "hours": "76.40", "gross_pay": "2157.89", "net_pay": "1629.98", "gross_pay_ytd": "19421.01", "net_pay_ytd": "14669.82" } } ] } ] } ``` Alternate sub-12-month profile; here the connection returns the employment summary with no statements. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Acme", "job_title": "PR associate", "job_type": null, "is_active": false, "start_date": "2026-02-02", "end_date": "2026-02-15", "pay_frequency": "SM", "income": "51789.36", "income_unit": "YEARLY", "pay_rate": "2157.89", "statement_count": 0, "w2_count": 0, "missing_data_fields": [], "latest_statement": null } ] } ] } ``` ### Benefits and special cases Both scenarios return SSN `9988`. | Scenario | Username | What it returns | | --------- | -------------- | ----------------------------------------------- | | `VOIE-B1` | `military` | Military MyPay data via the DFAS myPay provider | | `VOIE-B2` | `unemployment` | Weekly unemployment benefits | **Retirement, disability, and Veterans benefits:** Search for the benefit type in Truv Bridge (for example, "SSA" for Social Security or "VA Benefits"), pick a login method, and use `goodlogin` / `goodpassword`. Retirement and disability return a Social Security Administration Benefits Verification Letter. Veterans Benefits return a VA Benefit Summary Letter via the Veterans Affairs provider, or a retirement paystub via the DFAS myPay provider. Military service member pay record. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "United States Air Force", "job_title": "AF O4", "job_type": "F", "is_active": true, "start_date": "2023-03-16", "end_date": null, "pay_frequency": "M", "income": "141015.71", "income_unit": "YEARLY", "pay_rate": "7192.20", "statement_count": 26, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-31", "period_start": "2026-05-01", "period_end": "2026-05-31", "hours": null, "gross_pay": "16332.67", "net_pay": "16332.67", "gross_pay_ytd": "81663.35", "net_pay_ytd": "81663.35" } } ] } ] } ``` Weekly unemployment benefit income. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Illinois Department of Employment Security", "job_title": "Unemployed", "job_type": null, "is_active": true, "start_date": "2023-08-14", "end_date": null, "pay_frequency": "W", "income": "450.00", "income_unit": "WEEKLY", "pay_rate": null, "statement_count": 108, "w2_count": 3, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-06-15", "period_start": "2026-06-09", "period_end": "2026-06-15", "hours": null, "gross_pay": "750.00", "net_pay": "750.00", "gross_pay_ytd": "18000.00", "net_pay_ytd": "18000.00" } } ] } ] } ``` ### Gig and shift workers | Scenario | Username | What it returns | | --------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `VOIE-G1` | `goodlogin.shift` | Gig worker with earned wage access — use for testing gig-payroll VOIE flows where hours and earnings cadence differ from W-2 payroll | Gig provider connections return different field coverage than W-2 payroll connections. DoorDash returns gross pay and hours but no net pay or deductions; Uber returns gross and net pay but no hours. Validate your decisioning logic against partial-coverage responses, not against the assumption that every field will be populated. Gig worker with earned wage access; field coverage differs from W-2 payroll. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "DoorDash", "job_title": "Gig Worker", "job_type": null, "is_active": true, "start_date": "2026-04-06", "end_date": null, "pay_frequency": "W", "income": null, "income_unit": null, "pay_rate": null, "statement_count": 8, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-24", "period_start": "2026-05-17", "period_end": "2026-05-23", "hours": "31.00", "gross_pay": "618.50", "net_pay": null, "gross_pay_ytd": null, "net_pay_ytd": null } } ] } ] } ``` ### Income changes and outliers These credentials connect through the **Truv Payroll Provider**. Each returns a statement history with a clear value pattern. One trends up, one trends down, one holds high values, and one carries a single spike. Use them to check how your trend, averaging, and outlier logic reads movement across statements instead of a single period. | Scenario | Username | What it returns | | --------- | ----------------- | ------------------------------------------------------------------------------ | | `VOIE-D1` | `pay.raise` | Ongoing **pay increase**. `gross_pay` steps up across consecutive statements | | `VOIE-D2` | `pay.reduction` | Ongoing **pay decrease**. `gross_pay` steps down across consecutive statements | | `VOIE-D3` | `extreme.income` | **Very high values** for `gross_pay`, `hours`, and bonus on every statement | | `VOIE-D4` | `outlier.paystub` | A steady history with **one outlier statement** far larger than the rest | `pay.raise` and `pay.reduction` only show their pattern across the full statement set. Read the `statements[]` array from oldest to newest, not just `latest_statement`. `outlier.paystub` returns normal statements with one spike. Check each statement value, not the average alone. `gross_pay` rises on every statement, so the most recent statement is the highest. The values in the sample below show the trend. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Emerald City Tech", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2026-03-13", "end_date": null, "pay_frequency": "BW", "income": null, "income_unit": null, "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-22", "period_start": "2026-05-08", "period_end": "2026-05-22", "hours": "80.00", "gross_pay": "3500.00", "net_pay": "3500.00" } } ] } ] } ``` `gross_pay` falls on every statement, so the most recent statement is the lowest. The values in the sample below show the trend. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Coastal Retail Partners", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2026-03-13", "end_date": null, "pay_frequency": "BW", "income": null, "income_unit": null, "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-22", "period_start": "2026-05-08", "period_end": "2026-05-22", "hours": "80.00", "gross_pay": "2000.00", "net_pay": "2000.00" } } ] } ] } ``` Every statement carries high values for `gross_pay`, `hours`, and bonus. Use this to confirm your fields and decisioning hold at the top of the value range. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Apex Heavy Industries", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2026-03-13", "end_date": null, "pay_frequency": "BW", "income": "100.00", "income_unit": "HOURLY", "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-22", "period_start": "2026-05-08", "period_end": "2026-05-22", "hours": "320.00", "gross_pay": "48000.00", "net_pay": "48000.00", "bonus": "8000.00" } } ] } ] } ``` Most statements hold a steady value. One statement spikes far above the rest. `latest_statement` shows the normal value, so look through the `statements[]` array to find the spike. ```json theme={null} { "links": [ { "provider_name": "Truv payroll provider", "employments": [ { "company": "Valley Manufacturing", "job_title": null, "job_type": "F", "is_active": true, "start_date": "2026-03-13", "end_date": null, "pay_frequency": "BW", "income": "31.25", "income_unit": "HOURLY", "pay_rate": null, "statement_count": 6, "w2_count": 0, "missing_data_fields": [], "latest_statement": { "pay_date": "2026-05-22", "period_start": "2026-05-08", "period_end": "2026-05-22", "hours": "80.00", "gross_pay": "2500.00", "net_pay": "2500.00" } } ] } ] } ``` *** ## Error scenarios VOIE shares the universal authentication-error credentials. Use these to test your error handling and retry UX. | Scenario | Credential | Task status | Use it to test | | ---------- | ------------------------------- | -------------------------- | ----------------------------------------------- | | `VOIE-X1` | `goodlogin` / `no_data` | `no_data` | Successful login, provider returns zero records | | `VOIE-X2` | `goodlogin` / `mfa` | `mfa` → `done` | MFA flow — enter code `12345` | | `VOIE-X3` | `goodlogin` / `mfa_captcha` | `mfa` → `done` | MFA captcha — enter answer `9M4BP` | | `VOIE-X4` | `goodlogin` / `mfa_select` | `mfa` → `done` | MFA verification-method selection | | `VOIE-X5` | `goodlogin` / `longcheck` | `parse` → `done` (delayed) | \~30 second processing delay | | `VOIE-X6` | `error.user` / `login_error` | `login_error` | Incorrect credentials | | `VOIE-X7` | `error.user` / `mfa_error` | `mfa_error` | MFA verification failed | | `VOIE-X8` | `error.user` / `account_locked` | `account_locked` | Account locked by provider | | `VOIE-X9` | `error.user` / `unavailable` | `unavailable` | Provider under maintenance | | `VOIE-X10` | `error.user` / `error` | `error` | Generic login error | | `VOIE-X11` | `error.user` / `config_error` | `config_error` | Organization ID configuration failure | See [Task lifecycle](/api-reference/tasks/lifecycle) for the full status reference and the meaning of each error state. *** ## Fraud and suspicious documents Document-uploaded VOIE uses filename-driven triggers in sandbox to simulate fraud detection. The full filename → task status + `error_message` map lives on the [Test Documents](/developers/testing/test-documents#suspicious-document-detection) page. For interpreting `is_suspicious` on the report, fraud-tier behavior, and recommended manual-review workflows, see [Fraud Detection & Manual Review](/developers/fraud-and-manual-review). *** ## Webhook events When testing VOIE end to end, your webhook endpoint receives one `task-status-updated` event per status transition plus one `order-status-updated` event per connection when the user finishes the order. Per-task event (one per employer connection): ```json theme={null} { "webhook_id": "609a82aab21e4d9ba2569f35e9e8f26a", "event_type": "task-status-updated", "updated_at": "2026-04-26T13:02:20.369267+00:00", "task_id": "67f2924530564282bbaf6d27655e94a4", "link_id": "64f8e374949c4b769706028022626bf1", "product": "income", "tracking_info": "your-applicant-id", "status": "done" } ``` Order event (one per connection — fires for each unique `link_id` when the user closes Bridge via **Finish and Share**, so an order with more than one connection emits multiple `order-status-updated` events): ```json theme={null} { "webhook_id": "698e974cb30646189862229199f7ed1a", "event_type": "order-status-updated", "event_created_at": "2026-04-26T13:02:35.172897+00:00", "product": "income", "link_id": "64f8e374949c4b769706028022626bf1", "order_id": "45771e47434341039c61ccb28caeb9d8", "order_number": "your-loan-number", "status": "completed" } ``` For the difference between these two events and why `tracking_info` is the reliable mapping key, see the [Orders object](/api-reference/orders/object#order-lifecycle-and-webhooks) reference. *** ## Mortgage VOIE (GSE testing) For Fannie Mae Day 1 Certainty and Freddie Mac AIM testing — with borrower test accounts that map to specific GSE submission outcomes — see [GSE Testing](/developers/testing/gse-testing) and the credential tables on the [Fannie Mae D1C](/mortgage/d1c-aim/fannie-mae) and [Freddie Mac AIM](/mortgage/d1c-aim/freddie-mac) pages. *** ## Next steps Mint a bridge token and embed the widget Order-driven VOIE with auto-generated reports Fannie Mae D1C and Freddie Mac AIM workflows JSON schema for the VOIE report # Launch Checklist Source: https://docs.truv.com/developers/testing/launch-checklist Pre-production steps for any Truv integration Complete these steps before going live. Not all steps are required for minimal operation, but following them makes your integration more robust, secure, and maintainable. ## Production setup Email [support@truv.com](mailto:support@truv.com) to schedule a UX review session. Get tips on implementing Truv Bridge to increase conversion rates. Use the [production test providers](/developers/testing/test-credentials#testing-in-production) (Truv Payroll Provider, Truv Bank OAuth, Truv Bank non-OAuth) with sandbox credentials to validate your integration against real provider behavior. This confirms your webhook handling, error flows, and data ingestion work correctly. Walk through the full end-to-end flow as an end user: complete verification, confirm data appears in your system, test error and retry paths, and verify notifications deliver correctly. Ensure Truv Bridge matches your application's branding. Visit [Branding](https://dashboard.truv.com/app/customization/account/branding) to update colors, logo, and link expiration. Fill out your company profile in **Settings** → **Company**. Request Production keys via the [API Keys](https://dashboard.truv.com/app/development/keys) page. Configure your backend to use Production credentials. Remove Sandbox credentials from production code. Add teammates to the [Dashboard](https://dashboard.truv.com/app/settings/team) for shared access and monitoring. *** ## Bridge setup Pass a unique value for `tracking_info` when creating bridge tokens. This makes connections easy to track in the Dashboard and in your own systems. If you collect the user's employer name upfront, resolve it to a `company_mapping_id` and pass it when creating the order or bridge token. This skips the search screen and improves conversion. See [Deeplinking](/developers/integration/embedded-orders/deeplinking). Implement `onEvent` handling to provide better UX when the user closes Bridge or encounters an error. Use events to track conversion metrics. See [Bridge Events](/developers/sdks/bridge-events). *** ## Configure webhooks Add your endpoint URL in the Dashboard under **Development** → **Webhooks**. Each environment needs a separate URL. Validate the `X-WEBHOOK-SIGN` header on every incoming webhook. See [Security](/api-reference/security) for code examples in 5 languages. Your endpoint must respond within **1 second** connection timeout and **1 second** read timeout. If you need to do heavy processing, acknowledge the webhook immediately and process asynchronously. *** ## Handle errors Add retry logic for API calls to handle intermittent outages at supported institutions. Use exponential backoff. Users may not complete all connections. Process available data rather than treating partial completions as failures. Confirm that refresh orders return updated data when the session is active. Verify your system falls back to a new verification link when refresh returns `login_error` or `mfa_error`. See [Data Refresh](/developers/integration/embedded-orders/data-refresh). Track error rates by type (login\_error, mfa\_error, unavailable) to spot provider-specific issues early. *** ## Industry-specific checklists Sandbox credentials and test scenarios Sample documents for document processing testing # Paycheck Linked Lending Testing Source: https://docs.truv.com/developers/testing/paycheck-linked-lending Sandbox credentials and integration patterns for testing PLL flows Test Paycheck Linked Lending (PLL) flows in sandbox using the credentials below. Pass `product_type: pll` on the bridge token, and search for **Truv Payroll Provider** in Truv Bridge. PLL testing is more behavioral than report-driven. Unlike VOIE and VOA, PLL produces a setup confirmation plus an ongoing stream of deduction events as the borrower's paychecks land. Plan your sandbox tests around the lifecycle, not around a one-shot report. For additional login fields, use **Phone:** `(111)111-1111` and **Email:** `goodlogin@domain.com`. *** ## Quick start | Credential | Provider | What you get | | ---------------------------- | --------------------- | ------------------------------------------------------------------ | | `goodlogin` / `goodpassword` | Truv Payroll Provider | Successful PLL link with the deduction routed to your test account | For the PLL integration architecture, see the [PLL integration guide](/credit/integration/pll). For the product surface area and use cases, see the [PLL product page](/credit/products/pll). *** ## Check coverage first Before launching Bridge for a real borrower, call the [Company Mapping endpoint](/api-reference/companies/company_mapping) with `product_type: pll` to get the success likelihood for the borrower's employer. This is the same check you should run in production — sandbox returns a representative response so you can wire the flow. ```bash theme={null} curl --request GET \ --url "https://prod.truv.com/v1/companies/mapping/?company_name=Walmart&product_type=pll" \ --header 'X-Access-Client-Id: YOUR_TRUV_CLIENT_ID' \ --header 'X-Access-Secret: YOUR_TRUV_CLIENT_SECRET' ``` *** ## Tenure-based eligibility scenarios PLL eligibility commonly depends on the borrower's tenure with their current employer — a minimum employment length (typically 12 months) is a frequent underwriting requirement. Use these credentials to validate your eligibility logic against sub-minimum-tenure borrowers. | Scenario | Credential | Returns | | -------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `PLL-T1` | `goodlogin.tn1` / `goodpassword` | Active employment with **less than 12 months tenure** — use to confirm your eligibility check correctly declines or routes this borrower | | `PLL-T2` | `goodlogin.tn2` / `goodpassword` | Active employment with **less than 12 months tenure** (alternate profile when your QA matrix needs multiple sub-12-month test cases) | For your happy-path (eligible) case, use the standard `goodlogin` / `goodpassword` — the underlying profile has multi-year tenure that passes the typical 12-month threshold. *** ## Error scenarios PLL shares the universal authentication-error credentials. Use them to confirm your error handling and retry UX. | Scenario | Credential | Task status | | -------- | ------------------------------- | ----------------------------------- | | `PLL-X1` | `goodlogin` / `mfa` | `mfa` → `done` (enter code `12345`) | | `PLL-X2` | `error.user` / `login_error` | `login_error` | | `PLL-X3` | `error.user` / `mfa_error` | `mfa_error` | | `PLL-X4` | `error.user` / `account_locked` | `account_locked` | | `PLL-X5` | `error.user` / `config_error` | `config_error` | See [Task lifecycle](/api-reference/tasks/lifecycle) for the full status reference. *** ## What sandbox returns A completed PLL task produces a deposit allocation setup confirmation (same shape as DDS — the underlying mechanism is the same) plus ongoing webhooks as payroll deposits land and Truv recognizes them as repayment events. ```json theme={null} { "webhook_id": "609a82aab21e4d9ba2569f35e9e8f26a", "event_type": "task-status-updated", "updated_at": "2026-04-26T13:02:20.369267+00:00", "task_id": "67f2924530564282bbaf6d27655e94a4", "link_id": "64f8e374949c4b769706028022626bf1", "product": "pll", "tracking_info": "your-loan-id", "status": "done" } ``` *** ## Behavior and limitations ### No PDF report PLL's deliverable is the setup confirmation plus the ongoing webhook stream — there is no PDF report to render or persist. Store the JSON setup response and the per-deduction events alongside your loan record. ### Known sandbox gaps Sandbox PLL coverage is lighter than VOIE / VOA / DDS: * There is no scripted way to simulate a missed paycheck or a borrower who loses their job during repayment. Validate those scenarios against your own webhook handler with simulated payloads. * There is no scripted way to simulate the borrower disconnecting their payroll connection mid-repayment. Use a real refresh failure (`goodlogin` / `mfa_captcha` on the original verification, then trigger a refresh) to approximate. *** ## Next steps Full PLL implementation guide Product overview and use cases Run the PLL coverage check before launching Bridge Subscribe to ongoing deduction events # Test Credentials Source: https://docs.truv.com/developers/testing/test-credentials Start here — pick your product, then use the universal login scenarios and sandbox environment behavior that apply across every Truv product Test Truv's APIs in sandbox using the credentials below. Pick the product you're integrating against to see credentials, scenario coverage, sample responses, and sample reports specific to it. Universal authentication scenarios and environment behavior that apply across every product live on this page. For additional login fields used by any test credential, use **Phone:** `(111)111-1111` and **Email:** `goodlogin@domain.com`. *** ## Pick your product VOIE and VOE — payroll credentials, pay-frequency variants, sample PDFs VOA — financial accounts credentials, bank income source variants DDS — allocation scenarios, switch\_deposit lifecycle, error states PLL — setup confirmation and ongoing deduction events Test paystubs, W-2s, 1099s, and filename-driven fraud detection scenarios Fannie Mae D1C and Freddie Mac AIM end-to-end submission flows *** ## Universal login scenarios These credentials apply to every product. Use them to test authentication flows, MFA paths, processing delays, and error handling. See the product-specific pages above for the credentials that drive the actual report data. | Username | Password | Scenario | | ------------ | ---------------- | ----------------------------------------------- | | `goodlogin` | `goodpassword` | Successful login with complete data | | `goodlogin` | `no_data` | Successful login, provider returns zero records | | `goodlogin` | `mfa` | **MFA flow** — enter code: **12345** | | `goodlogin` | `mfa_captcha` | **MFA captcha** — enter answer: **9M4BP** | | `goodlogin` | `mfa_select` | **MFA flow** — verification method selection | | `goodlogin` | `longcheck` | **Wait state** — \~30 second processing delay | | `error.user` | `login_error` | Incorrect credentials | | `error.user` | `mfa_error` | MFA verification failed | | `error.user` | `account_locked` | Account locked by provider | | `error.user` | `unavailable` | Provider under maintenance | | `error.user` | `error` | Generic login error | | `error.user` | `config_error` | Organization ID configuration failure | See [Task lifecycle](/api-reference/tasks/lifecycle) for what each status means and how to handle it in your integration. *** ## Confirming your test worked Every test verification produces three signals you can check to confirm it ran end-to-end: | Signal | Where to find it | What to look for | | ----------------------------- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | Webhook events | Your registered webhook endpoint | `task-status-updated` events per status transition; `order-status-updated` on terminal state (orders only) | | Order or task status (API) | `GET /v1/orders/{id}/` for orders, or the [link status endpoint](/api-reference/links/object) for Bridge | `status: done` on the task or `status: completed` on the suborder | | Connection record (Dashboard) | [Dashboard → Users / Orders](https://dashboard.truv.com/app/users) | The connection row appears with the expected provider, employer, and product type | If the test scenario you used was an error credential (e.g. `error.user` / `login_error`), look for the matching error status — not `done`. See [Task lifecycle](/api-reference/tasks/lifecycle) for the full status map. *** ## Testing in production Truv exposes three test providers in production environments. Search for them by name in Truv Bridge to run sandbox-quality test scenarios against your production API keys without billing impact on real applicants. | Provider | Type | Use case | | --------------------- | -------------------------------- | ------------------------------------------------------------- | | Truv Payroll Provider | Payroll | Test VOIE, VOE, DDS, and PLL flows | | Truv Bank OAuth | Financial accounts (OAuth) | Test asset and transaction flows with OAuth login | | Truv Bank non-OAuth | Financial accounts (credentials) | Test asset and transaction flows with username/password login | Use the same test credentials documented on the product-specific pages — these providers return sandbox-quality data in your production environment. *** ## Refresh testing Data refreshes automatically succeed with `goodlogin` / `goodpassword`. To test a failed refresh, use `goodlogin` / `mfa_captcha` on the initial verification, then trigger a data refresh — the refresh will fail with `mfa_error` status. *** ## Native reset for authentication Truv Sandbox supports the native credential-reset workflow that providers expose for users who've forgotten their password. To test it: 1. In Truv Bridge, choose **Forgot password** (or the equivalent provider-specific link) on the login screen. 2. Enter any value in the requested fields the provider asks for (e.g. SSN, email, security question). 3. Use `goodlogin` / `mfa` to receive an MFA prompt — enter code `12345`. 4. The reset completes and Bridge proceeds with the standard verification flow. For embedded flows, borrowers may also be required to complete MFA during a data refresh. To exercise that path: use `goodlogin` / `mfa_captcha` on the original verification, then trigger a data refresh via `POST /v1/orders/{original_order_id}/` — the refresh will surface an MFA prompt that completes successfully when the borrower passes a `goodlogin` MFA credential. *** ## Native login via mobile SDKs Native logins inside the iOS and Android SDKs hit a different code path than the WebView-based flow. In sandbox, native login works only against the **Truv Payroll Provider** test provider — every other provider's native login is gated on production traffic. To exercise native login end-to-end with a real provider's UI (e.g. ADP, Workday), switch to production keys and use the [production test providers](#testing-in-production) approach, which gives you sandbox-quality data through the real provider UX. If your test plan requires validating native-login UX against a specific provider (Workday, ADP, etc.) before going live, schedule a session via [support@truv.com](mailto:support@truv.com) so we can pair on a controlled production test against that provider. *** ## Supported companies for testing The companies below return a valid `company_mapping_id` in sandbox. Use them when testing deeplink flows or the [Company Mapping endpoint](/api-reference/companies/company_mapping). * **Facebook**: Workday * **Bank of America**: Company with single sign on * **Kroger**: Custom integration * **Fannie Mae**: ADP * **Freddie Mac**: Workday In sandbox, only the companies above return a `company_mapping_id` from the Company Mapping endpoint. Production environments resolve `company_mapping_id` for the full Truv employer network. If you need a specific company mapped for sandbox testing (for example, to validate a deeplink flow into your largest customer's employer), email [support@truv.com](mailto:support@truv.com) and we'll add it to your sandbox set. # Test Documents Source: https://docs.truv.com/developers/testing/test-documents Sample PDFs for testing document processing in the sandbox When testing [Document Processing](/developers/integration/document-processing), use the sample PDFs below. Upload these documents to test successful parsing, various tax form types, and suspicious document detection. Test scenarios use the **file name** to determine results. The sandbox ignores actual file contents. Only the file name matters. **Trigger a suspicious result on any doc upload test scenario.** Add the prefix `suspicious.` to any test file name from this page (for example, rename `most.recent.paystub.pdf` to `suspicious.most.recent.paystub.pdf`) and upload it. The doc upload task will return data with `is_suspicious: true`. This works for every test file listed below — paystubs and tax forms. ## Pay stubs | Document | Download | | ------------------- | ------------------------------------------------------------------------------------- | | Most recent paystub | [most.recent.paystub.pdf](https://prod.truv.com/v1/permalink/most.recent.paystub.pdf) | | Next recent paystub | [next.recent.paystub.pdf](https://prod.truv.com/v1/permalink/next.recent.paystub.pdf) | | First paystub | [first.paystub.pdf](https://prod.truv.com/v1/permalink/first.paystub.pdf) | *** ## High income earner Use these documents to test parsing for a high income earner scenario. | Document | Download | | ------------------- | ------------------------------------------------------------------------------------------- | | Most recent paystub | [hi.most.recent.paystub.pdf](https://prod.truv.com/v1/permalink/hi.most.recent.paystub.pdf) | | Next recent paystub | [hi.next.recent.paystub.pdf](https://prod.truv.com/v1/permalink/hi.next.recent.paystub.pdf) | | First paystub | [hi.first.paystub.pdf](https://prod.truv.com/v1/permalink/hi.first.paystub.pdf) | | W-2 | [hi.w2.pdf](https://prod.truv.com/v1/permalink/hi.w2.pdf) | *** ## Tax documents | Document | Download | | --------- | --------------------------------------------------------------- | | W-2 | [w2.pdf](https://prod.truv.com/v1/permalink/w2.pdf) | | 1099-DIV | [1099div.pdf](https://prod.truv.com/v1/permalink/1099div.pdf) | | 1099-G | [1099g.pdf](https://prod.truv.com/v1/permalink/1099g.pdf) | | 1099-INT | [1099int.pdf](https://prod.truv.com/v1/permalink/1099int.pdf) | | 1099-MISC | [1099misc.pdf](https://prod.truv.com/v1/permalink/1099misc.pdf) | | 1099-NEC | [1099nec.pdf](https://prod.truv.com/v1/permalink/1099nec.pdf) | | 1099-R | [1099r.pdf](https://prod.truv.com/v1/permalink/1099r.pdf) | | SSA-1099 | [ssa1099.pdf](https://prod.truv.com/v1/permalink/ssa1099.pdf) | | 1040 | [f1040.pdf](https://prod.truv.com/v1/permalink/f1040.pdf) | For 1099 tax documents, Truv supports parsing formats from any year after 2021. This includes 1099-DIV, 1099-G, 1099-INT, 1099-MISC, 1099-NEC, and 1099-R. *** ## Volunteer documents | Document | Download | | ------------------- | -------------------------------------------------------------------------------------- | | Volunteer letter | [volunteer\_letter.pdf](https://prod.truv.com/v1/permalink/volunteer_letter.pdf) | | Volunteer timesheet | [volunteer\_timesheet.pdf](https://prod.truv.com/v1/permalink/volunteer_timesheet.pdf) | *** ## Suspicious document detection | Scenario | Description | Downloads | | ----------------------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Tampered documents** | Information is falsified or manipulated | [Tampered 1](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/f1.paystub.pdf), [Tampered 2](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/f2.paystub.pdf), [Tampered 3](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/f3.paystub.pdf) | | **Different SSNs** | Personal information is inconsistent across documents | [SSN 1](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/ssn1.paystub.pdf), [SSN 2](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/ssn2.paystub.pdf), [SSN 3](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/ssn3.paystub.pdf) | | **Different applicant names** | Personal information is inconsistent across documents | [Applicant 1](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/p1.paystub.pdf), [Applicant 2](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/p2.paystub.pdf), [Applicant 3](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/p3.paystub.pdf) | | **No data or invalid data** | Information is missing or unable to be parsed | [No data 1](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/nd1.paystub.pdf), [No data 2](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/nd2.paystub.pdf), [No data 3](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/nd3.paystub.pdf) | To flag **any** doc upload test scenario as suspicious, rename the file with the `suspicious.` prefix before uploading. See the tip at the top of this page for the full rule and examples. *** ## Validation failures Use these files to test the file-level validation flags returned by the [Document Collections API](/developers/integration/document-processing). Each file triggers a specific validation failure on the [collection retrieve](/api-reference/document-collections/collections_retrieve) response. In the sandbox, only the **file name** determines the test scenario — the actual file contents are ignored. You can upload any PDF as long as the filename matches. | Document | Triggers | Download | | ----------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | | Duplicate file | `is_unique: false` — upload any file twice in the same collection, or use the provided file | [duplicate.pdf](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/duplicate.pdf) | | Unreadable file | `is_readable: false` | [unreadable.pdf](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/unreadable.pdf) | | Password-protected file | `is_accessible: false` (password: `paystub123`) | [password.pdf](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/password.pdf) | | Unsupported MIME type | `is_supported_type: false` | [unsupported\_type.pdf](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/unsupported_type.pdf) | | Processing failure | `status: failed` after validation passes | [failed.pdf](https://citadelid-resources.s3.us-west-2.amazonaws.com/doc_upload/failed.pdf) | The sandbox triggers the duplicate scenario by **file name**. In production, Truv detects duplicates by **file content**, not file name — so sandbox results for renamed or same-named files do not reflect production behavior. See [How duplicate detection works](/developers/integration/document-processing#how-duplicate-detection-works). *** ## Base64 encoding for Document Collections API The [Document Collections API](/developers/integration/document-processing) accepts base64-encoded file content when creating or uploading to a collection. To encode a test document for use with the API: ```bash theme={null} # Download a test document curl -O https://prod.truv.com/v1/permalink/most.recent.paystub.pdf # Base64 encode it base64 -i most.recent.paystub.pdf -o most.recent.paystub.b64 # Use the encoded content in your API call cat most.recent.paystub.b64 ``` Pass the base64 string as the `content` field when creating a document collection: ```json theme={null} { "files": [ { "filename": "most.recent.paystub.pdf", "content": "BASE64_ENCODED_CONTENT" } ] } ``` In sandbox mode, the **file name** determines the test scenario, not the actual content. The base64 content can be from any valid PDF — only the filename matters for sandbox behavior. # Caseworker Portal Source: https://docs.truv.com/government/integration/caseworker-portal Create verification orders and send links to clients from your caseworker system using the EmployeePortal demo Create verification orders from your caseworker system and send clients a link to complete verification on their own device. Truv delivers the link via email or SMS, tracks completion, and returns verified data through webhooks. For clients who apply by phone or in person, see [Offline & Contact Center](/government/integration/offline-contact-center). **Integration pattern:** [Hosted Orders](/developers/integration/hosted-orders/new-user) | **Products:** VOIE, VOE, VOA | **Demo:** [Case Worker Portal](/developers/demos/public-sector/case-worker-portal) *** ## Get started Clone and run the [Case Worker Portal demo](/developers/demos/public-sector/case-worker-portal) to see the full caseworker-to-client flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Public Sector > Case Worker Portal**, add a test client with an email address, and send a verification request. The demo tracks order status and displays reports when the client completes Bridge. See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Create an order** — Your server sends client PII (name, email, phone) and selected products to [POST /v1/orders/](/api-reference/orders/orders_create). The response includes `order_id`, `share_url`, and `user_id`. 2. **Deliver the link** — Truv sends the `share_url` to the client via email and/or SMS automatically. For agency-managed notifications, suppress Truv emails and send the `share_url` through your own messaging system. 3. **Client completes Bridge** — The client opens the link, searches for their employer, and connects their payroll account on their own device. 4. **Receive webhooks** — Truv sends an `order-status-updated` [webhook](/api-reference/webhooks) when verification completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 5. **Retrieve reports** — Fetch the [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) with `POST /v1/users/{user_id}/reports/` or the [assets report](/api-reference/user-asset-verification-reports/assets-report-create) with `POST /v1/users/{user_id}/assets/reports/`. Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | -------------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Order creation | [`server/routes/orders.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/orders.js) | [POST /v1/orders/](/api-reference/orders/orders_create) | | Caseworker dashboard | [`src/demos/EmployeePortal.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/EmployeePortal.jsx) | [Hosted Orders](/developers/integration/hosted-orders/new-user) | | Webhook verification | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Report retrieval | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Income reports](/api-reference/user-income-and-employment-reports/users_reports) | *** ## Public Sector-specific configuration ### Case ID tracking Use `external_user_id` to link orders to your agency's case identifier. Group all household member orders under the same case ID for unified tracking. ```json theme={null} { "products": ["income"], "first_name": "John", "last_name": "Doe", "email": "john.doe@example.com", "phone": "4155554193", "external_user_id": "case-12345", "template_id": "YOUR_TEMPLATE_ID", "locale": "es" } ``` Pass `template_id` to apply your agency's [customized template](/developers/customization) (branding, messaging, landing page). Pass `locale` to set the client's language — see [threshold languages](/government/overview#threshold-languages) for all supported values. ### Notification delivery Choose how the client receives the verification link: | Method | Configuration | Best for | | ------------------ | ----------------------------------------------------------------------------------------- | ----------------------------------------------- | | **Truv-managed** | Include `email` and/or `phone` in the order | Automatic delivery with configurable reminders | | **Agency-managed** | Set `suppress_user_notifications: true`, use `share_url` from the response | All communications must come from state systems | | **Dashboard** | Create orders through the [Truv Dashboard](https://dashboard.truv.com) or CSV bulk upload | No code required | For agency-managed notifications, use the `short_share_url` from the order response for SMS and the full `share_url` for email. ### Household members Create a separate order for each household member. Use the same `external_user_id` to group all orders under one case. Truv sends each member their own verification link. *** ## Follow-up tasks When a client doesn't complete verification after receiving a link, configure [follow-up notifications](/developers/integration/embedded-orders/follow-up) to send automatic reminders. | Setting | Description | | -------------------------------- | --------------------------------------------------------- | | `suppress_user_notifications` | Set to `false` (default) to enable Truv-managed reminders | | `first_notification_delay_hours` | Hours to wait before the first reminder (default: 0) | For caseworker-initiated workflows, the caseworker can also manually resend the link from the Dashboard or trigger a new notification through the API. *** ## Next steps Embed verification in the client-facing portal Verify clients who apply by phone or in person Re-verify clients at recertification Extract income data from uploaded documents Full implementation guide for hosted order creation and notification delivery Test with government-specific scenarios # Customer Portal Source: https://docs.truv.com/government/integration/customer-portal Embed income, employment, and asset verification in your benefits portal using the CustomerPortal demo Truv Bridge embedded in a government benefits portal Verify client income, employment, and assets in real-time by embedding Truv Bridge directly in your benefits portal. The client searches for their employer, connects their accounts, and completes verification without leaving your system. **Integration pattern:** [Embedded Orders](/developers/integration/embedded-orders/overview) | **Products:** VOIE, VOE, VOA | **Demo:** [Customer Portal](/developers/demos/public-sector/customer-portal) *** ## Get started Clone and run the [Customer Portal demo](/developers/demos/public-sector/customer-portal) to see the full client self-service flow working locally. ```bash theme={null} git clone https://github.com/truvhq/demo-apps.git cd demo-apps npm install && npm start ``` Open `http://localhost:5173`, select **Public Sector > Customer Portal**, choose a product (income, employment, or assets), and walk through a verification using sandbox credentials (`goodlogin` / `goodpassword`). See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. The demo follows this sequence: 1. **Search for employer** — Your server calls [GET /v1/company-mappings-search/](/api-reference/companies/company_autocomplete_search) to find the client's employer by name. For asset verification, search financial institutions with [GET /v1/providers/](/api-reference/data-providers/providers-list). 2. **Create an order** — Your server sends client PII, case ID, and selected products to [POST /v1/orders/](/api-reference/orders/orders_create). The response includes a `bridge_token` and `user_id`. 3. **Initialize Bridge** — Your frontend opens [Truv Bridge](/developers/sdks/overview) with the `bridge_token`. Set `isOrder: true` and optionally pass `companyMappingId` to [deeplink](/developers/integration/embedded-orders/deeplinking) directly to the employer. 4. **Receive webhooks** — Truv sends an `order-status-updated` [webhook](/api-reference/webhooks) when verification completes. Verify the signature using the `X-Webhook-Sign` header with HMAC-SHA256. 5. **Retrieve reports** — Fetch the [VOIE report](/api-reference/user-income-and-employment-reports/users_reports) with `POST /v1/users/{user_id}/reports/` or the [assets report](/api-reference/user-asset-verification-reports/assets-report-create) with `POST /v1/users/{user_id}/assets/reports/`. Each step maps to a specific file in the demo. Use these as reference when building your integration. | Step | Demo file | API reference | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | Employer search | [`src/components/CompanySearch.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/components/CompanySearch.jsx) | [Company Search](/api-reference/companies/company_autocomplete_search) | | Order creation | [`server/routes/orders.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/orders.js) | [POST /v1/orders/](/api-reference/orders/orders_create) | | Bridge initialization | [`src/demos/CustomerPortal.jsx`](https://github.com/truvhq/demo-apps/blob/main/src/demos/CustomerPortal.jsx) | [Bridge SDK](/developers/sdks/overview) | | Webhook verification | [`server/webhooks.js`](https://github.com/truvhq/demo-apps/blob/main/server/webhooks.js) | [Webhooks](/api-reference/webhooks) | | Report retrieval | [`server/routes/user-reports.js`](https://github.com/truvhq/demo-apps/blob/main/server/routes/user-reports.js) | [Income reports](/api-reference/user-income-and-employment-reports/users_reports) | *** ## Public Sector-specific configuration ### Case ID tracking Use `external_user_id` to link orders to your agency's case or application identifier. This enables data continuity across verifications, renewals, and household members. ```json theme={null} { "products": ["income", "assets"], "first_name": "John", "last_name": "Doe", "ssn": "222233333", "external_user_id": "case-12345", "template_id": "YOUR_TEMPLATE_ID", "locale": "es" } ``` Pass `template_id` to apply your agency's [customized template](/developers/customization) (branding, messaging, landing page). Pass `locale` to set the client's language — see [threshold languages](/government/overview#threshold-languages) for all supported values. ### Products Request the products your eligibility determination requires: | Product | Use case | Report | | ------------ | ------------------------------------------------- | ------------------------------- | | `income` | SNAP, TANF, Medicaid, housing assistance | VOIE (includes employment data) | | `employment` | Employment status confirmation, compliance checks | VOE | | `assets` | Means testing, housing assistance | VOA + Income Insights | The `income` product includes employment verification automatically. Do not pass both `income` and `employment`. ### Household members Create separate orders for each household member who needs to verify income. Use the same `external_user_id` (case ID) to group orders under one case. | Approach | How it works | Best for | | ---------------- | ------------------------------------------------------------ | ------------------------------------------ | | **Portal tasks** | Create a to-do item in the portal for each household member | Agencies with portal login for all members | | **Email / SMS** | Create an order with contact info and let Truv send the link | Agencies that collect contact consent | ### Content Security Policy If your portal uses a Content Security Policy, allow `my.truv.com` (frame-src) and `cdn.truv.com` (script-src) for Bridge to load. Missing CSP configuration is the most common cause of the widget failing to load. Check your CSP settings first if Bridge doesn't appear. ### Renewals and data refresh When a client's case is due for recertification, use the [Order Refresh API](/api-reference/orders/orders_create_refresh_order) to pull updated data from their existing payroll and bank connections. If the session is still active, the client does not need to do anything — Truv returns fresh data automatically. | Scenario | What happens | Client action | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | | **Session still active** | Refresh succeeds. Your system receives updated income and employment data via webhook. Pre-fill the caseworker review screen. | None | | **Session expired** | Refresh fails with `login_error` or `mfa_error`. The client needs to re-authenticate. | Complete verification through a new link | **Recommended renewal flow:** 1. **Attempt a refresh first.** When a case is due for recertification, create a [refresh order](/api-reference/orders/orders_create_refresh_order) against the original order. This is a server-side call — no portal interaction needed. 2. **If the refresh succeeds**, route the updated data to the caseworker review screen. The client's portal can show a "Verification complete" status with no action required. 3. **If the refresh fails**, display a verification task in the client's portal. The client logs in, sees the pending task, and completes a new verification through Bridge. For programs with periodic eligibility reviews, most refreshes succeed because sessions stay active. For annual recertification, expect more re-authentication. Plan your portal UX for both paths. See [Data Refresh](/developers/integration/embedded-orders/data-refresh) for the full implementation guide, including refresh limits (3 per connection per 24 hours) and failure handling. ### Self-certification Enable [self-certification](/developers/integration/embedded-orders/self-certification) to let clients review and confirm retrieved income and employment data before submission. After verification, the client sees their data and marks it as representative or flags discrepancies. Self-certification is especially useful for: * Clients with multiple income sources or irregular pay * Self-employed clients confirming bank transaction data * Programs that require client attestation Retrieve certification results from the [certifications endpoint](/api-reference/orders/orders_certifications_results) after the order completes. #### What's configurable on the certification screen The certification screen is the final review step the client sees before submitting their verified data. Most layout and copy are fixed today — these specific elements are tunable per company: | Element | Configurable? | Notes | | ------------------------------------------------ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | Hours display | Yes | Designed for Community Engagement verification (e.g., volunteer-hour requirements). Toggle on the company's certification configuration. | | Link expiration text | Yes | The "Expires in…" countdown copy is set on the [Customization Template](/developers/customization). | | Income amounts and pay-period grouping | No | Driven by the parsed payroll data — not editable client-side. | | Section labels (employer, pay period, gross pay) | No | Fixed on the screen. | To change configurable elements, contact your Truv Technical Account Manager. ### Email and SMS link delivery For cases where the client verifies outside your portal (e.g., a caseworker sends a link during an office visit or phone call), you can embed the Truv verification link in your own communications: | Field | Use | | ----------------- | ------------------------------ | | `share_url` | Full URL for email links | | `short_share_url` | Shortened URL for SMS messages | To use your own email/SMS system instead of Truv's, set `suppress_user_notifications: true` in the order's `notification_settings` and deliver the `share_url` yourself. Order links expire based on your template configuration. To configure link expiry, set the expiration in your [template settings](/developers/customization) or pass it in the order request. ### Follow-up tasks When a client starts but doesn't complete verification, configure [follow-up notifications](/developers/integration/embedded-orders/follow-up) to bring them back. Truv sends email/SMS reminders automatically based on your `notification_settings`. | Setting | Description | | -------------------------------- | --------------------------------------------------------- | | `suppress_user_notifications` | Set to `false` (default) to enable Truv-managed reminders | | `first_notification_delay_hours` | Hours to wait before the first reminder (default: 0) | For portal-integrated workflows, you can also display incomplete verifications as pending tasks in your portal UI and let the client resume where they left off. *** ## Next steps Send verification links and ingest data into caseworker screens Skip the employer search screen for higher completion rates Test with government-specific scenarios Full implementation guide for order creation, Bridge, callbacks, and data retrieval # Offline & Contact Center Workflows Source: https://docs.truv.com/government/integration/offline-contact-center Verify income and employment for clients who apply by phone or in person Verify income and employment for clients who don't apply in-app — those who reach an agent by phone or apply in person at an office. Both flows reuse the standard order, so verified data returns through the same webhooks and pre-fills the same caseworker screens as digital applications. *** ## Contact center Contact center agents create an order during the phone call and send the verification link while the client is on the line. 1. **Agent creates order** — During the call, the agent enters client details and creates an order through the Dashboard or API. 2. **Send link via SMS** — Use the `short_share_url` from the order response to send an SMS to the client's phone during the call. 3. **Client completes verification** — The client opens the link on their phone and connects their payroll or bank accounts while still on the call (or shortly after). 4. **Agent monitors status** — The Dashboard or your caseworker system shows real-time order status. The agent can confirm completion before ending the call. For contact center deployments, set `first_notification_delay_hours` to a low value (e.g., 1) so clients who don't complete during the call receive a reminder quickly. *** ## In-person QR code For office visits, generate a QR code from the order's `share_url` so clients can verify on their own phone at the office. 1. **Caseworker creates order** — Create an order via the Dashboard or API with the client's case information. 2. **Display QR code** — Generate a QR code from the `share_url` and display it on the caseworker's screen or print it. 3. **Client scans and verifies** — The client scans the QR code with their phone, opens Bridge, and connects their payroll or bank accounts. 4. **Results flow back** — Truv sends verified data through webhooks. The caseworker sees results in the Dashboard or caseworker system. QR codes work with any QR code generator — encode the `share_url` value. The same link works whether scanned from a screen or printed handout. *** ## Follow-up for incomplete verifications When a client doesn't finish after receiving a link, configure [follow-up notifications](/developers/integration/embedded-orders/follow-up) to send automatic reminders, or resend the link manually from the Dashboard. *** ## Next steps Send verification links and ingest data into caseworker screens. Re-verify clients at recertification. # Custom Integration Source: https://docs.truv.com/government/integration/overview Choose where to integrate Truv verification in your benefits workflow Integrate Truv income, employment, and asset verification into your agency's systems. Choose the integration channels based on who initiates verification and how the client completes it. Run a demo app locally before building. See [full setup instructions](/developers/quickstarts-overview#demo-apps) for ngrok and environment configuration. *** ## Choose your integration channels | Channel | Who initiates | How the client verifies | Demo | | ------------------------------------------------------------------------------------ | ------------- | --------------------------------------------------------------------- | ----------------------------------------------------- | | [Customer Portal](/government/integration/customer-portal) | Client | Embedded Bridge widget in your benefits portal | [CustomerPortal](https://github.com/truvhq/demo-apps) | | [Caseworker Portal](/government/integration/caseworker-portal) | Caseworker | Clicks a link sent via email or SMS | [EmployeePortal](https://github.com/truvhq/demo-apps) | | [Contact Center](/government/integration/offline-contact-center#contact-center) | Phone agent | Agent sends link via SMS during the call | [EmployeePortal](https://github.com/truvhq/demo-apps) | | [In-Person Office](/government/integration/offline-contact-center#in-person-qr-code) | Caseworker | Client scans a QR code on their phone | [EmployeePortal](https://github.com/truvhq/demo-apps) | | [Renewals](/government/integration/renewals) | Automated | Data refresh from existing connections — no client action when active | — | Document upload is a fallback within any channel, not a separate integration. When a client cannot connect their payroll provider, Bridge offers document upload automatically. See [Document Processing](/government/products/document-processing) for supported document types. *** ## Combine channels Most agencies use multiple channels to reach clients across different touchpoints: * **Customer Portal + Caseworker**: Clients self-serve through the portal. Caseworkers send follow-up links to those who didn't complete verification. * **Caseworker + Contact Center + In-Person**: Caseworkers send links proactively. Contact center agents send links during calls. Office visitors scan QR codes. * **All channels + Renewals**: Use any channel for initial verification. Automate data refresh at recertification time — only re-engage clients whose sessions have expired. *** ## Next steps Embed verification in your client-facing benefits portal Send verification links, manage contact center, and in-person flows Test with government-specific scenarios Full implementation guide for order creation, Bridge, callbacks, and data retrieval # Renewals Source: https://docs.truv.com/government/integration/renewals Re-verify income and employment for clients renewing their benefits at recertification Re-verify income and employment at recertification without making clients start over. Use the [Order Refresh API](/api-reference/orders/orders_create_refresh_order) to pull updated data from an existing order's connections — when the session is still active, the client does nothing and Truv returns fresh data. Only clients whose sessions have expired need to re-engage through a verification channel. *** ## Refresh workflow When a case is due for recertification, look up the original Truv order ID associated with the client's case record. Send a `POST` request to the original order's endpoint. Specify which product to refresh and, optionally, which employers to include. The refresh creates a **new order** with its own ID. Omit the `employers` array to refresh all connections from the original order. See the [Data Refresh guide](/developers/integration/embedded-orders/data-refresh#create-a-data-refresh-order-server-side) for the full request example. Listen for the `task-status-updated` webhook with `status: "done"` on the new order. Retrieve the refreshed report and pre-fill the caseworker review screen with updated income, employment status, and pay history. *** ## When a refresh fails Refreshes fail when the client's session has expired or their credentials have changed. The webhook returns `login_error` or `mfa_error`. Re-engage the client through any [verification channel](/government/integration/overview). | Scenario | Cause | What to do | | ------------------------ | -------------------------------------------------- | ---------------------------------------------------------------------------------- | | **Session expired** | Payroll provider session timed out or requires MFA | Create a new order and send a fresh verification link through your renewal process | | **Credentials changed** | Client changed their payroll login password | Create a new order — the client re-authenticates through Bridge | | **Provider unavailable** | Payroll provider is temporarily down | Retry the refresh after some time | OAuth-based payroll connections typically expire after \~180 days. For programs with annual recertification cycles, plan for re-authentication on most renewals. For programs with periodic eligibility reviews, refresh success rates are significantly higher. *** ## Refresh limits * **3 refreshes** per connection per 24-hour period * Each refresh is billed as a separate verification *** ## Bulk renewals For agencies processing many renewals at once, automate refresh order creation by iterating over cases due for recertification. Check each refresh result: if it succeeds, pre-fill the caseworker screen automatically. If it fails, queue the case for a new verification link. See [Data Refresh](/developers/integration/embedded-orders/data-refresh) for the full implementation guide, including [Bridge Update Mode](/developers/integration/bridge-widget/returning-user) for re-authentication. *** ## Next steps Send verification links and ingest data into caseworker screens. The digital, in-app verification channel. # Public Sector Source: https://docs.truv.com/government/overview Income, employment, and asset verification for government programs Truv helps government agencies and social service organizations verify income, employment, and assets for benefit eligibility, program enrollment, and recertification workflows. Reduce application review time with real-time income and employment data Eliminate manual data entry, document collection, and follow-up calls Source-verified data replaces self-reported documents and transcription Clients verify in minutes from any device — no pay stubs to gather *** ## What you can verify * Current income (gross, net) * YTD earnings * Employment status and employer details * Pay frequency and history * W-2 employment and payroll-connected gig work * Self-employment and gig work income via bank transactions * Bank account balances for asset-tested programs * Non-payroll income streams (freelance, cash, family support) * Expense tracking for self-employment *** ## Common use cases Verify income and employment for: * SNAP (Supplemental Nutrition Assistance Program) * TANF (Temporary Assistance for Needy Families) * Medicaid eligibility * Housing assistance programs * Child care subsidies Covers W-2 employees, self-employed clients, and gig workers. For self-employed clients, bank transaction data captures income that payroll verification cannot reach. **Products:** `income`, `assets` Speed up enrollment for: * Low-income energy assistance (LIHEAP) * Free/reduced school lunch programs * Emergency rental assistance * Veterans benefits * Disability assistance **Products:** `income`, `assets` Automate data collection for: * Annual recertification * Periodic eligibility reviews * Change reporting * Program compliance Use the [Order Refresh API](/api-reference/orders/orders_create_refresh_order) to pull updated income and employment data at recertification time without requiring the client to re-verify. When the session has expired, send a new verification link through your renewal workflow. See the [Renewals](/government/integration/renewals) guide for the full renewal flow. **Products:** `income` with automatic refresh Verify income for clients without traditional W-2 employment: * Freelancers and independent contractors * Rideshare and delivery drivers * Home daycare, lawn care, cleaning services * Cash-paid and informal work Bank transaction data through the `assets` product makes these income streams visible. Pair with [self-certification](/developers/integration/embedded-orders/self-certification) so clients can confirm or annotate their income sources. **Products:** `income`, `assets` *** ## Integration options ### Option 1: Dashboard (No Code) Truv Dashboard and order landing page Use the Truv Dashboard to create and manage verification orders without any integration: * Create orders manually via the Dashboard UI * Send verification links to clients via email/SMS * Caseworkers can view results directly in the Dashboard * Configure [webhooks](/api-reference/webhooks) to automatically sync verified data to your eligibility system when verifications complete [Learn more about Dashboard integration -->](/developers/dashboard) ### Option 2: Custom Integration (Recommended) Portal with embedded order form and Truv Bridge widget Embed Truv directly into your systems for a seamless client and caseworker experience. Choose the channels that fit your workflow. Self-service verification embedded in your online benefits application Send verification links and view pre-filled data in caseworker screens Phone agents create orders and send links during the call Clients scan a QR code at the office to verify on their own device Automatic data refresh at recertification — no client action when sessions are active Document upload is a fallback within any channel, not a separate integration. When a client cannot connect their payroll provider, Bridge automatically offers document upload. See [Document Processing](/government/products/document-processing) for details. ### Channel summary | Channel | How it works | Client action | | --------------------- | ------------------------------------------------------- | --------------------------------------------------- | | **Customer Portal** | Embedded verification in the benefits application flow | Self-service during application | | **Caseworker Portal** | Caseworker creates order, Truv sends link via email/SMS | Clicks link, completes verification on their device | | **Contact Center** | Phone agent creates order during the call, sends link | Completes verification after the call | | **In-Person Office** | Client scans QR code at the office | Verifies on their phone while at the office | | **Renewals** | Automatic data refresh from existing connections | None if session is active; re-verifies if expired | *** ## Benefits for government agencies * Reduce back-and-forth for pay stubs and employment documents * Pre-fill eligibility workflows with verified data * Speed up application review for straightforward cases * Eliminate manual data entry and document collection * Automatic data updates for recertification — no client outreach needed * Staff can focus on complex cases instead of chasing documents * Source-verified data eliminates transcription errors * Real-time income data from payroll systems * Consistent data format across all channels * Reduce staff time spent on verification follow-up * Lower manual processing overhead * Reuse the same workflow for applications and renewals * No need to gather pay stubs or mail documents * Faster approval decisions * Mobile-friendly — clients verify from any device * Available in [multiple languages](#threshold-languages) * Bank transaction data captures income outside traditional payroll * Covers freelancers, gig workers, cash-paid clients * Self-certification lets clients confirm income sources *** ## Compliance & Security Review [Security](/api-reference/security) for current platform security details. If your agency has additional compliance, retention, or procurement requirements, confirm them directly with Truv before rollout. [View security documentation -->](/api-reference/security) *** ## Threshold languages Truv Bridge, emails, SMS messages, and landing pages support multiple languages. Pass the `locale` parameter when [creating an order](/api-reference/orders/orders_create) to set the language for the client's verification experience. | Code | Language | Code | Language | | ----- | -------- | ----- | ---------- | | `en` | English | `ko` | Korean | | `es` | Spanish | `lo` | Lao | | `ar` | Arabic | `pa` | Punjabi | | `cmn` | Mandarin | `pt` | Portuguese | | `zh` | Chinese | `ru` | Russian | | `fa` | Farsi | `so` | Somali | | `hi` | Hindi | `tl` | Tagalog | | `hmn` | Hmong | `th` | Thai | | `hy` | Armenian | `uk` | Ukrainian | | `ja` | Japanese | `vi` | Vietnamese | | `km` | Khmer | `ium` | Mien | Set the `locale` on the order to match the client's preferred language. Bridge, emails, and SMS all render in that language automatically. *** ## Template customization Customize the verification experience — Bridge widget branding, email/SMS copy, and landing page appearance — using [templates](/developers/customization). Pass `template_id` when creating an order to apply a specific template. Manage templates in the [Dashboard](https://dashboard.truv.com) under **Customization > Templates** or via the [Templates API](/api-reference/templates/object). *** ## Implementation timeline | Phase | Dashboard (No Code) | Custom Integration | | -------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | **Setup** | Configure templates, API keys, and order workflows in the Dashboard | Implement order creation, Bridge widget, webhooks, and data ingestion | | **Testing** | Create test orders with [sandbox credentials](/developers/testing/test-credentials) | End-to-end testing with demo apps and sandbox | | **Pilot** | Run a limited rollout with real clients | Deploy to staging, validate data flow into eligibility system | | **Production** | Full rollout | Full rollout with monitoring | *** ## Get started * Quick start with no code? --> [Dashboard Integration](/developers/dashboard) * Building custom? --> Choose a channel above (Customer Portal, Caseworker Portal, Contact Center, or In-Person Office) See a working verification flow locally. [Demo setup instructions](/developers/quickstarts-overview#demo-apps). Use [sandbox credentials](/developers/testing/test-credentials) to test various income scenarios — W-2 employment, self-employment, multiple employers, SSA benefits. Deploy to production and begin running live eligibility workflows. *** ## Resources Choose your integration channels Complete API documentation Import the Postman collection for hands-on API testing Sandbox credentials and test scenarios Talk to our government solutions team [support@truv.com](mailto:support@truv.com) # Document Processing for Government Source: https://docs.truv.com/government/products/document-processing Verify client income and employment from uploaded documents when payroll connections are unavailable Verify client income and employment by processing uploaded documents. Document processing serves as a fallback when clients cannot connect to their payroll provider through Bridge, or as a tool for caseworkers who already have documents on file. It is included as part of the standard orders workflow — no separate implementation is needed when using [Customer Portal](/government/integration/customer-portal) or [Caseworker Portal](/government/integration/caseworker-portal). *** ## Benefits Verify income from paystubs, W-2s, and 1099s without requiring the client to log in Automatic detection of manipulated documents and suspicious metadata Extract employer name, pay period, gross/net pay, and tax withholdings into structured fields Returns the same income and employment data structure as a live payroll connection *** ## What you get * Gross and net pay per period * Year-to-date earnings * Pay frequency and period dates * Tax withholdings and deductions * Employer name and address * Job title and position * Employment dates * Pay basis (salary, hourly) * Document type classification * Readability verification * Suspicious document flagging * Known suspicious template detection * Paystubs * W-2 forms * 1099 tax forms (DIV, G, INT, MISC, NEC, R) * SSA-1099 * Volunteer/community service letters *** ## Government use cases Clients without traditional payroll (freelancers, gig workers, small business owners) can upload 1099s and bank statements to verify income for benefits eligibility. Caseworkers who receive documents by mail or in person can upload them through the Document Collections API for automated processing, replacing manual data entry. When a client's employer isn't supported or the payroll connection fails, document upload provides an alternative verification path within the same workflow. *** ## Government-specific configuration ### Government document types Benefits eligibility determinations commonly use these document types: | Document type | Use case | Fields extracted | | ----------------- | ---------------------------------------- | ----------------------------------------------- | | Pay stubs | SNAP, TANF, Medicaid income verification | Employer, gross/net pay, deductions, pay period | | W-2 forms | Annual income verification | Annual wages, federal/state taxes, employer EIN | | 1099 forms | Self-employed and gig income | Payer, non-employee compensation | | SSA-1099 | Social Security benefits | Benefit amounts, tax withholdings | | Volunteer letters | Community service hour verification | Organization, hours, dates | ### Case ID tracking Pass `external_user_id` when creating the user to link document collections to your agency's case identifier. ```json theme={null} { "external_user_id": "case-12345" } ``` ### Fallback from a payroll connection When a client can't connect their payroll provider through [Customer Portal](/government/integration/customer-portal) or [Caseworker Portal](/government/integration/caseworker-portal), fall back to document upload. Enable document upload in the [Truv Dashboard](https://dashboard.truv.com) to offer it directly within the Bridge widget. ### Lenient document intake Applicants rarely upload exactly what's required. With [intelligent intake](/developers/integration/document-processing#intelligent-intake), a client uploads any mix of files — including phone photos — and Truv classifies each one and flags unreadable scans up front. If a SNAP determination needs two recent pay stubs and the applicant uploads five files, Truv recognizes the two pay stubs among them; you finalize those and let the applicant proceed. *** ## How to implement | Path | Code required | Best for | | ----------------------------------------------------------------------- | ------------- | ------------------------------------- | | [Document Collections API](/developers/integration/document-processing) | Custom | Caseworker-initiated, bulk processing | | [Bridge fallback](/developers/integration/bridge-widget/overview) | Minimal | Client-initiated via Customer Portal | | [Truv Dashboard](/developers/dashboard) | None | Manual upload, pilot testing | For caseworker-driven workflows, use the [Document Collections API](/developers/integration/document-processing) to upload, validate, finalize, and retrieve structured data. For client-facing portals, enable document upload as a fallback in [Truv Bridge](/developers/sdks/overview) by setting `data_sources: ["docs"]` in the bridge token. *** ## API reference Create collections, upload files, finalize, and retrieve results Upload and process documents via the Collections API Retrieve parsed and structured data Create tokens with document upload enabled *** ## Next steps Full Document Collections API walkthrough Integrate document processing into caseworker workflows Client-facing verification with Bridge fallback Sample PDFs for sandbox testing # Income & Employment for Government Source: https://docs.truv.com/government/products/income-employment Income and employment verification for government benefits programs Income & Employment (VOIE) verification provides instant access to client income and employment data directly from payroll providers. For public sector agencies, this replaces manual pay stub collection and employer phone calls with real-time, source-verified data. ## Benefits Replace employer phone calls and paper forms with instant payroll data Connects to payroll providers covering 85%+ of US employees. See [coverage](/developers/coverage-payroll) for details. Data comes directly from payroll systems — no self-reported documents Seconds instead of days for income and employment verification *** ## What you get ### Income Data * **Current income:** Base salary, hourly rate, tips, commission, bonus, overtime * **Pay frequency:** Weekly, bi-weekly, semi-monthly, monthly * **YTD earnings:** Year-to-date gross and net pay * **Deductions:** Federal/state taxes, benefits, garnishments, child support * **Pay history:** Historical pay statements across multiple pay periods ### Employment Data * **Employer information:** Name, address, phone number, EIN * **Employment status:** Active, terminated, on leave * **Employment dates:** Start date, end date (if applicable) * **Job title:** Current position and department * **Work schedule:** Full-time, part-time, hours per week ### Documents * Pay stubs (PDF) * W-2 forms (when available) * Employment verification letter *** ## Government use cases Verify household income against program thresholds. Income & Employment verification captures all income streams, including gig work and multiple employers, giving a complete picture for means-tested programs. **Typical product:** `income` (automatically includes employment data) Determine eligibility and subsidy amounts based on verified income. Pay frequency and YTD data help normalize income across different pay schedules. **Typical product:** `income` (automatically includes employment data) Refresh income data automatically at recertification time using the [Order Refresh API](/api-reference/orders/orders_create_refresh_order). When the client's payroll session is still active, Truv pulls fresh pay statements, updated YTD earnings, and current employment status — no client action needed. If the session has expired, create a new order and send a verification link through your renewal workflow. The client re-authenticates through Bridge. For programs with periodic eligibility reviews, most refreshes succeed automatically. For annual recertification, plan for re-authentication on a larger share of cases. See [Data Refresh](/developers/integration/embedded-orders/data-refresh) for implementation details. **Typical product:** `income` (automatically includes employment data) Truv connects to the **Social Security Administration (SSA)** as a distinct provider. This covers clients whose primary income is Social Security benefits rather than payroll employment. **Benefit type classification:** The `job_title` field in the employment response identifies the specific benefit type. Values include: * `"Disability"` -- SSDI benefits * `"Survivors"` -- Survivor benefits * `"Retirement"` -- Retirement benefits **What you receive:** SSA income returns a **Benefits Verification Letter** rather than standard paystubs. This letter confirms the benefit type and monthly payment amount. Standard payroll fields like `w2s`, deductions, and pay frequency are not applicable for SSA connections. **Bank transaction fallback:** Government benefit deposits can also be detected through bank transaction analysis. Include the `assets` product in your order to capture bank-deposited benefit payments when the client cannot authenticate directly with SSA. **Sandbox testing:** In Bridge, search for SSA as the provider and authenticate with `goodlogin` / `goodpassword`. **Typical product:** `income` (automatically includes employment data) *** ## Data coverage Truv connects to payroll providers covering 85%+ of US employees, including ADP, Paychex, Workday, UKG, Paylocity, Gusto, and 100+ more. See the [coverage page](/developers/coverage-payroll) for the full provider list. ### Supported income types | Income type | How it's captured | | -------------------- | --------------------------------------------------------------------------- | | W-2 employment | Direct payroll connection | | 1099 contractors | Payroll provider connection | | Multiple employers | Client connects each employer separately | | Gig / on-demand work | Payroll connection (e.g., Uber, DoorDash) or bank transactions via `assets` | | Self-employment | Bank transactions via `assets` product | For the most complete income picture, include `income` and `assets` products in your order. The `income` product automatically includes employment data — no need to request `employment` separately. This captures W-2 payroll **and** bank-deposited income from self-employment, gig work, and other non-payroll sources. *** ## How to implement | Path | Code required | Best for | | --------------------------------------------------------------- | ------------- | ------------------------------------------------- | | [Customer Portal](/government/integration/customer-portal) | Minimal | Self-service client verification | | [Caseworker Portal](/government/integration/caseworker-portal) | None | Caseworker-initiated orders via Dashboard | | [Document Processing](/government/products/document-processing) | Minimal | Upload pay stubs and tax documents for extraction | *** ## Report structure ### API Response The Income & Employment response uses the `IncomeCheck` schema. The top-level object contains an `employments` array, where each entry includes nested `company`, `profile`, income fields, and `statements`. | Field | Path | Example | | -------------- | ----------------------------- | -------------------- | | Annual income | `employments[].income` | `"70000.00"` | | Income period | `employments[].income_unit` | `YEARLY` | | Pay frequency | `employments[].pay_frequency` | `BW` (Bi-Weekly) | | Employer | `employments[].company.name` | `"Acme Corporation"` | | Pay statements | `employments[].statements[]` | Array of pay stubs | | W-2 forms | `employments[].w2s[]` | Array of W-2 docs | ```json theme={null} { "id": "24d7e80942ce4ad58a93f70ce4115f5c", "status": "done", "finished_at": "2024-01-20T14:30:00Z", "access_token": "48427a36d43c4d5aa6324bc06c692456", "provider": "adp", "employments": [ { "id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", "income": "60000.00", "income_unit": "YEARLY", "pay_rate": "2307.69", "pay_frequency": "BW", "is_active": true, "job_title": "Medical Technician", "job_type": "F", "start_date": "2021-06-15", "original_hire_date": "2021-06-15", "company": { "name": "City General Hospital", "address": { "street": "500 Main St", "city": "Springfield", "state": "IL", "zip": "62701" }, "phone": "2175550100", "ein": "37-1234567" }, "profile": { "first_name": "Maria", "last_name": "Garcia" }, "statements": [ { "pay_date": "2024-01-19", "net_pay": "1780.00", "net_pay_ytd": "1780.00", "gross_pay": "2450.00", "gross_pay_ytd": "2450.00", "hours": "80.00", "basis_of_pay": "H" } ], "w2s": [ { "year": 2023, "wages": "58000.00", "federal_tax": "7200.00", "gross_pay": "58000.00" } ] } ] } ``` For the full schema, see the [Income & Employment reports reference](/api-reference/user-income-and-employment-reports/object). *** ## API reference Create and manage verification orders Retrieve income verification data Retrieve employment data Receive status notifications *** ## Best practices For benefits eligibility, 12 months provides enough data to calculate average monthly income and identify seasonal patterns. See the [Create Order API reference](/api-reference/orders/orders_create) for all available fields. Many benefits clients have multiple income sources: part-time jobs, gig work, seasonal employment. Include both `income` and `assets` products so clients can connect payroll **and** bank accounts in one session. If your agency already has the client's employer on file, pass a `company_mapping_id` to skip the employer search screen. This improves completion rates. [Learn more about deeplinking](/developers/integration/embedded-orders/deeplinking). Pass the `locale` parameter when creating an order to render Bridge, emails, and SMS in the client's preferred language. See [threshold languages](/government/overview#threshold-languages) for supported languages. Enable [self-certification](/developers/integration/embedded-orders/self-certification) so clients can review and confirm the income and employment data Truv retrieves. This is especially useful for clients with multiple income sources or irregular pay. *** ## Next steps Step-by-step technical setup Integration scenarios across all channels API examples and code patterns Sandbox test credentials # Assets for Government Source: https://docs.truv.com/government/products/self-employed-income Verify self-employment income, gig work, and financial assets for government programs Assets (VOA) verification connects directly to clients' bank accounts to capture income that traditional payroll verification can't reach: **self-employment, gig work, cash deposits, family support, and other non-payroll income streams**. For public sector agencies, this is the primary tool for verifying the hardest-to-document income types. Assets verification also provides account balances for asset-tested programs, replacing manual bank statement collection entirely. **Why Assets verification matters for public sector:** A significant portion of benefits clients earn income outside of traditional W-2 employment: rideshare drivers, freelancers, home daycare providers, cash-paid workers, and those receiving family assistance. Payroll verification alone misses these income streams. Assets verification captures them through bank transaction data. ## Benefits Real-time access to bank account data Data pulled from financial institutions, not self-reported Bank income analysis for clients without traditional payroll Identify business expenses alongside income for complete financial picture *** ## What you get ### Account Information * **Account type:** Checking, savings, money market, CD, investment * **Account ownership:** Verified account holder name(s) * **Current balance:** Real-time balance as of the connection date * **Available balance:** Funds currently available for withdrawal * **Account number:** Masked account number for identification ### Transaction History * **Transaction details:** Date, description, amount, credit/debit type * **Deposit identification:** Payroll deposits, government payments, transfers * **Large deposits:** Flagged for caseworker review * **History depth:** Up to 2 years (30-730 days, configurable via `days_requested`) ### Documents * Bank statements (PDF) * Account verification letter *** ## Government use cases Many clients earn income outside traditional W-2 employment: * **Self-employed:** Home daycare, lawn care, cleaning services, freelance work * **Gig economy:** Rideshare (Uber, Lyft), delivery (DoorDash, Instacart), TaskRabbit — many gig platforms are also available as payroll connections through the `income` product * **1099 contractors:** Independent contractors paid outside of payroll * **Cash and informal income:** Cash-paid work, family support, room rentals * **Government payments:** Social Security, disability, veterans benefits Bank transactions make these income streams visible and verifiable. Deposits are categorized and can be used for [self-certification](/developers/integration/embedded-orders/self-certification) workflows, giving caseworkers documented evidence of income that would otherwise require clients to self-report. **Recommended products:** `income`, `assets` (the `income` product automatically includes employment data) Many benefits programs have asset limits. Assets verification provides verified balances across all connected accounts, giving caseworkers a complete picture of a client's financial resources without collecting paper bank statements. **Typical product:** `assets` Verify that clients meet asset thresholds for Section 8, public housing, or emergency rental assistance programs. Assets verification captures checking, savings, and investment account balances. **Typical product:** `assets` For emergency programs (LIHEAP, disaster relief, emergency food assistance), Assets verification provides rapid financial verification so agencies can process applications quickly. **Typical product:** `assets` Refresh bank account balances and transaction data at recertification time using the [Order Refresh API](/api-reference/orders/orders_create_refresh_order). When the client's bank connection is still active, Truv returns updated balances and recent transactions without requiring the client to reconnect. If the connection has expired, create a new order and send a verification link through your renewal workflow. See [Data Refresh](/developers/integration/embedded-orders/data-refresh) for implementation details. **Typical product:** `assets` *** ## Data coverage ### Financial Institutions Truv connects to thousands of US banks and credit unions: | Institution Type | Examples | | ---------------- | ---------------------------------------------- | | National banks | Chase, Bank of America, Wells Fargo, Citi | | Regional banks | PNC, US Bank, TD Bank, Regions | | Credit unions | Navy Federal, State Employees CU, Pentagon FCU | | Online banks | Ally, Marcus, Discover, Capital One 360 | | Neobanks | Chime, Current, Varo | ### Supported Account Types | Account Type | Balance | Transactions | Ownership | | ---------------------- | ------- | ------------ | --------- | | Checking | Yes | Yes | Yes | | Savings | Yes | Yes | Yes | | Money market | Yes | Yes | Yes | | CD | Yes | Limited | Yes | | Investment / brokerage | Yes | Limited | Yes | *** ## How to implement | Path | Code required | Best for | | --------------------------------------------------------------- | ------------- | ------------------------------------------------- | | [Customer Portal](/government/integration/customer-portal) | Minimal | Self-service client verification | | [Caseworker Portal](/government/integration/caseworker-portal) | None | Caseworker-initiated orders via Dashboard | | [Document Processing](/government/products/document-processing) | Minimal | Upload pay stubs and tax documents for extraction | *** ## Report structure ### API Response The Assets response uses the `VoaApplicantReport` schema. The report contains a `links` array (one per financial institution connection), each with an `accounts` array. Each account includes `balances`, `owners`, and `transactions`. | Field | Path | Example | | --------------- | ----------------------------------------------------- | --------------------- | | Account type | `links[].accounts[].type` | `CHECKING`, `SAVINGS` | | Masked number | `links[].accounts[].mask` | `"1234"` | | Account holder | `links[].accounts[].owners[].full_name` | `"Jane Smith"` | | Current balance | `links[].accounts[].balances.current` | `"5420.75"` | | Direct deposit | `links[].accounts[].transactions[].is_direct_deposit` | `true` | ```json theme={null} { "report_id": "7d4fcb86b81a4880955beea558092391", "created_at": "2024-01-15T10:00:00Z", "completed_at": "2024-01-15T10:30:00Z", "days_requested": 60, "borrower": { "first_name": "Maria", "last_name": "Garcia" }, "links": [ { "link_id": "150491a20bdb4292bb2a2ad8554fecba", "provider": "first_national", "provider_name": "First National Bank", "accounts": [ { "id": "4d601895417c46ec99633978db12a866", "type": "CHECKING", "mask": "4521", "owners": [ { "full_name": "Maria Garcia", "email": "maria.garcia@example.com" } ], "balances": { "balance": "2340.75", "available_balance": "2240.75", "currency_code": "USD" }, "transactions": [ { "id": "txn_001", "transacted_at": "2024-01-12T00:00:00Z", "description": "DIRECT DEPOSIT - SPRINGFIELD COUNTY", "amount": "1850.00", "type": "CREDIT", "status": "POSTED" }, { "id": "txn_002", "transacted_at": "2024-01-10T00:00:00Z", "description": "VENMO - PAYMENT FROM J GARCIA", "amount": "500.00", "type": "CREDIT", "status": "POSTED" } ] }, { "id": "5e702906528d53a0bb3b3089ec23b977", "type": "SAVINGS", "mask": "4522", "owners": [ { "full_name": "Maria Garcia" } ], "balances": { "balance": "8500.00", "available_balance": "8500.00", "currency_code": "USD" }, "transactions": [] } ] } ], "summary": { "total_balance": "10840.75" } } ``` For the full schema, see the [Asset verification reports reference](/api-reference/user-asset-verification-reports/object). *** ## API reference Create and manage verification orders Retrieve asset data Financial account details Receive status notifications *** ## Expense tracking For self-employed clients, agencies often need to verify expenses alongside income to determine net self-employment income. Bank transaction data captures both sides: * **Business expenses:** Supplies, equipment, vehicle costs, subcontractor payments * **Income deposits:** Client payments, platform payouts, recurring transfers Transaction descriptions and categorization help caseworkers distinguish business expenses from personal spending. Use self-certification to let the client annotate which transactions are business-related. *** ## Best practices 60 days provides enough history to identify regular deposits, income patterns, and expenses without overwhelming the caseworker with data. Many clients have accounts at more than one institution. Allow at least 3 connections so clients can add all relevant accounts in one session. Bank transactions reveal income that payroll data doesn't capture: gig payments, family transfers, cash deposits. Request both `income` and `assets` products in one order. See the [Create Order API reference](/api-reference/orders/orders_create) for all available fields. For asset-tested programs, use the `summary.total_balance` field to quickly compare against program thresholds. Individual account details are available for caseworker review when needed. Enable [self-certification](/developers/integration/embedded-orders/self-certification) so clients can review and confirm bank transaction data. Clients who receive income outside of traditional payroll (freelance, cash, family support) can annotate their deposits to help caseworkers verify income sources. Pass the `locale` parameter when creating an order to render Bridge, emails, and SMS in the client's preferred language. See [threshold languages](/government/overview#threshold-languages) for supported languages. *** ## Next steps Step-by-step technical setup Integration scenarios across all channels API examples and code patterns Sandbox test credentials # Day 1 Certainty (D1C) Source: https://docs.truv.com/mortgage/d1c-aim/fannie-mae Day 1 Certainty validation through Desktop Underwriter for income, employment, and assets Truv is an authorized report supplier for Fannie Mae's [Desktop Underwriter](https://singlefamily.fanniemae.com/applications-technology/desktop-underwriter) (DU). Truv reports provide representation and warranty relief on validated loan components: income, employment, and assets. Truv's vendor ID is **Truv**. ## How it works ```mermaid theme={null} sequenceDiagram participant Borrower participant Lender participant Truv participant DU as Fannie Mae DU Lender->>Truv: Create order (VOIE + VOA) Truv->>Borrower: Launch Bridge widget Borrower->>Truv: Connect payroll & bank accounts Truv->>Lender: Webhook: verification complete Lender->>Truv: Retrieve Report ID Lender->>DU: Submit loan with Report ID DU->>Truv: Fetch report data DU->>Lender: DU Findings (D1C eligible) ``` *** ## Day 1 Certainty eligibility Official Fannie Mae resource: [Desktop Underwriter](https://singlefamily.fanniemae.com/applications-technology/desktop-underwriter) D1C provides: * **Rep and warranty relief** on income, employment, and assets * **Reduced documentation** requirements * **Free re-verifications** for up to 90 days after the initial report **"Current as of" date:** For DU, this reflects the end of period from the borrower's last pay statement. *** ## Implementation checklist Use this sequence for a production-ready Fannie Mae flow: 1. Complete your Truv integration using [LOS integrations](/mortgage/integration/los-overview) or [Custom Integration](/mortgage/integration/custom-pos) 2. Collect borrower income and, when needed, asset verification through Truv 3. Retrieve the latest `voie_report_id` and `voa_report_id` 4. Submit the Report ID into Desktop Underwriter 5. Validate DU findings and confirm Day 1 Certainty eligibility 6. If data is refreshed, use the newest Report ID for resubmission *** ## Integrate with Encompass For [ICE Encompass](/mortgage/integration/ice-encompass) clients, Truv's Report ID appears in the **Loan: GSE Additional Provider Data** screen as **Truv (Bor, CoBorr)**. ### VOIE field mapping Write the Report ID to Encompass FieldID `GSEVENDOR.X50`. For borrower and coborrower, comma-separate the Report IDs: ``` borrower_report_id,coborrower_report_id ``` ### VOA field mapping | Borrower | Coborrower | | --------------- | --------------- | | `GSEVENDOR.X37` | `GSEVENDOR.X38` | *** ## Validation checklist Confirm Truv generated the latest VOIE and VOA reports and that the borrower completed all required verifications before you submit to DU. If you use Encompass, verify `GSEVENDOR.X50`, `GSEVENDOR.X37`, and `GSEVENDOR.X38` are populated correctly before DU submission. Submit the current Report ID in Desktop Underwriter and confirm DU can retrieve the report successfully. Check for Day 1 Certainty eligibility, missing data, or any partial-validation conditions caused by incomplete borrower verification. *** ## Test in sandbox For DU-oriented borrower test accounts, pre-generated VOIE and VOA report IDs, and sample report PDFs, see [GSE Testing](/developers/testing/gse-testing). For the general payroll credential matrix and non-GSE scenarios, see [Income & Employment Testing](/developers/testing/income-employment) and [Assets Testing](/developers/testing/assets). *** ## Next steps Freddie Mac Loan Product Advisor integration Shared report retrieval patterns and Encompass mappings Sandbox credentials and test scenarios Pre-production validation # Asset and Income Modeler (AIM) Source: https://docs.truv.com/mortgage/d1c-aim/freddie-mac Asset and Income Modeler (AIM) integration through Loan Product Advisor for income, employment, and assets Truv is an AIM service provider for Freddie Mac's Loan Product Advisor (LPA). Truv delivers automated assessment of borrower income, employment, and assets through [Asset and Income Modeler (AIM)](https://sf.freddiemac.com/tools-learning/technology-tools/our-solutions/aim-asset-income-modeler), and instant paystub and W-2 assessment through the AIM Check API. Truv's vendor ID is **Truv**. ## How it works ```mermaid theme={null} sequenceDiagram participant Borrower participant Lender participant Truv participant LPA as Freddie Mac LPA Lender->>Truv: Create order (VOIE + VOA) Truv->>Borrower: Launch Bridge widget Borrower->>Truv: Connect payroll & bank accounts Truv->>Lender: Webhook: verification complete Lender->>Truv: Retrieve Report ID Lender->>LPA: Submit loan with Report ID LPA->>Truv: Fetch report data (AIM) LPA->>Lender: LPA Feedback (AIM assessed) ``` *** ## AIM products Official Freddie Mac resource: [Asset and Income Modeler (AIM)](https://sf.freddiemac.com/tools-learning/technology-tools/our-solutions/aim-asset-income-modeler) ### Income and employment (AIM) Automated income and employment assessment through payroll data. LPA evaluates borrower income using Truv's VOIE report data. ### Assets (AIM) Automated asset assessment from connected bank accounts. LPA evaluates account balances, ownership, and transaction history. ### Document income (AIM Check API) For borrowers without a direct payroll connection, Truv supports the AIM Check API for instant paystub and W-2 assessment. Upload documents through [Document Processing](/developers/integration/document-processing) and submit the report to LPA. **"Current as of" date:** For LPA, this reflects the pay date of the borrower's last pay statement. *** ## Implementation checklist Use this sequence for a production-ready Freddie Mac flow: 1. Complete your Truv integration using [LOS integrations](/mortgage/integration/los-overview) or [Custom Integration](/mortgage/integration/custom-pos) 2. Collect VOIE, VOA, or AIM Check document income based on the borrower workflow 3. Retrieve the latest report identifier for the product you will submit 4. Submit the current Report ID through Loan Product Advisor 5. Review AIM feedback and confirm the result matches the loan scenario 6. If Truv data is refreshed, resubmit using the newest Report ID *** ## Integrate with Encompass For [ICE Encompass](/mortgage/integration/ice-encompass) clients, Truv's Report ID appears in the **Loan: GSE Additional Provider Data** screen under the Freddie Mac section. ### VOA field mapping | Borrower | Coborrower | | --------------- | --------------- | | `GSEVENDOR.X43` | `GSEVENDOR.X44` | ### VOIE field mapping Write the Report ID to the appropriate Encompass Freddie Mac vendor field for your implementation. *** ## Validation checklist Confirm whether the loan is using payroll-based AIM, asset-based AIM, or document-based AIM Check before retrieving the final report. Always use the latest Truv report generated for the borrower. Refreshed data creates a new Report ID and should replace older IDs in LPA submission. If you use Encompass, confirm the Freddie Mac Report ID fields are populated correctly before the loan is submitted. Validate LPA feedback for the exact loan scenario and confirm there are no partial-verification issues caused by incomplete borrower connections. *** ## Test in sandbox For LPA-oriented pre-generated VOIE and VOA report IDs and sample report PDFs, see [GSE Testing](/developers/testing/gse-testing). For the general payroll credential matrix and non-GSE scenarios, see [Income & Employment Testing](/developers/testing/income-employment) and [Assets Testing](/developers/testing/assets). *** ## Next steps Fannie Mae Desktop Underwriter integration Document-based Freddie Mac income workflow Shared report retrieval patterns and Encompass mappings Pre-production mortgage validation # Overview Source: https://docs.truv.com/mortgage/d1c-aim/overview Overview of Fannie Mae Day 1 Certainty and Freddie Mac Asset and Income Modeler with Truv Truv's Income & Employment and Asset reports are certified by Fannie Mae and Freddie Mac. The same Truv report IDs are accepted by both GSEs — Fannie Mae's Desktop Underwriter (DU) for Day 1 Certainty and Freddie Mac's Loan Product Advisor (LPA) for AIM. Fannie Mae Desktop Underwriter integration, vendor setup, Encompass field mapping, and validation flow. Freddie Mac Loan Product Advisor integration, AIM products, AIM Check API, and validation flow. *** ## Day 1 Certainty (Fannie Mae) Day 1 Certainty provides: * **Rep and warranty relief** on income, employment, and assets * **Reduced documentation** requirements * **Free re-verifications** for up to 90 days after the initial report * **Faster loan processing** and confidence in data accuracy To qualify for D1C with Truv: 1. Use Truv's VOIE and VOA reports for income, employment, and assets. 2. Retrieve the `voie_report_id` and `voa_report_id` from the order or user reports endpoint — Truv automatically generates them in GSE-compatible format. 3. Submit the IDs through [Desktop Underwriter](https://singlefamily.fanniemae.com/applications-technology/desktop-underwriter) with vendor ID **Truv**. 4. Confirm the loan meets D1C criteria via DU Findings. See the [Day 1 Certainty (D1C)](/mortgage/d1c-aim/fannie-mae) page for the full implementation walkthrough, including the borrower → lender → Truv → DU sequence, Encompass field mapping (`GSEVENDOR.X50` for VOIE, `GSEVENDOR.X37` / `GSEVENDOR.X38` for VOA), and the per-step validation checklist. *** ## Asset and Income Modeler (Freddie Mac) Truv is an AIM service provider for Freddie Mac's Loan Product Advisor. Truv supports three AIM product paths: * **AIM for income and employment** — automated income assessment via Truv's VOIE report. * **AIM for assets** — automated asset assessment from connected bank accounts via Truv's VOA report. * **AIM Check (document income)** — instant paystub and W-2 assessment for borrowers without a direct payroll connection, via Truv Document Processing. To use AIM with Truv: 1. Collect the relevant verification — VOIE, VOA, or AIM Check document income — based on the borrower workflow. 2. Retrieve the report identifier for the product being submitted. 3. Submit through [Loan Product Advisor](https://sf.freddiemac.com/tools-learning/technology-tools/our-solutions/aim-asset-income-modeler) with vendor ID **Truv**. 4. Review the AIM feedback and confirm the assessment matches the loan scenario. See the [Asset and Income Modeler (AIM)](/mortgage/d1c-aim/freddie-mac) page for the full implementation walkthrough, including the borrower → lender → Truv → LPA sequence, Encompass field mapping (`GSEVENDOR.X43` / `GSEVENDOR.X44` for VOA), and validation checklist. *** ## Submission patterns shared across both GSEs * The same `voie_report_id` is accepted by both DU and LPA. There is no separate Freddie-specific VOIE identifier — `freddie_voie_report_id` exists as a legacy field but is not the LPA submission key. * Truv's vendor ID is **Truv** in both DU and LPA. * Refreshed Truv data always produces a new report ID. Replace the older ID before resubmission. * "Current as of" date semantics differ: DU reflects the end of the pay period from the borrower's last pay statement; LPA reflects the pay date. *** ## Next steps Sandbox borrower accounts and pre-generated report IDs for DU and LPA validation Report retrieval patterns and field mapping references Pre-production mortgage validation [support@truv.com](mailto:support@truv.com) # BeSmartee Integration Source: https://docs.truv.com/mortgage/integration/besmartee Verify borrower income and employment within the BeSmartee digital mortgage POS platform Integrating Truv with BeSmartee allows lenders to instantly access and verify borrowers' employment and income details from authenticated payroll sources. This integration enhances the accuracy and speed of the verification process, facilitating quicker loan decisions, all within the BeSmartee point-of-sale system. Quickly verify employment and income during the borrower application Accurate data sourced directly from authenticated payroll accounts Skipped verifications become tasks in the borrower's to-do list for completion later Connected accounts monitored continuously for new payroll documents *** ## How it works During the pre-application phase, borrowers and co-borrowers are prompted to connect their payroll accounts using the **Verify Income** section of their BeSmartee loan application. Once accounts are connected, Truv reports are made available in your connected Loan Origination System (LOS) along with relevant payroll documents. If the Verify Income step is skipped, tasks are automatically assigned to the borrower or co-borrower in their to-do list to complete the verification later. Connected accounts are continuously monitored for new payroll documents, enabling up-to-date verification reports throughout the origination process. *** ## BeSmartee Setup Guide **Step 1:** Contact BeSmartee Customer Success to complete the one-time admin configuration. **Step 2:** Copy your Truv API credentials into the BeSmartee platform: * Log into the [Truv Dashboard](https://dashboard.truv.com) and navigate to **Development → API Keys** * Copy your **Client ID** and **Access Secret** Truv API Keys Dashboard **Step 3:** Configure webhooks in the Truv Dashboard: * BeSmartee utilizes webhooks to listen to events on every order from Truv and get updated statuses. * Ask your BeSmartee Customer Success representative to provide the Sandbox and Production URLs to add to the Truv Dashboard. * Once you have the URLs for both environments, navigate to **Truv Dashboard → Development → Webhooks** and add a URL for your environment. Each environment requires a specific and separate URL. BeSmartee Webhook Configuration **Step 4:** Test the full borrower flow in **Sandbox mode** using Truv's test credentials. **Step 5:** Obtain production access and confirm end-to-end setup with DU (Desktop Underwriter) and LPA (Loan Product Advisor) systems. *** ## Borrower workflow Borrowers enter their employment and income information using the **Verify Income** section of the BeSmartee application. Alternatively, they receive tasks in their **TO-DO list** prompting them to connect their accounts through Truv.