GuidesAPI ReferenceChangelog
Log In

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:

FieldValue
Company IDcompany_good
Usernameuser_good*
Email[email protected]
Passwordpass_good
SSN123456789
Last 4 of SSN1234
MFA codemfa_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:

FieldValue
Usernameuser_mfa
Email[email protected]

To test Direct Deposit Forms use the following credentials:

FieldValue
Usernameuser_dd_form

To test jobs with an outcome of error, use the following credentials. Additional error cases are covered in the section below.

FieldValue
Usernameuser_error
Email[email protected]

To test jobs with an outcome of pending, use the following credentials:

FieldValue
Usernameuser_pending
Email[email protected]

To test a direct deposit with an error outcome followed by a successful card switch, use the following credentials:

FieldValue
Usernameuser_dd_error
Email[email protected]

To test a successful direct deposit followed by a card switch with an error outcome, use the following credentials:

FieldValue
Usernameuser_card_error
Email[email protected]

📘

Note

In sandbox mode, jobs with a pending outcome will transition to an error 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 a pending outcome, followed by an event with an error outcome.

In Production, jobs may remain in pendingfor 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 simulateSandbox username
MFA requireduser_mfa
Credentials requireduser_good
Credentials and MFA requireduser_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:

UsernameBehavior
earnings_stream_payouts_availableThis 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_salariedThis 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_snpThis 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:

Usernamepayload.unavailable_reason
payouts_unavailable_temporary_outagetemporary_outage
payouts_unavailable_employer_not_supportedemployer_not_supported
payouts_unavailable_waiting_for_workuser_action_waiting_for_work
payouts_unavailable_new_employeeuser_action_new_employee
payouts_unavailable_undetermineduser_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:

  1. The first step is to register a webhook with the verification_reports.refreshed webhook event. For an introduction to webhooks, please read this.
  2. 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.
  3. Select at leastidentity and employment in required_jobs (income is required to generate a VOIE report, and paystubs is required to see meaningful numbers in some parts of the report), and provide an end_user_id.
  4. 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:

UsernameBehavior
voe_and_voie_availableBoth 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_paystubsThis 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_unavailableThis 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_unavailableThis 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.

UsernameBehavior
voe_and_voie_available_active_longThis 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_paystubsThis 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_shortThis 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_longThis 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_shortThis 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:

  1. Create a link token with an end_user_id, and with at least identity and employment in required jobs (income is required to generate a VOIE report, and paystubs is required to see meaningful numbers in some parts of the report).
  2. Launch Link modal, and select any payroll plaform.
  3. Log in using any of the above usernames (for example voe_and_voie_available_inactive_short) with pass_good as the password (and any other applicable IDs such as company_id which should be displayed)
  4. Exit Link modal after seeing the success screen
  5. Create a second link token with the same end user ID as step 1 (and the same required jobs)
  6. Launch Link modal, and select any payroll plaform.
  7. Log in using a different one of the above usernames (for example voe_and_voie_available_active_long) with pass_good as the password (and any other applicable IDs such as company_id which should be displayed)
  8. Exit Link modal after seeing the success screen
  9. (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

This error indicates that the user must update their password before logging in.

FieldValue
Usernameuser_change_password_required
Passwordpass_good

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).

FieldValue
Usernameuser_account_not_active
Passwordpass_good

accountLoggedIn

This error is thrown when the platform detects that the user is logged in via another mechanism.

FieldValue
Usernameuser_account_logged_in
Passwordpass_good

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.

FieldValue
Usernameuser_mfa_setup_required
Passwordpass_good

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).

FieldValue
Usernameuser_location_restricted
Passwordpass_good

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.

FieldValue
Usernameuser_email_not_registered
Passwordpass_good

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).

FieldValue
Usernameuser_max_failed_attempts
Passwordpass_good
MFA codemfa_code or any valid string

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.

FieldValue
Usernameuser_mfa_time_exceeded
Passwordpass_good
MFA codemfa_code for both attempts

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.

FieldValue
Usernameuser_challenge_answer_incorrect
Passwordpass_good
Security question answersecurity_answer_good or pinwheel drive

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.

FieldValue
Usernameuser_passwords_not_equal
Passwordpass_good
Confirm passwordany 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*

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.

FieldValue
Usernameuser_system_error
Passwordpass_good

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.

FieldValue
Usernameuser_account_locked
Passwordpass_good

contactHelpDesk*

This error is thrown when the user needs to contact their payroll admin in order to continue.

FieldValue
Usernameuser_contact_help_desk
Passwordpass_good

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).

FieldValue
Usernameuser_direct_deposit_disabled
Passwordpass_good

sessionTimeout*

This error occurs when the session closes after a period of inactivity (e.g. due to lack of user action).

FieldValue
Usernameuser_session_timeout
Passwordpass_good

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.

FieldValue
Usernameuser_platform_error
Passwordpass_good

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.

FieldValue
Usernameuser_platform_unavailable
Passwordpass_good

routingNumberRejected

This error is thrown when the routing number provided in the Link token is rejected by the platform's validation logic.

FieldValue
Usernameuser_routing_number_rejected
Passwordpass_good

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.

FieldValue
Usernameuser_invalid_existing_split
Passwordpass_good

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).

FieldValue
Usernameuser_changes_temporarily_disabled
Passwordpass_good

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.

FieldValue
Usernameuser_max_accounts
Passwordpass_good

validationFailed

This is a catch-all error that is thrown to capture account data validation issues.

FieldValue
Usernameuser_validation_failed
Passwordpass_good

invalidInput*

This is a catch-all error that is thrown to capture generic input errors.

FieldValue
Usernameuser_invalid_input
Passwordpass_good

Income and Employment job errors

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.

FieldValue
Usernameuser_data_not_available
Passwordpass_good

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.

FieldValue
Usernameuser_data_not_refreshable
Passwordpass_good

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.

FieldValue
Usernameuser_direct_deposit_allocations_disabled
Passwordpass_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 SubstringScenario Description
doc_uploads_antivirus_failThe uploaded file fails an antivirus check. As a result, the document is not persisted, and a document.addedwebhook is sent with outcome error.
doc_uploads_unsupported_doc_typeThe uploaded file is an unsupported document. As a result, the document is not persisted, and a document.addedwebhook is sent with outcome error.
doc_uploads_fraudulent_suspectedThe 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_dataThe 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 filenameThe 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 KeyValue
first_nameuser
last_namemulti_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_birthYYYY-MM-DD
email[email protected]

User ineligible for all partner-based platforms

end_user.platform_matching KeyValue
first_nameuser
last_nameineligible
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_birthYYYY-MM-DD
email[email protected]

Please contact [email protected] for access to our Dashboard.