Skip to main content

What is income verification?

Income verification is the process of confirming a borrower’s income and employment status to assess their ability to repay a mortgage loan. Lenders must verify that borrowers have sufficient, stable income to make monthly mortgage payments. Traditionally, income verification has been a manual, time-consuming process requiring borrowers to:
  • Upload pay stubs
  • Provide employment letters
  • Log into employer HRIS systems
  • Submit tax returns and W-2s
  • Manually enter income information
Pylon automates this entire process using Day 1 Certainty (D1C) and Automated Income Model (AIM) approved services that verify income and employment data automatically, reducing manual documentation and speeding up loan processing.

Why D1C/AIM income verification matters

Day 1 Certainty (D1C) and Automated Income Model (AIM) are programs from Fannie Mae and Freddie Mac that allow lenders to use automated verification sources to reduce conditions and speed up loan processing. When income data comes from D1C/AIM approved sources, it’s considered a “verified” source, meaning no additional documentation is typically required, underwriting conditions are reduced, and loan processing is faster.

Pylon’s income verification integrations

Pylon has integrations with two D1C/AIM approved income verification vendors:
  • Truv - Account connection-based income verification (requires borrower opt-in and your API call)
  • The Work Number (TWN) - SSN-based income verification (fully automatic)

Truv

Truv is an account connection-based income verification service that allows borrowers to connect their payroll or bank accounts to automatically verify income and employment data. Pylon is a reseller of Truv and will create an account and API credentials on your behalf. Truv is driven entirely through Pylon’s GraphQL API, and Pylon supports two integration paths depending on who drives the borrower’s connection:
  • Embedded widget — the borrower connects their payroll account in-flow, inside your application, using the Truv Bridge widget.
  • Hosted link — an LO or processor requests a link on the borrower’s behalf and sends it to them (email, text, your own portal). The borrower completes the connection later, out-of-flow, on Truv’s own hosted page. No widget embed required.
Both paths converge on the same backend: once the borrower connects, Pylon pulls the verification of income and employment (VOIE) report, maps income entities, and populates the loan file identically either way.

Choosing an integration path

Both paths require the borrower to opt in and connect their account at some point—Truv income verification is never fully automatic the way The Work Number is. The difference is only when and where that connection happens.

Option 1: Embedded widget (borrower connects in-flow)

Truv flow at a glance

The borrowerId you pass must belong to a loan your credentials can access.

How the embedded widget works

1

Request a bridge token from Pylon

Call the createInitializationToken mutation (under the verify namespace) with vendor: TRUV and the borrower’s ID. Pylon returns a bridgeToken used to initialize the Truv Bridge widget.The mutation returns a CreateInitializationTokenResponse union, so select the TruvBridgeToken member with an inline fragment:
Variables
CreateInitializationTokenInput fields:
  • vendor (VendorName!): TRUV (the VendorName enum is TRUV or PLAID)
  • borrowerId (ID!): the borrower being verified
  • templateId, clientUserId (String): not used for Truv; omit
2

Initialize the Truv Bridge widget

Pass the bridgeToken to the Truv Bridge widget in your frontend. Truv Bridge is a pre-built UI component that handles employer/payroll lookup and the borrower’s secure login.
3

Borrower opts in and connects accounts

The borrower selects their employer or payroll provider and authenticates through Truv’s secure flow. This allows Truv to access payroll and employment information.
4

Exchange the public token with Pylon

When the borrower finishes, the Truv Bridge onSuccess callback hands your frontend a public token and metadata containing a Truv task_id. Pass both back to Pylon via the exchangePublicToken mutation to finalize the connection.
Variables
ExchangePublicTokenInput fields:
  • vendor (VendorName!): TRUV
  • publicToken (String!): the public token from the Bridge onSuccess callback
  • borrowerId (ID!): the same borrower from step 1
  • truvMetadata (TruvExchangeMetadata), required when vendor is TRUV:
    • taskId (String!): the Truv task ID from the onSuccess metadata
    • employerName (String): optional employer name
  • plaidMetadata: not used for Truv; omit
The response is an ExchangePublicTokenResponse union; the TruvLinkAccess member returns linkId (the Truv task ID Pylon now tracks).
You must call exchangePublicToken explicitly. Unlike some embedded SDK integrations where the widget exchanges the token for you, building directly on the GraphQL API means your application is responsible for sending the public token and taskId to Pylon. Skipping this step means Pylon never retrieves the verification data.
5

