payroll scenario pairs a login with the employments, paystubs, W-2s, bank accounts, and shifts you want back, and serves them when the user signs in with that login in Truv Bridge. It drives every payroll product: Income & Employment, Employment History, Direct Deposit Switch, and Paycheck Linked Lending.
Use it when the built-in payroll credentials don’t cover the case you need: a specific pay frequency, a terminated employment, a second job, or income near your approval threshold. For the shared concepts, read Custom Sandbox Data first.
Create a scenario [Server-side]
This request creates a scenario with one salaried employment and one paystub:Send
"data_source": "payroll" explicitly. username and password are supported on payroll, financial accounts, and insurance, so Truv can’t infer the data source from them and refuses the request with data_source_required. Only company_domain fits payroll alone, so a scenario that sets it can leave data_source out.Use it in Bridge
Start a sandbox verification the way you normally do. In Truv Bridge, select Truv Payroll Provider and sign in withacme.salaried / s4ndb0x. The task completes with your data instead of Truv’s built-in test data. Read the result the same way as for any other connection: from the task webhooks and the income and employment report.
The scenario above sets neither provider_id nor company_domain, so any payroll provider works in sandbox. If your scenario sets either field, use a connection that matches those values.
Full sample: profile, bank account, and two paystubs with year-to-date totals
Full sample: profile, bank account, and two paystubs with year-to-date totals
This request fills every section of an employment. It creates a separate scenario,
acme.full, so it doesn’t collide with the one above.The response
The response is the stored scenario, with the fields you left out filled in with their defaults. The request sent no behavior fields, so the task completes withdone, with no delay and no MFA. The payload is abbreviated here; the API returns it in full.
filenames, ssn_last4, and date_of_birth are matching fields for other data sources, so they stay empty on a payroll scenario.
Matching fields
These fields decide which login the scenario answers. A field you leave out narrows nothing, so it matches any value. Set at least one ofusername, password, provider_id, or company_domain; is_refresh doesn’t count on its own.
products restricts the scenario to a subset of income, employment, deposit_switch, and pll. Empty, the default, matches every payroll product.
Behavior
A payroll scenario supports everybehavior_status and replays behavior_mfa at login. The payroll sandbox acts on every status except unable_to_reset, which it treats as a successful login. See Behavior for the fields.
Payload reference
Thepayload object contains an employments array and optional flags. The tables below describe the fields in each employment record. Every field is optional unless noted: send only what your test needs, and leave the rest out.
employments[]
employments[]
employments[].profile
employments[].profile
employments[].company
employments[].company
employments[].paystubs[]
employments[].paystubs[]
employments[].bank_accounts[]
employments[].bank_accounts[]
employments[].w2s[]
employments[].w2s[]
employments[].shifts[]
employments[].shifts[]
flags
flags
Fraud markers reported alongside the data, at the top level of the payload next to
employments.Money and quantities are decimal strings, so nothing is lost to floating point:
"4615.38", not 4615.38.Examples
Each example is a request body forPOST /v1/sandbox/scenarios/ and creates a new scenario. Send it with the same curl command as the first scenario. The hourly, two-job, terminated, and failing-login bodies are complete. The rest are abbreviated to the fields the example is about, and each one says so above its code block.
Hourly employee with overtime
Express an hourly wage asincome plus income_unit: "HOURLY", and put the hours on the paystub.
Two employments
Return a second job by adding another entry toemployments. Up to 10 fit in one scenario.
Terminated employment
Setend_date and is_active: false. end_date can equal start_date but not precede it.
Failing login
A failure status needs no payload. Use it to exercise the error paths in your integration.Slow task
Delay the task before it finishes, up to 120 seconds, to test loading states and webhook ordering.MFA challenge
behavior_mfa.challenges replays one screen per entry, in order. A TEXT challenge prompts for a code; an OPTIONS challenge renders a select. A challenge with neither answer nor answers accepts anything the user types.
answers when more than one response is acceptable. Up to 5 challenges per scenario.
Refresh-only data
Set the data a data refresh should find by restricting a scenario to refreshes withis_refresh: true. On a refresh it wins over the general scenario for the same login, because it sets is_refresh and the other doesn’t. Create it alongside the acme.salaried scenario; don’t update that one.
acme.salaried and gets the original data; the refresh of that same connection gets the raised income.
Restrict a scenario to one provider or employer
Addprovider_id or company_domain to answer only connections that went through a specific provider or employer. This is how the same login returns different data depending on where the user connected. Create it alongside the acme.salaried scenario: the extra matching field makes it more specific, so it wins for ADP connections.
company_domain matches the employer the user selects through company search in Truv Bridge, the domain that Search companies returns. A user who picks a provider directly, such as Truv Payroll Provider, selects no employer, so a scenario that sets company_domain doesn’t match their connection.
Attach PDFs
A paystub or W-2 can carry a real file. Upload it to your sandbox document library once, then reference it by id from as many scenarios as you like. A paystub’s file is optional; every W-2 needs one, because a W-2 with nothing behind it is dropped when the task is served.1
Upload the paystub PDF
Send the file as The response is the library entry. Keep the top-level
multipart/form-data. filename is a separate field: it is the name the entry is addressed by, and it does not have to match the name on disk.id: that is the document_id your payload references.documents is test metadata you configure for the file, not data extracted from it. You didn’t send it, so the entry got the default: one paystub for John Doe at Acme Inc. Only document upload scenarios read it. A payroll scenario serves the file and ignores it, so leave it out.2
Upload the W-2 PDF
The same endpoint also takes a JSON body, with the bytes base64-encoded in The response has the same shape as the multipart one.
content. Use whichever transport suits your client, and send exactly one of file or content, never both.validations and documents are abbreviated here.3
Reference both from a scenario
Put each Sign in with
id on the record it belongs to: the paystub’s file on the paystub, the W-2’s file on the W-2.acme.documents / s4ndb0x and the completed task carries both PDFs, downloadable through the same endpoints as any other connection: Pay Statements for the paystub and Tax Documents for the W-2.Limits
These are the default limits for payroll payloads. The account-wide limits are listed on Custom Sandbox Data.Next steps
Income & Employment Testing
Truv’s built-in payroll credentials and sample reports
Document upload scenarios
Serve the same employment data from uploaded documents
Data refresh
How refreshes reach your
is_refresh scenariosSandbox API reference
Full request and response schemas for every sandbox endpoint