Behind the Scenes: Enhancing Gusto’s External Payroll Flow

Developer Perspective
enhancing gusto external payroll flow
Bookmark

What’s the first thing you do after getting a new mobile phone? Transfer the previous data. External payroll is our version of this data transfer app, but for payrolls. External Payrolls is a way for companies onboarding on Gusto to bring all the previous payroll data relevant for the current calendar year onto the platform. This helps Gusto ensure accurate tax filings for the year. As a Gusto Embedded partner, you can provide this feature to your clients directly through the pre-built UI components (Flows) that can be directly incorporated into your product or by calling a set of APIs. 

 

At Gusto Embedded, our goals are twofold:

  1. To be a complete and efficient payroll solution for our partners
  2. To provide a seamless experience for the companies onboarding through our partners

 

Motivated by our goals, we recently upgraded our External Payrolls Flow. The upgrades include:

  1. Redesigning the UI for a better user experience
  2. New feature release for adding and managing dismissed employees
  3. Allowing the option to integrate External Payrolls with Company Onboarding Flows

 

This post walks through these major upgrades – what we did, why we did it, and for our savvy partner developers, how we did it! 

 

1. Redesigning the UI for a better user experience

We made this upgrade as a result of insights from dogfooding and partner feedback, and an effort towards creating a better user experience for the companies. At Gusto Embedded, Flows is a big part of our onboarding training for new engineers as it serves as a guide to understanding the domain and how our APIs are potentially consumed. We also have a dedicated product and technical solutions team that works closely with our partners to understand their requirements and collect feedback about their experiences with our product. Both these processes helped identify the UI issues and the friction they cause in product usage. Some of these issues include:

 

  • Ambiguity and unclear call-to-action: The External Payroll Flow previously consisted of 2 actions: adding the employee’s previous payroll records and reviewing the tax liabilities calculated based on these payrolls. Reviewing tax liabilities also had two pages at the end: one for confirming and one for submitting the tax liabilities. We saw a pattern where either the review was not done at all, or the payroll admins simply confirmed the tax liabilities without actually submitting them. This was the process:

 

Review flow (before)

before review step 1

before review step 2

before review step 3

before review step 4

So we introduced a status column that shows a status of “Pending Review”  next to each payroll, clearly calling out that a review is pending so companies don’t skip this step. We also combined the confirmation and submission page into one to reduce the ambiguity and ensure that the tax liabilities are submitted every time the “Save” button is clicked.

 

Review flow (after)

after review step 1

after review step 2

 

after review step 3

 

  • The endless story of endless scrolling: Our initial UI design leaned heavily towards a single stack design where all the input boxes were stacked one per row in a single column using the entire page width. This created long forms that required a lot of scrolling especially for forms that required many inputs such as entering an employee’s payroll information – clearly not an ideal user experience. We’ve since moved to a responsive grid model for our UI pages which neatly aligns all the inputs in a grid.

 

Before

tax form before

 

After

tax form after

2. Add a new feature to add and manage dismissed employees

Dismissed employees are employees who have been terminated before a company onboards on the new platform but whose payroll information is relevant for tax calculation purposes. The ability to add and manage dismissed employees on the Gusto Embedded platform was another milestone towards becoming a complete payroll solution for our partners. Before this feature, all employees (including dismissed employees) would have to be onboarded through our standard employee onboarding process. This multi-step process requires detailed information about the employee, such as their payment methods, tax selections, job title, etc. Dismissed employee onboarding does not require this level of detail, nor is it readily available to the payroll admins. Asking dismissed employees to self-board and provide this information is also not feasible. This created significant friction for onboarding dismissed employees. The new feature mitigates this friction by allowing the payroll admins to enter only the minimal relevant information while onboarding dismissed employees. 

 

Under the hood, each step of this multi-step employee onboarding process is managed by a separate set of endpoints. Their data is stored in separate database tables as well. For example, in step 1, an employee’s basic details, such as name and date of birth, are created through POST api/v1/companies/:company_id/employees and are stored in the Employee table. In step 2, the compensation details are added via POST api/v1/employees/{employee_id}/jobs and are stored in the Job table. By allowing a single-step minimal data entry for dismissed employees, we were combining all the steps into one. However, this wasn’t as simple as calling these endpoints directly from our code for following reasons:

 

  • Existing API limitations: The existing APIs required additional data to update the corresponding database records, which we did not have. For example, when adding a job, the endpoint requires ‘Job Title’ as a mandatory field, without which a record of employment cannot be created for the employee. However, the only thing we needed for dismissed employees was a `Start Date.` 

 

  • All steps mandatory: Each step in the employee onboarding process is associated with an Employee Onboarding status record that is updated after completion of the step. An employee is not considered fully onboarded and shows up on the list of company employees until all these steps are completed. However, we wanted to bypass some steps, such as collecting W2s, federal and state tax selections. This would have left the dismissed employee record with an incomplete onboarding status. 


  • Data integrity & performance: Since we were asking for all the relevant information in one step (one form), we now needed to update all the database records for that employee together, such as the employee’s basic details record in the Employee table, home address record in the Home Address table, job details in the Job table. And to maintain our data integrity, these updates needed to happen atomically. Partial updates would have rendered our data inaccurate. For example, one of the steps we needed to include for dismissed employees was to mark them as terminated in our system.  We do this by creating a Termination record against the Employment record for the employee. Let’s say there was a failure while creating a Termination record. The employee will still show as active for the company, which is inaccurate. And if we tried to avoid partial updates by serially calling the endpoints, our system would have poorer performance since a lot more logic is included in each endpoint that we didn’t need for our case.  

 