Pylon retrieves and maps the data

After the exchange, Pylon pulls the VOIE report from Truv asynchronously (Truv notifies Pylon via webhook when the report is ready). Pylon then maps all income types (variable income, commission, bonus, salary, and others) to the appropriate Pylon income entities. No data-mapping work is required on your end.
6

Read the verified data

Once mapping completes, the verified amount lands on each Income entity’s verifiedAmount field, with a voieReportId referencing the source report. Poll the GraphQL API to detect completion (see Checking income verification status). Since the data comes from Truv (a D1C and AIM approved source), no additional income documentation is typically required.

End-to-end example (Node.js/TypeScript)

This example shows the two server-side calls that bookend the Truv Bridge widget: requesting the bridge token, and exchanging the public token your frontend receives from the onSuccess callback.

Embedded widget characteristics

  • Client opt-in required: Borrowers must opt in and connect their accounts through Truv’s connection flow
  • You must drive it: The flow runs through the verify mutations and the Truv Bridge widget; it does not happen automatically
  • Asynchronous completion: Verification data is retrieved by Pylon in the background after the exchange; poll verifiedAmount to detect when it’s ready
  • >95% coverage: Truv has over 95% coverage of employers and payroll providers
  • Lower production costs: Cheaper production costs compared to The Work Number
  • Pylon handles data mapping: Pylon automatically maps all income types (variable, commission, bonus, salary, etc.) to appropriate Pylon fields; no work required on your end
Instead of embedding a widget in your own frontend, you can ask Pylon to create a hosted verification link and send it to the borrower yourself—by email, text, or through your own portal. The borrower opens the link later and completes the connection on Truv’s hosted page, entirely outside your application. There is no widget to embed and no onSuccess callback to wire up.
Off by default. This path needs to be enabled for your organization before you can call requestOrder—the embedded widget flow is unaffected either way. Ask your account manager to turn it on.
This path requires the update:loan scope (the embedded widget’s verify mutations require update:borrower).
1

Request an order from Pylon

Call the requestOrder mutation under the incomeVerification namespace with the borrower’s ID. Pylon creates the order with Truv and returns a shareUrl—the borrower-facing hosted link—along with the order’s status and expiresAt.
Variables
RequestOrderInput fields:
  • borrowerId (ID!): the borrower being verified
RequestOrderResponse fields:
  • orderId (String!): Pylon’s ID for this order; pass it to cancelOrder
  • status (IncomeVerificationOrderStatus!): PENDING, COMPLETED, CANCELED, or FAILED—a freshly created order is always PENDING
  • expiresAt (DateTime!): when the link stops being usable
  • shareUrl (String): the hosted link to send the borrower; null if the order has no usable link
  • existingOrderReused (Boolean!): true if the borrower already had a live, unexpired order and Pylon returned it instead of creating a duplicate
Requesting again is safe. If a borrower already has a pending, unexpired order, Pylon returns that same order (existingOrderReused: true) rather than creating a second link. You don’t need to track order state yourself to avoid duplicates.
2

Send the link to the borrower

Deliver shareUrl to the borrower through whatever channel your application uses—email, SMS, an in-app notification, or your own borrower portal. Pylon does not deliver the link on your behalf.
3

Borrower connects on Truv's hosted page

The borrower opens the link at any point before expiresAt, selects their employer or payroll provider, and authenticates through Truv’s own hosted flow—no widget embed, and no active session in your application required.
4

Pylon retrieves and maps the data

Exactly as with the embedded widget: once the borrower connects, Pylon pulls the VOIE report from Truv asynchronously and maps income types to the appropriate Pylon income entities. No data-mapping work is required on your end.
5

Read the verified data

Once mapping completes, the verified amount lands on each Income entity’s verifiedAmount field, with a voieReportId referencing the source report. Poll the GraphQL API to detect completion (see Checking income verification status).

Checking and canceling orders

