GuidesAPI ReferenceChangelog
Log In


Pinwheel Link is a front-end modal that allows users to search for their employers and payroll providers and seamlessly authenticate with their payroll platform credentials in order to authorize access to their payroll account.

There are several methods for implementing Pinwheel Link. For web application you can embed Pinwheel Link directly into your site. For mobile development we recommend using one of our Link SDKs: React Native, Android, and iOS.


We understand how important it is to have a cohesive user experience, so we’ve made Pinwheel Link highly customizable. All customizations are done via Link token creation. Some of the most notable customizations include:

  • Skipping the Pinwheel intro screen
  • Building your own search functionality
  • Disabling partial direct deposit switch
  • Language localization

For more information on navigating these customizations please take a look at our Implementation Guide.

Link Tokens

In order to initialize Pinwheel Link, your server side code will need to generate a short-lived Link token by sending a POST request to the /link_tokens endpoint. Link tokens are intended to be single-use and expire after one hour. Your server should generate a new Link token each time you wish to launch Pinwheel Link.


Keep your secrets a secret

Make sure to keep your API secrets secure! You should avoid storing or using API secrets in client-side code, GitHub, or other non-secure spots.


POST /v1/link_tokens
Content-Type: application/json
x-api-secret: YOUR-API-SECRET
  "org_name": "YOUR APP NAME",
  "required_jobs": ["employment", "income"],


  "data": {
    "mode": "production",
    "id": "97f420ff-5d0a-46ee-9cfc-6f17d5d31256",
    "token": "eyJ0eXAiOiJKV1QiLCJhbGci...cyldX8fILelb6A0XKmdWsXZHMH4W1o",
    "expires": "2021-01-09T02:52:26+00:00"



The id returned here is identical to the link_token_id included with webhooks, and should be stored accordingly. The end_user_id you provide in this request is also included in any subsequent webhooks events. You can find recommendations for storing identifiers here.

Link Events

Link events are returned to your client and will give you visibility into what is happening in the modal as the user moves through Pinwheel Link. The nine different event types are outlined below. It is up to you to determine how to use these events for tracking.

openModal was opened.{}
select_employerUser selected an employer.{ selectedEmployerId: string, selectedEmployerName: string }
select_platformUser selected a platform.{ selectedPlatformId: string, selectedPlatformName: string }
incorrect_platform_givenClient has incorrect platform in token.{}
login_attemptUser has submitted login attempt for the first time.{ platformId: string }
loginUser logged in successfully.{ accountId: string, platformId: string }
input_amount (deprecated)User inputted an amount. Note that this event is deprecated in favor of input_allocation, which provides more detail on what was input by the user.{ value: number, unit: '$' | '%' }
input_allocationUser has submitted an allocation.{ action: string, allocation?: { type: string, value?: number, target?: { accountName: string, accountType: string } }
card_switch_beginUser has elected to do a card switch.{}
doc_uploads_beginUser has started the doc uploads flow.{}
doc_uploads_submittedUser has submitted documents for upload.{uploadedDocumentSubmittedCount: number}
dd_form_beginUser has begun the process to create a direct deposit form.{}
dd_form_createUser has successfully created a direct deposit form, which is available at the returned URL.{ url: string }
dd_form_downloadUser has downloaded or shared the direct deposit form PDF.{}
screen_transitionUser has transitioned to a new screen within the modal.{ screen_name: string, selectedEmployerId?: string, selectedEmployerName?: string, selectedPlatformId?: string, selectedPlatformName?: string }
exitModal was exited.PinwheelError | {}
successUser reached the success screen. For direct deposit and card switch jobs, this will occur once for each job that completes successfully. For all other jobs this will be when the user logs in successfully, as these jobs are completed in the background.LinkResult
errorUser was shown an error.PinwheelError

For On Demand Updates, the select_employer, select_platform, and incorrect_platform_given events are not sent since the account_id is already associated with a platform. Additionally, the login_attempt event is only sent if user input is required and an attempt to login is made.

You can find more detail on Link errors and error handling here.

Reference Types

The following types should be used while integrating Link into your application.


{ type: string; code: string; message: string, pendingRetry: boolean }

The boolean pendingRetry is true when the job results in an error but will be retried asynchronously. Your user will be notified that their request is pending. This is available starting Link v2.3 and above.


type InitializationParams = {
  linkToken: string;
  onLogin?: (result: { accountId: string, platformId: string }) => void;
  onSuccess?: (result: LinkResult) => void;
  onError?: (error: PinwheelError) => void;
  onExit?: (error?: PinwheelError) => void;
  onEvent?: (name: string, payload: EventPayload) => void;
linkTokenThe Link token created using the /link_tokens endpoint.
onLogin (optional)Callback whenever a user successfully logs in to their payroll account.
onSuccess (optional)Callback whenever a user reaches the success screen. For direct deposit jobs, this will occur when the job has completed successfully. For Income and Employment jobs this will be when the user logs in successfully, as these jobs are completed in the background.
onError (optional)Callback anytime an error occurs during the flow. This could be a user error like incorrect credentials or a system error. Receiving this callback does not necessarily mean the flow cannot proceed.
onExit (optional)Callback whenever a user exits the modal either explicitly or if an error occurred that crashed the modal.
onEvent (optional)Callback with more granular events to help you track usage. All possible events are listed here.


Note that the params object is deprecated. Please use the input_allocation event to determine the amount and type of allocation that the user submitted.

  accountId: string;
  platformId: string;
  job: string;
  params: {
    amount?: {value: number, unit: '%' | '$'}


SEARCH_DEFAULT{ screen_name: SEARCH_DEFAULT }Default search screen after the initial intro page.
SEARCH_RESULTS{ screen_name: SEARCH_RESULTS }Results screen when the user starts a search from the SEARCH_DEFAULT screen.
SEARCH_PLATFORM_ONLY{ screen_name: SEARCH_PLATFORM_ONLY }From the SEARCH_RESULTS screen, the user is able to search through a list filtered for platforms only.
PROVIDER_CONFIRMATION{ screen_name: PROVIDER_CONFIRMATION }Provider confirmation screen. When some employers or platforms (e.g. Workday) are initially selected, the user is prompted to then confirm their specific employer/platform before logging in.
LOGIN{ screen_name: LOGIN, selectedEmployerId?: string, selectedEmployerName?: string, selectedPlatformId?: string, selectedPlatformName?: string }Login screen once the user has selected a platform or employer from search.
DD_AMOUNT_SELECTION{ screen_name: DD_AMOUNT_SELECTION }Direct deposit amount selection screen after the user has successfully logged in.
DD_CONFIRMATION{ screen_name: DD_CONFIRMATION }Confirmation screen before a direct deposit switch is performed.
JOB_SUCCESS{ screen_name: JOB_SUCCESS }Job success screen (e.g. direct deposit switch succeeded).
JOB_ERROR{ screen_name: JOB_ERROR }Job error screen (e.g. direct deposit switch failed).
EXIT_CONFIRMATION{ screen_name: EXIT_CONFIRMATION }Exit confirmation screen when the user presses the modal close button.

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