{"id":631,"date":"2024-07-24T08:52:32","date_gmt":"2024-07-24T15:52:32","guid":{"rendered":"https:\/\/embedded.gusto.com\/blog\/?p=631"},"modified":"2024-07-29T14:05:16","modified_gmt":"2024-07-29T21:05:16","slug":"external-payroll-flow","status":"publish","type":"post","link":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/","title":{"rendered":"Behind the Scenes: Enhancing Gusto&#8217;s External Payroll Flow"},"content":{"rendered":"<p><span style=\"font-weight: 400\">What&#8217;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 (<\/span><a href=\"https:\/\/docs.gusto.com\/embedded-payroll\/docs\/flows-intro\"><span style=\"font-weight: 400\">Flows<\/span><\/a><span style=\"font-weight: 400\">) that can be directly incorporated into your product or by calling a set of APIs.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">At Gusto Embedded, our goals are twofold:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">To be a complete and efficient payroll solution for our partners<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">To provide a seamless experience for the companies onboarding through our partners<\/span><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">Motivated by our goals, we recently upgraded our External Payrolls Flow. The upgrades include:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Redesigning the UI for a better user experience<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">New feature release for adding and managing dismissed employees<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Allowing the option to integrate External Payrolls with Company Onboarding Flows<\/span><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">This post walks through these major upgrades &#8211; what we did, why we did it, and for our savvy partner developers, how we did it!\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<h3><span style=\"font-weight: 400\">1. Redesigning the UI for a better user experience<\/span><\/h3>\n<p><span style=\"font-weight: 400\">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. <\/span><span style=\"font-weight: 400\">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:<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400\"><b>Ambiguity and unclear call-to-action: <\/b><span style=\"font-weight: 400\">The External Payroll Flow previously consisted of 2 actions: adding the employee\u2019s 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:<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><b>Review flow (before)<\/b><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-642 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-1-1.png\" alt=\"before review step 1\" width=\"1290\" height=\"1130\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-1-1.png 1290w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-1-1-342x300.png 342w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-1-1-719x630.png 719w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-1-1-150x131.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-1-1-768x673.png 768w\" data-sizes=\"(max-width: 1290px) 100vw, 1290px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1290px; --smush-placeholder-aspect-ratio: 1290\/1130;\" \/><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-643 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-2-1.png\" alt=\"before review step 2\" width=\"1186\" height=\"1454\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-2-1.png 1186w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-2-1-245x300.png 245w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-2-1-514x630.png 514w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-2-1-122x150.png 122w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-2-1-768x942.png 768w\" data-sizes=\"(max-width: 1186px) 100vw, 1186px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1186px; --smush-placeholder-aspect-ratio: 1186\/1454;\" \/><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-644 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-3-1.png\" alt=\"before review step 3\" width=\"1178\" height=\"1468\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-3-1.png 1178w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-3-1-241x300.png 241w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-3-1-506x630.png 506w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-3-1-120x150.png 120w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-3-1-768x957.png 768w\" data-sizes=\"(max-width: 1178px) 100vw, 1178px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1178px; --smush-placeholder-aspect-ratio: 1178\/1468;\" \/><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-645 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-4-1.png\" alt=\"before review step 4\" width=\"1270\" height=\"1458\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-4-1.png 1270w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-4-1-261x300.png 261w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-4-1-549x630.png 549w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-4-1-131x150.png 131w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/before-review-step-4-1-768x882.png 768w\" data-sizes=\"(max-width: 1270px) 100vw, 1270px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1270px; --smush-placeholder-aspect-ratio: 1270\/1458;\" \/><\/p>\n<p><span style=\"font-weight: 400\">So we introduced a status column that shows a status of \u201cPending Review\u201d\u00a0 next to each payroll, clearly calling out that a review is pending so companies don\u2019t 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 \u201cSave\u201d button is clicked.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><b>Review flow (after)<\/b><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-633 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-1.png\" alt=\"after review step 1\" width=\"1374\" height=\"992\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-1.png 1374w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-1-416x300.png 416w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-1-873x630.png 873w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-1-150x108.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-1-768x554.png 768w\" data-sizes=\"(max-width: 1374px) 100vw, 1374px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1374px; --smush-placeholder-aspect-ratio: 1374\/992;\" \/><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-634 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-2.png\" alt=\"after review step 2\" width=\"1386\" height=\"1052\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-2.png 1386w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-2-395x300.png 395w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-2-830x630.png 830w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-2-150x114.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-2-768x583.png 768w\" data-sizes=\"(max-width: 1386px) 100vw, 1386px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1386px; --smush-placeholder-aspect-ratio: 1386\/1052;\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-635 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3.png\" alt=\"after review step 3\" width=\"1418\" height=\"648\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3.png 1418w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3-425x194.png 425w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3-1200x548.png 1200w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3-150x69.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3-768x351.png 768w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/after-review-step-3-1400x640.png 1400w\" data-sizes=\"(max-width: 1418px) 100vw, 1418px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1418px; --smush-placeholder-aspect-ratio: 1418\/648;\" \/><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li><b>The endless story of endless scrolling: <\/b><span style=\"font-weight: 400\">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\u2019s payroll information &#8211; clearly not an ideal user experience. We\u2019ve since moved to a responsive grid model for our UI pages which neatly aligns all the inputs in a grid.<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><b>Before<\/b><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-646 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1.png\" alt=\"tax form before\" width=\"1430\" height=\"1440\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1.png 1430w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1-298x300.png 298w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1-626x630.png 626w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1-150x150.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1-768x773.png 768w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-before-1-1400x1410.png 1400w\" data-sizes=\"(max-width: 1430px) 100vw, 1430px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1430px; --smush-placeholder-aspect-ratio: 1430\/1440;\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><b>After<\/b><\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-640 size-full lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after.png\" alt=\"tax form after\" width=\"1638\" height=\"1600\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after.png 1638w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after-307x300.png 307w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after-645x630.png 645w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after-150x147.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after-768x750.png 768w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after-1536x1500.png 1536w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/tax-form-after-1400x1368.png 1400w\" data-sizes=\"(max-width: 1638px) 100vw, 1638px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1638px; --smush-placeholder-aspect-ratio: 1638\/1600;\" \/><\/p>\n<h3><span style=\"font-weight: 400\">2. Add a new feature to add and manage dismissed employees<\/span><\/h3>\n<p><span style=\"font-weight: 400\">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.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">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\u2019s basic details, such as name and date of birth, are created through <\/span><i><span style=\"font-weight: 400\">POST api\/v1\/companies\/:company_id\/employees<\/span><\/i> <span style=\"font-weight: 400\">and are stored in the Employee table. In step 2, the compensation details are added via <\/span><i><span style=\"font-weight: 400\">POST api<\/span><\/i><span style=\"font-weight: 400\">\/v1\/employees\/<\/span><span style=\"font-weight: 400\">{employee_id}<\/span><span style=\"font-weight: 400\">\/jobs <\/span><span style=\"font-weight: 400\">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\u2019t as simple as calling these endpoints directly from our code for following reasons:<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400\"><b>Existing API limitations<\/b><span style=\"font-weight: 400\">: 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 \u2018Job Title\u2019 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.`\u00a0<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<ul>\n<li><b>All steps mandatory: <\/b><span style=\"font-weight: 400\">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.\u00a0<\/span><\/li>\n<\/ul>\n<p><b><\/b><br \/>\n<b><\/b><\/p>\n<ul>\n<li><b>Data integrity &amp; performance: <\/b><span style=\"font-weight: 400\">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\u2019s 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.\u00a0 We do this by creating a Termination record against the Employment record for the employee. Let\u2019s 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\u2019t need for our case.\u00a0\u00a0<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">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.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<h3><span style=\"font-weight: 400\">3. Integrate External Payroll Flow with Company Onboarding Flow<\/span><\/h3>\n<p><span style=\"font-weight: 400\">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.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400\">Currently, all steps in <a href=\"https:\/\/docs.gusto.com\/embedded-payroll\/docs\/onboard-a-company\">Company Onboarding Flow<\/a> are mandatory. So, adding an optional step wasn\u2019t as straightforward. We brainstormed through potential solution ideas, assessed their trade-offs and finalized the solution, or as we like to say, \u201cDebated then committed\u201d to a solution. We looked into the following solutions:<\/span><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400\"><b>UI-based optionality:<\/b><span style=\"font-weight: 400\"> 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:<\/span><\/li>\n<\/ul>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">The solutions worked for partners who used our Flows (UI components) directly but excluded partners who used our APIs instead.\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">If the External Payroll step appears in the UI for partners who do not want it in their products, it degrades our partner experience.\u00a0<\/span><\/li>\n<\/ol>\n<p>&nbsp;<\/p>\n<ul>\n<li><b>API-centric approach: <\/b><span style=\"font-weight: 400\">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:<\/span><\/li>\n<\/ul>\n<p>1. Add a null flag to the endpoint to indicate whether or not to include the External Payroll step in the Company Onboarding Flow.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-650 lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.20\u202fPM.png\" alt=\"external payroll code snippet one\" width=\"1184\" height=\"266\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.20\u202fPM.png 1184w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.20\u202fPM-425x95.png 425w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.20\u202fPM-150x34.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.20\u202fPM-768x173.png 768w\" data-sizes=\"(max-width: 1184px) 100vw, 1184px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1184px; --smush-placeholder-aspect-ratio: 1184\/266;\" \/><\/p>\n<p><span style=\"font-weight: 400\">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\u2019t 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.\u00a0\u00a0\u00a0<\/span><\/p>\n<pre><\/pre>\n<p><span style=\"font-weight: 400\">2. Add an \u2018options\u2019 (aka metadata)\u00a0 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.\u00a0<\/span><\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-651 lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.26\u202fPM.png\" alt=\"external payroll code snippet two\" width=\"1194\" height=\"268\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.26\u202fPM.png 1194w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.26\u202fPM-425x95.png 425w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.26\u202fPM-150x34.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/Screenshot-2024-07-24-at-2.47.26\u202fPM-768x172.png 768w\" data-sizes=\"(max-width: 1194px) 100vw, 1194px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1194px; --smush-placeholder-aspect-ratio: 1194\/268;\" \/><\/p>\n<p><span style=\"font-weight: 400\">These enhancements to Gusto&#8217;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&#8217;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.<\/span><\/p>\n<pre><span style=\"font-weight: 400\">\u00a0<\/span><\/pre>\n<p><span style=\"font-weight: 400\">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!\u00a0<\/span><\/p>\n<pre><span style=\"font-weight: 400\">\u00a0<\/span><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>What&#8217;s the first thing you do after getting a new mobile phone? Transfer the previous data. External payroll is our&#8230;<\/p>\n","protected":false},"author":20,"featured_media":632,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-631","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developer-perspective"],"acf":{"exclude_from_embedded_resources":false,"popularity":0,"essentiality":0},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Behind the Scenes: Enhancing Gusto&#039;s External Payroll Flow - Gusto Embedded Blog<\/title>\n<meta name=\"description\" content=\"See how the Gusto Embedded engineering team worked to streamline the external payroll flow during employer onboarding.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Behind the Scenes: Enhancing Gusto&#039;s External Payroll Flow - Gusto Embedded Blog\" \/>\n<meta property=\"og:description\" content=\"See how the Gusto Embedded engineering team worked to streamline the external payroll flow during employer onboarding.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/\" \/>\n<meta property=\"og:site_name\" content=\"Gusto Embedded Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-07-24T15:52:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-07-29T21:05:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Ankita Khandelwal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Ankita Khandelwal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"TechArticle\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/\"},\"author\":{\"name\":\"Ankita Khandelwal\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/#\\\/schema\\\/person\\\/1438a4892ccf2101d2a37bb06d41e020\"},\"headline\":\"Behind the Scenes: Enhancing Gusto&#8217;s External Payroll Flow\",\"datePublished\":\"2024-07-24T15:52:32+00:00\",\"dateModified\":\"2024-07-29T21:05:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/\"},\"wordCount\":1913,\"image\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/EMB-blog-behindscenes-header-light.png\",\"articleSection\":[\"Developer Perspective\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/\",\"url\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/\",\"name\":\"Behind the Scenes: Enhancing Gusto's External Payroll Flow - Gusto Embedded Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/EMB-blog-behindscenes-header-light.png\",\"datePublished\":\"2024-07-24T15:52:32+00:00\",\"dateModified\":\"2024-07-29T21:05:16+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/#\\\/schema\\\/person\\\/1438a4892ccf2101d2a37bb06d41e020\"},\"description\":\"See how the Gusto Embedded engineering team worked to streamline the external payroll flow during employer onboarding.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#primaryimage\",\"url\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/EMB-blog-behindscenes-header-light.png\",\"contentUrl\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/07\\\/EMB-blog-behindscenes-header-light.png\",\"width\":1920,\"height\":1080,\"caption\":\"enhancing gusto external payroll flow\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/external-payroll-flow\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Behind the Scenes: Enhancing Gusto&#8217;s External Payroll Flow\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/\",\"name\":\"Gusto Embedded Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/#\\\/schema\\\/person\\\/1438a4892ccf2101d2a37bb06d41e020\",\"name\":\"Ankita Khandelwal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/06\\\/ankita-blog.jpeg\",\"url\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/06\\\/ankita-blog.jpeg\",\"contentUrl\":\"https:\\\/\\\/embeddedblog.wpengine.com\\\/wp-content\\\/uploads\\\/2024\\\/06\\\/ankita-blog.jpeg\",\"caption\":\"Ankita Khandelwal\"},\"description\":\"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.\",\"url\":\"https:\\\/\\\/embedded.gusto.com\\\/blog\\\/author\\\/ankita-khandelwal\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Behind the Scenes: Enhancing Gusto's External Payroll Flow - Gusto Embedded Blog","description":"See how the Gusto Embedded engineering team worked to streamline the external payroll flow during employer onboarding.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/","og_locale":"en_US","og_type":"article","og_title":"Behind the Scenes: Enhancing Gusto's External Payroll Flow - Gusto Embedded Blog","og_description":"See how the Gusto Embedded engineering team worked to streamline the external payroll flow during employer onboarding.","og_url":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/","og_site_name":"Gusto Embedded Blog","article_published_time":"2024-07-24T15:52:32+00:00","article_modified_time":"2024-07-29T21:05:16+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light.png","type":"image\/png"}],"author":"Ankita Khandelwal","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Ankita Khandelwal","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"TechArticle","@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#article","isPartOf":{"@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/"},"author":{"name":"Ankita Khandelwal","@id":"https:\/\/embedded.gusto.com\/blog\/#\/schema\/person\/1438a4892ccf2101d2a37bb06d41e020"},"headline":"Behind the Scenes: Enhancing Gusto&#8217;s External Payroll Flow","datePublished":"2024-07-24T15:52:32+00:00","dateModified":"2024-07-29T21:05:16+00:00","mainEntityOfPage":{"@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/"},"wordCount":1913,"image":{"@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#primaryimage"},"thumbnailUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light.png","articleSection":["Developer Perspective"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/","url":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/","name":"Behind the Scenes: Enhancing Gusto's External Payroll Flow - Gusto Embedded Blog","isPartOf":{"@id":"https:\/\/embedded.gusto.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#primaryimage"},"image":{"@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#primaryimage"},"thumbnailUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light.png","datePublished":"2024-07-24T15:52:32+00:00","dateModified":"2024-07-29T21:05:16+00:00","author":{"@id":"https:\/\/embedded.gusto.com\/blog\/#\/schema\/person\/1438a4892ccf2101d2a37bb06d41e020"},"description":"See how the Gusto Embedded engineering team worked to streamline the external payroll flow during employer onboarding.","breadcrumb":{"@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#primaryimage","url":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light.png","contentUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light.png","width":1920,"height":1080,"caption":"enhancing gusto external payroll flow"},{"@type":"BreadcrumbList","@id":"https:\/\/embedded.gusto.com\/blog\/external-payroll-flow\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/embedded.gusto.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Behind the Scenes: Enhancing Gusto&#8217;s External Payroll Flow"}]},{"@type":"WebSite","@id":"https:\/\/embedded.gusto.com\/blog\/#website","url":"https:\/\/embedded.gusto.com\/blog\/","name":"Gusto Embedded Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/embedded.gusto.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/embedded.gusto.com\/blog\/#\/schema\/person\/1438a4892ccf2101d2a37bb06d41e020","name":"Ankita Khandelwal","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/06\/ankita-blog.jpeg","url":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/06\/ankita-blog.jpeg","contentUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/06\/ankita-blog.jpeg","caption":"Ankita Khandelwal"},"description":"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.","url":"https:\/\/embedded.gusto.com\/blog\/author\/ankita-khandelwal\/"}]}},"images":{"large":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/07\/EMB-blog-behindscenes-header-light-1120x630.png"},"authorDetails":{"id":20,"name":"Ankita Khandelwal","avatar":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/06\/ankita-blog.jpeg"},"_links":{"self":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/posts\/631","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/comments?post=631"}],"version-history":[{"count":0,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/posts\/631\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/media\/632"}],"wp:attachment":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/media?parent=631"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/categories?post=631"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/tags?post=631"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}