Use incomeVerification.orders to list a borrower’s recent orders—for example, to show an LO whether a link is still live before deciding to send a new one:
This returns the borrower’s 10 most recent orders, newest first. shareUrl is only populated while an order is PENDING and unexpired—expired, completed, canceled, or failed orders return null. To cancel a still-pending order (for example, if it was sent to the wrong borrower or is no longer needed), call cancelOrder:
Variables
Cancellation is a race, not a guarantee. If the borrower completes verification while your cancel request is in flight, Pylon treats the completed verification as the terminal outcome: the response comes back with status: COMPLETED, not CANCELED. Branch your UI on the returned status rather than assuming the cancel always succeeds.
  • No widget required: Two GraphQL calls—no Truv Bridge SDK, no onSuccess callback to wire up
  • Out-of-flow: The borrower can complete verification later, from an email or text, entirely outside your application session
  • You initiate it: An LO, processor, or your API caller explicitly requests the order—it does not happen automatically for every borrower
  • You own delivery: Pylon returns shareUrl; sending it to the borrower is your responsibility
  • Single live link per borrower: Requesting again while a link is pending and unexpired returns the existing order instead of creating a duplicate
  • Cancelable: Cancel a still-pending order, with the caveat that a borrower who finishes mid-cancellation settles as COMPLETED
  • Off by default: Ask your account manager to enable this capability for your organization before using it
  • Same downstream pipeline: Once the borrower connects, data retrieval, income mapping, and rep/warrant tracking work identically to the embedded widget path

The Work Number (TWN)

The Work Number (TWN) is a comprehensive employment and income verification service that maintains a database of verified employment and payroll data from thousands of employers and payroll providers across the United States.

How The Work Number works

1

Credit pull collects SSN

When you pull credit for a borrower, you collect their Social Security Number (SSN) as part of the credit pull process. This SSN is the only information needed for income verification through The Work Number.
2

Pylon automatically triggers verification

Pylon automatically triggers income verification through The Work Number in the background. No customer opt-in or flow is required to initialize-it happens automatically once the SSN is available.
3

Pylon queries The Work Number

Pylon uses the borrower’s SSN to query The Work Number’s database for verified income and employment data. This happens automatically-no API calls or requests from you are needed.
4

Pylon uses verified data

If the borrower’s employer is covered by The Work Number, verified income and employment data is automatically retrieved and stored in the loan file. Pylon uses this verified data for underwriting and pricing calculations.
5

No additional documentation needed

Since the data comes from The Work Number (a D1C and AIM approved source), no additional income documentation is typically required. Pylon’s underwriting system accepts the verified data without additional documentation.

The Work Number characteristics

  • SSN-based: Only requires the borrower’s Social Security Number (collected during credit pull)
  • Fully automatic: Pylon automatically triggers verification-no borrower opt-in, no flow to initialize, and no API calls required from you
  • Higher production costs: Much higher production costs compared to Truv (in the range of 5x)
  • Charged on re-pull: Costs are incurred on each verification pull, including re-pulls

Programmatic configuration and cost considerations

Cost impact: The Work Number is approximately 5x more expensive than other verification sources like Truv. Given this cost difference, it’s important to be thoughtful about application-to-funded loan ratios when configuring The Work Number programmatically.
Reach out to your account manager to discuss programmatic configuration of The Work Number. Because The Work Number is charged on each verification pull (including re-pulls), and Pylon covers the cost of unfunded loans in the closed per loan fee, high application-to-funded loan ratios can significantly impact your per-funded-loan underwriting fee. Key considerations:
  • Application-to-funded ratio: If you have a high dropout rate (many applications that don’t result in funded loans), the cost of The Work Number verifications per funded loan increases substantially
  • Per-funded-loan impact: Since Pylon covers unfunded loan costs in the closed per loan fee, using The Work Number when you have a low application-to-funded ratio may require adjusting your per-funded-loan underwriting fee
  • Vendor waterfall strategy: Consider implementing a vendor waterfall that prioritizes lower-cost options (like Truv) before falling back to The Work Number, especially if your application-to-funded ratio is low
Your account manager can help you:
  • Configure when The Work Number should be triggered programmatically
  • Understand the cost implications based on your application-to-funded ratio
  • Implement vendor waterfall strategies to optimize costs
  • Adjust pricing structures if needed

Checking income verification status

After income verification is initiated (automatically for The Work Number, or after borrower opt-in for Truv), check the verifiedAmount field on the Income entity to see if verification was successful. When verifiedAmount has a value, income has been verified through Truv or The Work Number, and Pylon will use this verified data for underwriting without requiring additional documentation. For complete details on querying income data, understanding income states (stated, qualified, verified), and all income fields, see the Incomes entity guide.

GraphQL query example

Poll Pylon’s GraphQL API to check for verified income values. The verifiedAmount field will be populated when income has been successfully verified through Truv or The Work Number:
Key fields:
  • verifiedAmount: The verified monthly income amount. null if not yet verified, or a number if verified through Truv or The Work Number
  • voieReportId: The ID of the source verification of income and employment (VOIE) report. Populated alongside verifiedAmount when income is verified through Truv
  • statedMonthlyAmount: The borrower’s stated monthly income amount
  • __typename: The concrete income kind (e.g., StandardEmploymentIncome), used to select the matching inline fragment