For the above reasons, we created an entirely separate set of endpoints to support dismissed employees that only required minimal data and directly set onboarding status as Complete. Within the endpoint, we were still updating the employee records against different database tables, such as Employee, Job, Termination, etc. To avoid partial updates in this case, we followed the best practices for Rails applications and put all these update statements under an ActiveRecord Transaction block. This block helps maintain atomicity among all the ActiveRecord updates within it. Any exception during these updates triggers a rollback of all the previous updates. 

 

3. Integrate External Payroll Flow with Company Onboarding Flow

At Gusto Embedded, we greatly value our partner developers and strive towards creating efficient solutions that reduce their effort. One such requirement we came across from partners was to integrate External Payroll Flow as one of the steps in Company Onboarding Flow itself. Instead of integrating with two separate Flows, our partner developers could integrate and manage only one overall Company Onboarding Flow. However, we wanted to ensure that this change does not impact our existing partners who may not need External Payroll Flow for their products. So, we decided to make this feature optional. Our partners could choose whether they wanted External Payroll Flow included in Company Onboarding Flow or not. 

 

Currently, all steps in Company Onboarding Flow are mandatory. So, adding an optional step wasn’t as straightforward. We brainstormed through potential solution ideas, assessed their trade-offs and finalized the solution, or as we like to say, “Debated then committed” to a solution. We looked into the following solutions:

 

  • UI-based optionality: We considered hiding the External Payroll step on UI only based on a flag. We could add this step to our APIs just like other steps but only show it in the UI when the flag was set. Another solution was to always show this step in the UI but make it skippable. We quickly rejected both these ideas for two reasons:
  1. The solutions worked for partners who used our Flows (UI components) directly but excluded partners who used our APIs instead. 
  2. If the External Payroll step appears in the UI for partners who do not want it in their products, it degrades our partner experience. 

 

  • API-centric approach: To ensure we have a similar experience for both our Flows and API-based partners, we decided to make changes in the API endpoint itself. Our Flows UI component also uses our API endpoint. An early consideration we made here was that it should not be an API-breaking change, so there is no impact on our existing partners. Some of the API design changes we thought through were:

1. Add a null flag to the endpoint to indicate whether or not to include the External Payroll step in the Company Onboarding Flow.

external payroll code snippet one

When the flag is true, the step is included. When it is false, it is excluded. To avoid making this an API-breaking change for our partners, we allow nil values so partner developers don’t necessarily have to provide a value for this field. It is considered false by default. However, this solution failed our extensibility test. In the future, we might have more similar customizations. Having a field for each of them in our endpoint will impact its manageability. So we rejected this idea.   


2. Add an ‘options’ (aka metadata)  field to the endpoint to encapsulate all the custom flags. This field would be a hashmap with key-value pairs. This will allow us to create both flag-based and value-based customizations. We ultimately settled on this solution. Additionally, this would allow us to validate the combination of keys used and the Flow type requested to reduce the potential for errors and bugs. 

external payroll code snippet two

These enhancements to Gusto’s External Payroll Flow are a significant step toward providing a seamless experience and becoming an efficient solution for our partners while meeting their evolving needs. By redesigning the UI, we’ve addressed critical user feedback and internal insights to create a more intuitive and navigable interface. Our new feature for adding and managing dismissed employees simplifies the process for payroll admins, ensuring accurate tax calculations without unnecessary friction. Integrating External Payrolls into the Company Onboarding Flows further streamlines the setup process, reducing integration effort and enhancing overall user satisfaction.

 

As we continue to evolve ourselves through partner feedback and innovative solutions, we encourage our partners to explore these new features and provide their valuable feedback! 

 

Updated: July 29, 2024

Ankita Khandelwal Ankita Khandelwal joined Gusto's Embedded Engineering team in 2024. Previously, she led projects at Airbnb, architecting systems and designing scalable and robust APIs for both product and platform services. At Gusto, Ankita is focused on building APIs and solutions that empower our partners and enhance user experiences.
Back to top