GuidesAPI ReferenceChangelogAPI PolicyAPI StatusGusto Security

Onboard a Company

Before using this guide you must have a developer account and created an application. To learn more about these steps, review the Getting Started guide.

1. Create a Partner Managed Company

You can create a company using the POST partner_managed_companies endpoint.

curl --request POST \
     --url https://api.gusto-demo.com/v1/partner_managed_companies \
     --header 'accept: application/json' \
     --header 'content-type: application/json'\
     --header 'Authorization: Token <<API_TOKEN>>'\
      --data '{
       "user": {
            "last_name": "Mushnik",
            "first_name": "Mister",
            "email": "[email protected]"
       },
       "company": {
            "name": "Mushnik`s Flower Shop"
            "ein": 910532465
       }
			}'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/partner_managed_companies';
const options = {
  method: 'POST',
  headers: {
    accept: 'application/json', 
    'content-type': 'application/json',
    authorization: 'Bearer <<API_TOKEN>>'
  }
  },
  body: JSON.stringify({
    user: {
      first_name: 'Mister',
      last_name: 'Mushnik',
      email: '[email protected]'
    },
    company: {
      name: "Mushnik\'s Flower Shop",
      ein: "910532465"
  }
                       
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

πŸ“˜

Payroll Administrators

The user created in this step is the primary payroll administrator of the new company. If you want to add more administrators you can use the POST companies/{company_id}/admins endpoint.

2. View and Accept Terms of Service

Each company added must accept the Gusto Terms of Service.

curl --request POST \
     --url https://api.gusto-demo.com/v1/partner_managed_companies/{company_uuid}/accept_terms_of_service \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "email": "[email protected]",
     "external_user_id": "2005648946132",
     "ip_address": "192.168.1.2"
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/partner_managed_companies/{company_uuid}/accept_terms_of_service';
const options = {
  method: 'POST',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<API_TOKEN>>'
  },
  body: JSON.stringify({
    email: '[email protected]',
    external_user_id: '2005648946132',
    ip_address: '192.168.1.2'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

3. Create a Company Location

Gusto requires the company’s mailing and filing address and all addresses where the company has employees physically working in the United States. This includes remote employees and employees who work from home. Set these addresses using the POST company/{company_uuid}/locations endpoint.

curl --request POST \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/locations \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "phone_number": "8009360383",
     "street_1": "425 2nd Street",
     "street_2": "Suite 602",
     "city": "San Francisco",
     "state": "CA",
     "zip": "94107",
     "country": "USA"
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/locations';
const options = {
  method: 'POST',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({
    phone_number: '8009360383',
    street_1: '425 2nd Street',
    street_2: 'Suite 602',
    city: 'San Francisco',
    state: 'CA',
    zip: '94107',
    country: 'USA'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

4. Update Federal Tax Details

In order to file and pay taxes correctly, a company needs to provide federal tax information. You can find this info on the company's IRS Form CP-575. To update the Federal Tax Details, you will first need to get the version of the tax details using GET companies/{company_uuid}/federal_tax_details . Once you have the version you can update the federal tax details using PUT companies/{company_uuid}/federal_tax_details .

curl --request PUT \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/federal_tax_details \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "version": "6cb95e00540706ca48d4577b3c839fbe",
     "tax_payer_type": "LLP",
     "taxable_as_scorp": false,
     "filing_form": "944",
     "has_ein": true,
     "ein_verified": false,
     "legal_name": "Mushnik\'s Flower Shop Inc"
}'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/federal_tax_details';
const options = {
  method: 'PUT',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({
    version: '6cb95e00540706ca48d4577b3c839fbe',
    tax_payer_type: 'LLP',
    taxable_as_scorp: false,
    filing_form: '944',
    has_ein: true,
    ein_verified: false,
    legal_name: 'Mushnik\'s Flower Shop Inc'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

5. Update Company Industry

Update the company's industry selection using naics_codeandsic_codes with the PUT companies/{company_uuid}/industry_selection endpoint .

πŸ“˜

NAICS and SIC Codes

Gusto requires this information to stay in compliance with finance regulations. North American Industry Classification System (NAICS) is used to classify businesses with a six digit number based on the primary type of work the business performs. SIC codes are the list of Standard Industrial Classification, which are four digit numbers that categorize the industries that companies belong to based on their business activities. You can look up a company’s NAICS and SIC codes here.

curl --request PUT \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/industry_selection \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "title": "Computer Training",
     "naics_code": "611420",
     "sic_codes": [
          "8243"
     ]
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/industry_selection';
const options = {
  method: 'PUT',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({title: 'Computer Training', naics_code: '611420', sic_codes: ['8243']})
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

6. Add Company Bank Account and Verify Account

You can create and connect a new bank account for a company using the POST companies/{company_id}/bank_accounts endpoint. If a default bank account exists, the new bank account will replace it as the company's default funding method.

You can also connect a bank account from Plaid using the POST plaid/processor_token endpoint.

curl --request POST \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/bank_accounts \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "routing_number": "115092013",
     "account_type": "Checking",
     "account_number": "9775014007"
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/bank_accounts';
const options = {
  method: 'POST',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({
    routing_number: '115092013',
    account_type: 'Checking',
    account_number: '9775014007'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

πŸ“˜

Routing Numbers in Demo Environment

Our API validates the routing number to ensure it's a valid US routing number and will reject false inputs. When testing in Gusto's demo environment, you can use this sample routing number: 102001017.

Upon being created, two verification deposits are automatically sent to the bank account in 1-2 business days, and the bank account's verification_status is awaiting_deposits.

When the deposits are successfully transferred, the verification_status changes to ready_for_verification, at which point the PUT companies/{company_id}/bank_accounts/{bank_account_uuid}/verify endpoint can be used to verify the bank account. After successful verification, the bank account's verification_status is verified.

curl --request PUT \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/bank_accounts/{bank_account_uuid}/verify \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "deposit_1": 0.02,
     "deposit_2": 0.42
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/bank_accounts/{bank_account_uuid}/verify';
const options = {
  method: 'PUT',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({deposit_1: 0.02, deposit_2: 0.42})
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

πŸ“˜

Validation in Demo Environment

We provide the POST companies/{company_id_or_uuid}/bank_accounts/{bank_account_uuid}/send_test_deposits endpoint to facilitate bank account verification in the demo environment. This endpoint simulates the micro-deposits transfer and returns them in the response. You can call this endpoint as many times as you wish to retrieve the values of the two micro deposits

7. Create an Employee

Employees are a critical part of payroll. Companies themselves are, naturally, a collection of one to hundreds of employees that must be paid on a regular cadence for work done. There are two different ways to create and onboard an employee: By Employer or By Employees ("self-onboarding").

For a more comprehensive Employee Onboarding, you can read the Onboard a W2 Employee guide.

You can create an employee using the POST employees endpoint.

The example below shows an employee "self-onboarding".

curl --request POST \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/employees \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "first_name": "Alexander",
     "middle_initial": "A",
     "last_name": "Hamilton",
     "date_of_birth": "1979-06-01",
     "email": "[email protected]",
     "ssn": "123451776",
     "self_onboarding": true
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/employees';
const options = {
  method: 'POST',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({
    first_name: 'Alexander',
    middle_initial: 'A',
    last_name: 'Hamilton',
    date_of_birth: '1979-06-01',
    email: '[email protected]',
    ssn: '123451776',
    self_onboarding: true
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

8. Create a Pay Schedule

To create a pay schedule for a company use the POST companies/{company_id}/pay_schedules endpoint. This create a new single default pay schedule for the company. To learn more about Pay Schedules review the Create a Pay Schedule guide.

πŸ“˜

Anchor Pay Date

  1. Payroll of any kind (regular, off-cycle, etc.) cannot be run in a quarter prior to the quarter that the anchor pay date falls in.
  2. If payroll (regular or off-cycle) is not run by the set anchor pay date, the field will be invalidated and the pay schedule will need to be set again.
  3. If the anchor pay date is changed prior to running the first payroll, the 8655 will need to be resigned by the company signatory.
    1. Context: the anchor pay date is reported on the Federal 8655 form (authorization for Gusto to pay & file taxes on behalf of the company). Because of this, our authorization starts in the month associated with the anchor pay date. If any information pertaining to this date changes, that form will be regenerated and need signature again.

9. Update Company State Tax Details

Although APIs exist for the majority of Company and Employee Onboarding steps, We recommend using the flow to handle the 2400+ different state tax account numbers

To learn more about this flow read the Flows (Pre-built UI) guide.

10. Add Previous Payrolls (Optional)

Historical payrolls are used for companies who transfer from one payroll provider to your payroll product after the start of a year. It's important to capture their previous payrolls during Company Onboarding to ensure year to date filings are accurate.

Employees are expecting a single W-2 with all their tax information at the end of the calendar year even if their Employer has switched to a different payroll provider at any time during that year.

You can use our Create a Historical Payroll Guide to add previous payroll.

11. Add a Signatory

The signatory should be an officer, owner, general partner or LLC member manager, plan administrator, fiduciary, or an authorized representative who is designated to sign agreements on the company's behalf. An officer is the president, vice president, treasurer, chief accounting officer, etc.

There can only be a single primary signatory in a company so you must delete a signatory before creating a new one. You can retrieve the current primary signatory from GET companies/{company_uuid}/signatories endpoint.

You can either create a new signatory or invite a signatory to create a signatory with minimal information and subsequently populate the remaining information using the update a signatory endpoint. The example below will show creating a new signatory using POST companies/{company_uuid}/signatories.

curl --request POST \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/signatories \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "home_address": {
          "street_1": "35 Fantine Street",
          "street_2": "Suite 17",
          "city": "Paris",
          "state": "TX",
          "zip": "75460"
     },
     "ssn": "254324601",
     "first_name": "Jean",
     "last_name": "Valjean",
     "email": "[email protected]\"",
     "title": "Business Man",
     "phone": "8002331000",
     "birthday": "1983-12-01"
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/signatories';
const options = {
  method: 'POST',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({
    home_address: {
      street_1: '35 Fantine Street',
      street_2: 'Suite 17',
      city: 'Paris',
      state: 'TX',
      zip: '75460'
    },
    ssn: '254324601',
    first_name: 'Jean',
    last_name: 'Valjean',
    email: '[email protected]"',
    title: 'Business Man',
    phone: '8002331000',
    birthday: '1983-12-01'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

12. Sign Onboarding Documents

πŸ›‘

You will not be able to sign onboarding documents until all of the above required steps have been completed

To see what forms need to be signed, you can use the GET companies/{company_id}/forms endpoint.

This will return an array of objects with documents:

[
  {
    "uuid": "48cdd5ec-a4dd-4840-a424-ad79f38d8408",
    "name": "company_direct_deposit",
    "title": "Direct Deposit Authorization",
    "description": "We need you to sign paperwork to authorize us to debit and credit your bank account and file and pay your taxes.",
    "requires_signing": true
  }
]

To preview the PDF of each document you can use the GET forms/{form_uuid}/pdf endpoint.

After identifying which forms require signing ("requires_signing": true) you can use the uuid of the form and make a subsequent request to sign a company form using the PUT /forms/{form_id}/sign endpoint.

curl --request PUT \
     --url https://api.gusto-demo.com/v1/forms/48cdd5ec-a4dd-4840-a424-ad79f38d8408/sign \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
     --header 'content-type: application/json' \
     --data '
{
     "signature_text": "Jean Valjean",
     "agree": true,
     "signed_by_ip_address": "192.168.0.1"
}
'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/forms/48cdd5ec-a4dd-4840-a424-ad79f38d8408/sign';
const options = {
  method: 'PUT',
  headers: {
    accept: 'application/json',
    'content-type': 'application/json',
    authorization: 'Bearer <<COMPANY_API_TOKEN>>'
  },
  body: JSON.stringify({
    signature_text: 'Jean Valjean',
    agree: true,
    signed_by_ip_address: '192.168.0.1'
  })
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

πŸ“˜

Form 8655 regenerates in these scenarios and will require re-signature:

  • The 8655 form has already been signed, and the signatory data has changed
  • The pay schedule’s new pay date’s month is earlier than the old pay date’s month (ex: if the previous pay date is in March and the new pay date is in February
  • Company data change occurs for any of the following: Company EIN, Company filing address, Company name

If a form requires action you can subscribe to webhooks and listen for form.updated. Check the value of form.signed_at - if going from present to blank/nil, then the form has gone from signed β†’ unsigned.

13. Confirm all steps are complete and submit

To confirm all steps have been completed, you can check the company’s onboarding status using the GET companies/{company_uuid}/onboarding_status endpoint. In the example below, payroll_schedule,sign_all_forms,and verify_bank_info have not been completed as shown by "completed": false.

{
    "uuid": "94a4d25c-c3a6-4bea-92a8-356ac915c8aa",
    "onboarding_completed": false,
    "onboarding_steps": [
        {
            "title": "Add Your Company’s Addresses",
            "id": "add_addresses",
            "required": true,
            "completed": true,
            "requirements": []
        },
        {
            "title": "Enter Your Federal Tax Information",
            "id": "federal_tax_setup",
            "required": true,
            "completed": true,
            "requirements": []
        },
        {
            "title": "Select Industry",
            "id": "select_industry",
            "required": true,
            "completed": true,
            "requirements": []
        },
        {
            "title": "Add Your Bank Account",
            "id": "add_bank_info",
            "required": true,
            "completed": true,
            "requirements": []
        },
        {
            "title": "Add Your Employees",
            "id": "add_employees",
            "required": true,
            "completed": true,
            "requirements": [
                "add_addresses"
            ]
        },
        {
            "title": "Enter Your State Tax Information",
            "id": "state_setup",
            "required": true,
            "completed": true,
            "requirements": [
                "add_addresses",
                "add_employees"
            ]
        },
        {
            "title": "Select a Pay Schedule",
            "id": "payroll_schedule",
            "required": true,
            "completed": false,
            "requirements": []
        },
        {
            "title": "Sign Documents",
            "id": "sign_all_forms",
            "required": true,
            "completed": false,
            "requirements": [
                "add_employees",
                "federal_tax_setup",
                "state_setup",
                "add_bank_info",
                "payroll_schedule"
            ]
        },
        {
            "title": "Verify Your Bank Account",
            "id": "verify_bank_info",
            "required": true,
            "completed": false,
            "requirements": [
                "add_bank_info"
            ]
        }
    ]
}

Once all of the above steps are marked with "completed": true, you can use PUT companies/{company_uuid}/finish_onboarding to complete the onboarding.

curl --request PUT \
     --url https://api.gusto-demo.com/v1/companies/{company_uuid}/finish_onboarding \
     --header 'accept: application/json' \
     --header 'authorization: Bearer <<COMPANY_API_TOKEN>>'
const fetch = require('node-fetch');

const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/finish_onboarding';
const options = {
  method: 'PUT',
  headers: {accept: 'application/json', authorization: 'Bearer <<COMPANY_API_TOKEN>>'}
};

fetch(url, options)
  .then(res => res.json())
  .then(json => console.log(json))
  .catch(err => console.error('error:' + err));

πŸ“˜

Demo Environment

After a company is finished onboarding, Gusto requires an additional internal step to review and approve that company.

We provide the endpoint PUT companies/{company_uuid}/approve to facilitate company approvals in the demo environment.

14. Monitor webhook for approval

Using webhooks you can detect an update to a Company.

Finishing company onboarding automatically triggers Gusto’s internal approval process which must be completed before a company can process payroll. The approval process can take up to two business days so it is recommended that company onboarding is completed accordingly to ensure employees are paid on time.

When you receive a updated webhook, check the company’s approval status using our get a company endpoint where "company_status": "Approved".

πŸ“˜

Update Information Post Onboarding

  • If you need to make any changes to company or employee info post onboarding, you can use the Company and Employee endpoints to do so.
  • If using Flows (Pre-built UI), recall the Flows to make the necessary adjustments. State tax information cannot be edited via Flows so you must contact Support.