Verification status:
  • verifiedAmount === null: Income has not been verified yet, or verification is not available
  • verifiedAmount > 0: Income has been successfully verified through D1C/AIM approved sources

Node.js/TypeScript polling example

Here’s a complete example of polling for verified income values using Node.js and TypeScript:
Key implementation details:
  • Polling strategy: The function polls at regular intervals (default: every 2 seconds) until verified incomes are found or max attempts are reached
  • Verification check: Checks if verifiedAmount is not null and greater than 0
  • Error handling: Includes error handling and fallback logic for when verification isn’t available
  • Multiple borrowers: Handles loans with multiple borrowers and collects all incomes
  • Pagination: The example shows pagination structure, though you may need to implement cursor-based pagination for loans with many incomes

Benefits

For borrowers

  • No document upload: No need to upload pay stubs, employment letters, or tax documents when verification is successful
  • No HRIS login: Borrowers don’t need to log into their employer’s HRIS system or payroll portal
  • Faster processing: Automated verification is faster than manual document review

For lenders

  • Reduced conditions: Pylon’s underwriting system generates fewer conditions when income is verified through D1C/AIM sources
  • Fewer borrower tasks: Pylon creates fewer tasks for borrowers when verification is successful
  • Faster closes: Pylon’s automated processing accelerates loan processing and reduces time to close
  • Better accuracy: Verified data from Truv or The Work Number is more accurate than manual entry or document review
  • Cost savings: Reduced manual processing and document review costs (with Truv offering lower production costs)

Limitations and fallbacks

When automated verification doesn’t work

Income verification through Truv or The Work Number may not be available if:
  • Truv opt-in not completed: The borrower didn’t opt in to Truv or didn’t complete the account connection process
  • Employer not covered: The borrower’s employer doesn’t participate in The Work Number
  • Self-employed borrowers: Both Truv and The Work Number are primarily for W-2 employees. Self-employed borrowers require different verification methods (tax returns, profit & loss statements, etc.)
  • Recent employment changes: If a borrower recently changed employers, verification services may not have the latest information yet
  • Contractor or gig workers: Non-traditional employment arrangements may not be covered

Fallback to traditional methods

When automatic verification isn’t available, Pylon will request traditional income verification documentation from borrowers:
  • Pay stubs: Recent pay stubs (typically 2-3 months)
  • Employment letters: Employment verification letters from employers
  • Tax returns: For self-employed borrowers, tax returns and profit & loss statements
  • W-2s and 1099s: Tax documents for income verification
  • Bank statements: Bank statements to verify income deposits
Always have a fallback: Don’t assume all borrowers will have income verified through Truv or The Work Number. Truv requires borrower opt-in, and The Work Number may not cover all employers. Always be prepared to use traditional verification methods when automated verification isn’t available.

Best practices

Monitoring verification status

  • Poll regularly: Check income verification status as part of your loan status polling workflow
  • For Truv (embedded widget): Drive the flow through the verify GraphQL mutations: createInitializationToken to get a bridge token, then exchangePublicToken after the borrower completes Truv Bridge. Verification data is then retrieved asynchronously by Pylon
  • For Truv (hosted link): Call incomeVerification.requestOrder and send the returned shareUrl to the borrower yourself; poll incomeVerification.orders if you need to check whether a link is still live before sending a new one
  • For The Work Number: No action required-verification happens automatically once SSN is available
  • Handle failures gracefully: If verification fails or isn’t available, immediately switch to traditional verification methods

Using verified data

  • Combine with other verifications: Use Truv or The Work Number alongside other D1C/AIM approved sources (like Plaid for assets) for maximum benefit
  • Pylon updates pricing automatically: Once income is verified, Pylon automatically recalculates pricing and eligibility, as verified income may affect loan terms
  • Incomes - Complete guide to the Income entity, including all income types, states (stated, qualified, verified), and fields
  • Day 1 Certainty & AIM Overview - Learn about D1C and AIM programs and their benefits
  • Asset Verification - Learn about Plaid for automatic asset verification
  • Credit Pulls - Understand credit pull requirements (SSN is collected here for income verification)
  • Order-Outs Overview - Understand when order-outs and verifications are triggered