Sandbox
Test Console
Prior to diving in with development work, we recommend familiarizing yourself with Link in our Test Console. The Link Test Console lives in the Dashboard and will allow you to create Link tokens and launch Pinwheel Link. The Test Console mimics Link token creation and allows you to see how different configurations affect the front-end UI. If you don't have access to the Dashboard, please contact [email protected].
In Sandbox mode, you must use our Sandbox credentials. Live credentials will not work in Sandbox. In order to test with live payroll credentials, you can use our Development Environment.
Sandbox Credentials
In Sandbox mode, you can use the following credentials to test Link:
Field | Value |
---|---|
Company ID | company_good |
Username | user_good * |
[email protected] | |
Password | pass_good |
SSN | 123456789 |
Last 4 of SSN | 1234 |
MFA code | mfa_code |
What street did you grow up on? | pinwheel drive |
*For USPS ONLY: Username value is "12345678"
For providers that support optional multifactor authentication (MFA), use the following credentials to test the MFA flow:
Field | Value |
---|---|
Username | user_mfa |
Email | [email protected] |
To test Direct Deposit Forms use the following credentials:
Field | Value |
---|---|
Username | user_dd_form |
To test jobs with an outcome
of error
, use the following credentials. Additional error cases are covered in the section below.
Field | Value |
---|---|
Username | user_error |
Email | [email protected] |
To test jobs with an outcome
of pending
, use the following credentials:
Field | Value |
---|---|
Username | user_pending |
Email | [email protected] |
To test a direct deposit with an error outcome followed by a successful card switch, use the following credentials:
Field | Value |
---|---|
Username | user_dd_error |
[email protected] |
To test a successful direct deposit followed by a card switch with an error outcome, use the following credentials:
Field | Value |
---|---|
Username | user_card_error |
[email protected] |
Note
In sandbox mode, jobs with a
pending
outcome will transition to anerror
outcome 60 seconds after the Link flow is completed. If you are subscribed to webhook events in Sandbox mode, you will first get an event with apending
outcome, followed by an event with anerror
outcome.In Production, jobs may remain in
pending
for up to 24 hours.
On Demand Updates
On Demand Updates may require user re-authentication before I&E data can be refreshed or a direct deposit switch is performed. The monitoring_status
of an account will indicate whether a user re-authentication is needed or not. For the sandbox experience, we will focus on active
and user_action_required
states.
Getting started
An existing sandbox account initially connected with one of the following usernames is required before performing an On Demand Update. Each username corresponds to a re-authentication flow.
Re-authentication flow to simulate | Sandbox username |
---|---|
MFA required | user_mfa |
Credentials required | user_good |
Credentials and MFA required | user_credentials_and_mfa |
Updating monitoring_status of an Account
The PATCH /v1/sandbox/accounts/{account_id}
sandbox-only endpoint can be used to simulate an account going into the user_action_required
state by forcing an account with monitoring_status = active
to monitoring_status = user_action_required
When the monitoring_status
changes for an account, you will receive an account.monitoring_status.updated webhook event as you would in Production. Once an account is in monitoring_status = user_action_required
, re-authentication is required to get the account back to the monitoring_status = active
state.
Simulating On Demand Update Re-authentication
Once the account is in the user_action_required
state, you can launch Link with an On Demand Update and the experience will simulate what users will see when re-authentication is required for the account.
*Note that an account in the active
state will not require re-authentication for On Demand Updates.
Limitation
Sandbox payroll accounts older than 7 days will default to requiring MFA and not follow the behavior associated with their username.
Earnings Stream
Earnings Stream can be tested in sandbox by leveraging user credentials to trigger specific scenarios.
Getting Started
The first step is to register a webhook with the earnings_stream.payouts.refreshed webhook event. For an introduction to webhooks, please read this.
Next, use the Test Console to create a Link Token.
end_user_id
must be provided to use Earnings Stream. Read the User Model documentation for details.
Select paystubs
in required_jobs
and provide a User Model end_user_id
.
Create a Link Token, launch the Link Modal and select ADP as the payroll provider.
You will provide different usernames to trigger different endpoint and webhook event scenarios. Use the password pass_good
for all of the scenarios below.
Trigger an available state with:
Username | Behavior |
---|---|
earnings_stream_payouts_available | This represents a hourly worker with shifts. The endpoint will be populated with valid estimated payout information and processed payout records going back to around one year. A webhook event will be sent with payload.availability set to available for all earnings_accrued subfields. |
earnings_stream_payouts_available_salaried | This represents a salaried worker with no shifts. The endpoint will be populated with valid estimated payout information and processed payout records going back to around January 1st, 2022. A webhook event will be sent with payload.availability set to available for payouts_estimated.earnings_accrued and payouts_processed.earnings_unknown subfields. |
earnings_stream_payouts_available_snp | This represents a new hourly worker with shifts and no paystubs. The endpoint will be populated with valid estimated payout information and processed payout records going back to around January 1st, 2022. A webhook event will be sent with payload.availability set to available for payouts_estimated.earnings_accrued and unavailable for payouts.processed subfields. |
You can trigger different unavailable states, which will have empty responses in the endpoint and the following payload.unavailable_reasons
in the webhook event:
Username | payload.unavailable_reason |
---|---|
payouts_unavailable_temporary_outage | temporary_outage |
payouts_unavailable_employer_not_supported | employer_not_supported |
payouts_unavailable_waiting_for_work | user_action_waiting_for_work |
payouts_unavailable_new_employee | user_action_new_employee |
payouts_unavailable_undetermined | user_action_undetermined |
Refreshing Data
Once a user is connected, you can refresh their data by triggering an On Demand Update. Once the user is re-authenticated, we will send another earnings_stream.payouts.refreshed webhook event to let you know how the user's payouts have changed. The refreshed_at
field in the payload will show when we last refreshed the payouts data, while the updated_at
field will show when the payouts last changed.
Verification Reports
Verification Reports can be tested in sandbox by leveraging user credentials to trigger specific scenarios.
Getting Started
There are a few steps required to use verification reports:
- The first step is to register a webhook with the verification_reports.refreshed webhook event. For an introduction to webhooks, please read this.
- Next, use the Test Console to create a Link Token. Note that
end_user_id
must be provided to use Verification Reports. Read the User Model documentation for details. - Select at least
identity
andemployment
inrequired_jobs
(income
is required to generate a VOIE report, andpaystubs
is required to see meaningful numbers in some parts of the report), and provide anend_user_id
. - Create a Link Token, launch the Link Modal and select ADP as the payroll provider.
You will provide different username to trigger different endpoint and webhook event scenarios. Use the password pass_good
for all of the scenarios below.
Trigger an available state with:
Username | Behavior |
---|---|
voe_and_voie_available | Both the Verification of Employment and Verification of Income & Employment reports are available. Both the VOE and VOIE endpoints will return the full set of data including paystubs for VOIE. A webhook event will be sent with voe and voie availability set to available . |
voe_and_voie_available_no_paystubs | This represents a user with identity, employment, and income details but no paystubs. The user could have recently started work with this employer and hasn't received a paystub yet. Both the Verification of Employment and Verification of Income & Employment reports are available. The VOIE report will be missing paystubs data. Both the VOE and VOIE endpoints will return data. A webhook event will be sent with voe and voie availability set to available . |
voe_available_voie_unavailable | This represents a user with identity and employment data but no income or paystubs data. Only the Verification of Employment report is available. The VOE endpoint will return data while the VOIE endpoint will return a 404 error. A webhook event will be sent with voe availability set to available and voie availability set to unavailable . |
voe_and_voie_unavailable | This represents a user with required data missing to generate both reports (at minimum, identity and employment data is required to generate a report). Both the VOE and VOIE endpoints will return a 404 error. A webhook event will be sent with voe and voie availability set to unavailable . |
Verification Reports Multiple Employments
The sandbox scenarios in the previous section can be used to test out the basic structure of the report and webhooks. The scenarios in this section show what a verification report looks like if a single end user has multiple payroll accounts. When a single end_user_id
is associated with multiple payroll accounts, the resulting verification report will include multiple employments (up to 3), with active employments listed first, ordered by end date, duration, and the employer name.
For all of these usernames, both the VOE and VOIE endpoints will return data, and
a webhook event will be sent with voe
and voie
availability set to available
.
Username | Behavior |
---|---|
voe_and_voie_available_active_long | This represents a user with an active employment that has a long duration. The employment name in the report will be Tortoise Company |
voe_and_voie_available_active_long_no_paystubs | This represents a user with an active employment that has a long duration. The employment name in the report will also be Tortoise Company |
voe_and_voie_available_active_short | This represents a user with an active employment that has a short duration. The employment name in the report will be Hare Incorporated |
voe_and_voie_available_inactive_long | This represents a user with a terminated employment that has a long duration. The employment name in the report will be Terminated Tortoise Company |
voe_and_voie_available_inactive_short | This represents a user with a terminated employment that has a short duration. The employment name in the report will be Terminated Hare Incorporated |
To use these usernames to generate a verification report with multiple employments:
- Create a link token with an
end_user_id
, and with at leastidentity
andemployment
in required jobs (income
is required to generate a VOIE report, andpaystubs
is required to see meaningful numbers in some parts of the report). - Launch Link modal, and select any payroll plaform.
- Log in using any of the above usernames (for example
voe_and_voie_available_inactive_short
) withpass_good
as the password (and any other applicable IDs such ascompany_id
which should be displayed) - Exit Link modal after seeing the success screen
- Create a second link token with the same end user ID as step 1 (and the same required jobs)
- Launch Link modal, and select any payroll plaform.
- Log in using a different one of the above usernames (for example
voe_and_voie_available_active_long
) withpass_good
as the password (and any other applicable IDs such ascompany_id
which should be displayed) - Exit Link modal after seeing the success screen
- (Optionally) Repeat steps 5-8 using other usernames
After completing these steps, when you query for a report, you will see up to 3 employments. They will be in the order shown in the table, regardless of which order you authenticate into them (and if you authenticate with more than 3, the report will show the first 3 using the order in the table).
In addition, in the PDF of the VOIE report, you will see a rollup of the annual incomes from all 3 employments.
Additional Error Cases
If you would like to test specific Job Errors, use the credentials below. Errors that are job-specific will have a note called out in the description.
Platform Selection in Sandbox
We have thousands of integrations into various payroll platforms, each with its own unique features and ways of working. As such, Sandbox is not an exact duplicate of our Production environment. To test the following errors and see the corresponding experience within the Link UI, we recommend that you test with
ADP
.
Login errors
If a login job ends with an error (e.g. the user didn't log in), no webhook event will be sent, as no connection was established.
changePasswordRequired
changePasswordRequired
This error indicates that the user must update their password before logging in.
Field | Value |
---|---|
Username | user_change_password_required |
Password | pass_good |
accountNotActive
accountNotActive
This error is thrown when a user attempts to login to an inactive account (e.g. if they've been terminated and have lost access).
Field | Value |
---|---|
Username | user_account_not_active |
Password | pass_good |
accountLoggedIn
accountLoggedIn
This error is thrown when the platform detects that the user is logged in via another mechanism.
Field | Value |
---|---|
Username | user_account_logged_in |
Password | pass_good |
mfaSetupRequired
mfaSetupRequired
This error is thrown when MFA setup is required by the platform, for example in the initial login. It's important to note that this error may potentially arise within both the login and direct deposit flows.
Field | Value |
---|---|
Username | user_mfa_setup_required |
Password | pass_good |
locationRestricted
locationRestricted
This error is thrown when the platform cannot be accessed at the user's current location (e.g. some employers restrict access to corporate networks, or from specific IPs or locations).
Field | Value |
---|---|
Username | user_location_restricted |
Password | pass_good |
emailNotRegistered
emailNotRegistered
This error is thrown when the email address provided by the user has not been registered with the payroll platform. This error can relate to both Username
or Email
being invalid. Unlike the invalidCredentials
error, where a platform could recognize the user but their credentials could be invalid for login, this error represents instances when a user cannot be recognized by the platform at all.
Field | Value |
---|---|
Username | user_email_not_registered |
Password | pass_good |
maxFailedAttempts
maxFailedAttempts
This error is thrown when a user reaches the maximum number of login attempts (e.g. when entering MFA code). Prior to seeing this error in Sandbox, you will be prompted to enter an MFA code 3 times (invalidMfaCode
failure will be returned each time).
Field | Value |
---|---|
Username | user_max_failed_attempts |
Password | pass_good |
MFA code | mfa_code or any valid string |
mfaTimeExceeded
mfaTimeExceeded
This error is thrown when the request to submit an MFA code surpasses the time limit. It often happens when a user's submitted MFA code is rejected by the platform; and normally there is an option to retry. With this specific scenario, we raise the error during the first attempt (regardless of the wait time). Subsequently, the login flow will succeed on the second attempt.
Field | Value |
---|---|
Username | user_mfa_time_exceeded |
Password | pass_good |
MFA code | mfa_code for both attempts |
challengeAnswerIncorrect
challengeAnswerIncorrect
This error is thrown when the answer provided for the challenge question was invalid (e.g. during an MFA step). Sandbox will raise this error 3 times while prompting you to enter an answer to the security question. Note that after 3 failed attempts (they are all set to fail no matter what), maxFailedAttempts
error is returned.
Field | Value |
---|---|
Username | user_challenge_answer_incorrect |
Password | pass_good |
Security question answer | security_answer_good or pinwheel drive |
passwordsNotEqual
passwordsNotEqual
This error is thrown in the password reset flow, when a password and its confirmation do not match. To mimic the behavior we see natively in platforms, changePasswordRequired
error will be raised first, then you will be prompted to reset the password 3 times, each time passwordsNotEqual
error will be raised. Note that after 3 failed attempts (they are all set to fail as long as passwords don't match), maxFailedAttempts
error is returned.
Field | Value |
---|---|
Username | user_passwords_not_equal |
Password | pass_good |
Confirm password | any valid string, but cannot match Password |
Direct Deposit Switch errors
Shared Errors
In Production, errors marked with
*
can appear in both Login and Direct Deposit Switch flows. In Sandbox mode, these will be raised during the Direct Deposit Switch job.
systemError
*
systemError
*An unhandled error when a payroll integration behaves in an unexpected manner. We have internal processes to triage and fix these errors such that subsequent users do not trigger them.
Field | Value |
---|---|
Username | user_system_error |
Password | pass_good |
accountLocked
*
accountLocked
*This error is thrown when the user's account has been locked. Generally, users will need to reach out to their HR Admin to proceed.
Field | Value |
---|---|
Username | user_account_locked |
Password | pass_good |
contactHelpDesk
*
contactHelpDesk
*This error is thrown when the user needs to contact their payroll admin in order to continue.
Field | Value |
---|---|
Username | user_contact_help_desk |
Password | pass_good |
directDepositDisabled
directDepositDisabled
This error is thrown when the account does not support any updates to direct deposit settings (e.g. the employer has disabled the ability to update settings within the online portal).
Field | Value |
---|---|
Username | user_direct_deposit_disabled |
Password | pass_good |
sessionTimeout
*
sessionTimeout
*This error occurs when the session closes after a period of inactivity (e.g. due to lack of user action).
Field | Value |
---|---|
Username | user_session_timeout |
Password | pass_good |
platformError
*
platformError
*This error is thrown when there is an issue with the underlying payroll platform. Although our connection is behaving as expected, the platform itself is not working as expected.
Field | Value |
---|---|
Username | user_platform_error |
Password | pass_good |
platformUnavailable
*
platformUnavailable
*This error is thrown when a payroll platform is unavailable or partially unavailable. This usually happens due to routine maintenances, which can cause failures to any part of the Pinwheel flow. This scenario showcases a failure that occurred within the direct deposit flow, indicating that the login might still be successful.
Field | Value |
---|---|
Username | user_platform_unavailable |
Password | pass_good |
routingNumberRejected
routingNumberRejected
This error is thrown when the routing number provided in the Link token is rejected by the platform's validation logic.
Field | Value |
---|---|
Username | user_routing_number_rejected |
Password | pass_good |
invalidExistingSplit
invalidExistingSplit
This error is thrown when the user's account does not support the requested change (e.g. a user attempts to add a fixed amount allocation to an account that has an existing percentage allocation). Validation rules vary from platform to platform.
Field | Value |
---|---|
Username | user_invalid_existing_split |
Password | pass_good |
changesTemporarilyDisabled
changesTemporarilyDisabled
This error is thrown when a change is rejected due to existing changes that are still pending on the account (e.g. a direct deposit switch has been submitted and is pending processing).
Field | Value |
---|---|
Username | user_changes_temporarily_disabled |
Password | pass_good |
maxAccounts
maxAccounts
This error is thrown when a user has reached the maximum number of permitted direct deposit allocations, such that a new one cannot be added.
Field | Value |
---|---|
Username | user_max_accounts |
Password | pass_good |
validationFailed
validationFailed
This is a catch-all error that is thrown to capture account data validation issues.
Field | Value |
---|---|
Username | user_validation_failed |
Password | pass_good |
invalidInput
*
invalidInput
*This is a catch-all error that is thrown to capture generic input errors.
Field | Value |
---|---|
Username | user_invalid_input |
Password | pass_good |
Income and Employment job errors
dataNotAvailable
dataNotAvailable
This error occurs only for Income and Employment jobs. It occurs when the user's payroll platform does not surface the data requested. The availability of data varies within platform, employer, and employee combinations.
Field | Value |
---|---|
Username | user_data_not_available |
Password | pass_good |
dataNotRefreshable
dataNotRefreshable
This error occurs only for Income and Employment jobs. It is raised when the user's payroll platform is able to surface the data requested when the user starts a new link session, but not when the job is run via refresh. The availability of data sometimes requires user action, such as an MFA code input, in order retrieve the requested data.
Field | Value |
---|---|
Username | user_data_not_refreshable |
Password | pass_good |
directDepositAllocationsDisabled
directDepositAllocationsDisabled
This error is thrown when the account does not support the ability to read its allocations settings. For this set of credentials, this error will be thrown for the Direct Deposit Allocations job, along with directDepositDisabled
for the Direct Deposit Switch job.
Field | Value |
---|---|
Username | user_direct_deposit_allocations_disabled |
Password | pass_good |
Document Uploads
The document uploads functionality (implementation guide here) has a number of sandbox scenarios you can test out. However, there is no payroll account authentication in this flow, so there is no place to enter a username or password. Instead, different scenarios are keyed off of the filename of the file(s) you are uploading. Here is a list of the different filenames and a description of the scenario triggered:
Filename Substring | Scenario Description |
---|---|
doc_uploads_antivirus_fail | The uploaded file fails an antivirus check. As a result, the document is not persisted, and a document.added webhook is sent with outcome error . |
doc_uploads_unsupported_doc_type | The uploaded file is an unsupported document. As a result, the document is not persisted, and a document.added webhook is sent with outcome error . |
doc_uploads_fraudulent_suspected | The uploaded document is suspected to be fraudulent. The fake sandbox placeholder document is still persisted, and the document.added webhook is sent with outcome success . The fraud signal is shown in the API call. |
doc_uploads_no_parsed_data | The uploaded document has no parsed data available. The fake sandbox placeholder document is still persisted, and the document.added webhook is sent with outcome success . The API response has no parsed data in it. |
Any other filename | The uploaded document has parsed data available. The fake sandbox placeholder document is persisted, and the document.added webhook is sent with outcome success . The API response has parsed_data populated, and the fraud object shows that fraud is not_suspected . |
We match the scenarios based on substrings, i.e. if you upload a file called doc_uploads_antivirus_fail_something.pdf
, we match the doc_uploads_antivirus_fail
scenario.
Partner-Based DDS
The partner-based product (implementation guide here) has sandbox scenarios set up to test functionality and events. Instead of entering user credentials in the Link modal as is the case for standard DDS jobs/sandbox, the credentials will be entered in the end_user.platform_matching
field during Link token creation. Here is a list of the available sandbox scenarios:
User eligible for all partner-based platforms
end_user.platform_matching Key | Value |
---|---|
first_name | user |
last_name | multi_payroll |
mobile_phone_number | <enter your phone number> |
social_security_number | <any 9-digit SSN> |
home_address_zip_code | <any 5-digit zip code> |
date_of_birth | YYYY-MM-DD |
email | [email protected] |
User ineligible for all partner-based platforms
end_user.platform_matching Key | Value |
---|---|
first_name | user |
last_name | ineligible |
mobile_phone_number | <enter your phone number> |
social_security_number | <any 9-digit SSN> |
home_address_zip_code | <any 5-digit zip code> |
date_of_birth | YYYY-MM-DD |
email | [email protected] |
Please contact [email protected] for access to our Dashboard.
Updated about 2 months ago