Onboard a contractor
Add a 1099 worker to your company payroll
Onboarding a Contractor is similar to onboarding a W2 Employee but requires less information. Jobs and compensations are simplified for contractors since these type of workers are not subject to the same minimum wage laws, tax calculations, and payroll rules.
Contractors may be added during a companyβs onboarding for payroll, or at any time after this initial onboarding is complete. A contractor can be setup in one of two ways:
- By employer
- By contractor (βSelf-onboardingβ)
Both can be done using Gustoβs pre-built flows or using the Contractor APIs to build custom UI/UX.
To learn more about the difference between contractor onboarding methods, review the FAQ or see our guide on Contractor self-onboarding.
1. Create a contractor
You can create an employee using the POST companies/{company_id}/contractors endpoint.
The example below shows a contractor "self-onboarding".
Sample request
curl --request POST \
--url https://api.gusto-demo.com/v1/companies/{company_uuid}/contractors \
--header 'accept: application/json' \
--header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
--header 'content-type: application/json' \
--data '
{
"type": "Individual",
"self_onboarding": true,
"file_new_hire_report": "true",
"wage_type": "Fixed",
"first_name": "Jenna",
"last_name": "Hunterson",
"start_date": "2022-03-14",
"email": "[email protected]",
"work_state": "GA",
"hourly_rate": "40.0"
}
'
const fetch = require('node-fetch');
const url = 'https://api.gusto-demo.com/v1/companies/{company_uuid}/contractors';
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: 'Bearer <<COMPANY_API_TOKEN>>'
},
body: JSON.stringify({
type: 'Individual',
self_onboarding: true,
file_new_hire_report: 'true,',
wage_type: 'Fixed',
first_name: 'Jenna',
last_name: 'Hunterson',
start_date: '2022-03-14',
email: '[email protected]',
work_state: 'GA',
hourly_rate: '40.0'
})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('error:' + err));
Sample response
{
"uuid": "cd84ccd5-3acb-4783-a8fa-722a135d76e2",
"company_uuid": "<company-uuid>",
"wage_type": "Fixed",
"version": "5c6dfbf5cae5ba55fe06034a903cd8e0",
"type": "Individual",
"first_name": "Jenna",
"last_name": "Hunterson",
"middle_initial": null,
"business_name": null,
"ein": null,
"has_ein": false,
"email": "[email protected]",
"department_uuid": null,
"dismissal_date": null,
"department_title": null,
"start_date": "2022-03-14",
"is_active": false,
"address": null,
"file_new_hire_report": false,
"work_state": "GA",
"onboarded": false,
"onboarding_status": "self_onboarding_started",
"payment_method": null,
"has_ssn": false,
"hourly_rate": "40.00"
}
2. Update a contractor's information
Add a contractor's address
After creating the contractor, it has an
addressby default. To "create" an address for the contractor, you need to update the existing address, which replaces it because a contractor can only have one address.
-
To update a contractor's address, you first need to get the version of the address using the GET contractors/{contractor_uuid}/address endpoint.
Sample requestcurl --request GET \ --url https://api.gusto-demo.com/v1/contractors/cd84ccd5-3acb-4783-a8fa-722a135d76e2/address \ --header 'X-Gusto-API-Version: 2025-06-15' \ --header 'accept: application/json' \ --header 'authorization: Bearer <token>'Sample response
{ "version": "d41d8cd98f00b204e9800998ecf8427e", "contractor_uuid": "cd84ccd5-3acb-4783-a8fa-722a135d76e2", "street_1": null, "street_2": null, "city": null, "state": null, "zip": null, "country": null, "active": true } -
Use the
versionto update the contractorβs address details using the PUT contractors/{contractor_uuid}/address endpoint.
Sample requestcurl --request PUT \ --url https://api.gusto-demo.com/v1/contractors/{contractor_uuid}/address \ --header 'accept: application/json' \ --header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \ --header 'content-type: application/json' \ --data ' { "version": "fe75bd065ff48b91c35fe8ff842f986c", "street_1": "39057 Broderick Light", "street_2": "Apt. 612", "city": "San Francisco", "state": "CA", "zip": "94107" } 'const fetch = require('node-fetch'); const url = 'https://api.gusto-demo.com/v1/contractors/{contractor_uuid}/address'; const options = { method: 'PUT', headers: { accept: 'application/json', 'content-type': 'application/json', authorization: 'Bearer <<COMPANY_API_TOKEN>>' }, body: JSON.stringify({ version: 'fe75bd065ff48b91c35fe8ff842f986c', street_1: '39057 Broderick Light', street_2: 'Apt. 612', city: 'San Francisco', state: 'CA', zip: '94107' }) }; fetch(url, options) .then(res => res.json()) .then(json => console.log(json)) .catch(err => console.error('error:' + err));Sample response
{ "version": "fe75bd065ff48b91c35fe8ff842f986c", "contractor_uuid": "cd84ccd5-3acb-4783-a8fa-722a135d76e2", "street_1": "39057 Broderick Light", "street_2": "Apt. 612", "city": "San Francisco", "state": "CA", "zip": "94107", "country": "USA", "active": true }
Create a contractor's bank account
Creating a contractor bank account will automatically update an contractor's payment method from Check to Direct Deposit. If you want to change the payment method, you can use the PUT contractors/{contractor_uuid}/payment_method endpoint.
To create a bank account for a contractor use the POST contractors/{contractor_uuid}/bank_accounts endpoint.
We only support one bank account per contractor. Using this endpoint on a contractor who already has a bank account will replace the existing bank account.
Sample request
curl --request POST \
--url https://api.gusto-demo.com/v1/contractors/{contractor_uuid}/bank_accounts \
--header 'accept: application/json' \
--header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
--header 'content-type: application/json' \
--data '
{
"name": "BoA Checking Account",
"routing_number": "266905059",
"account_number": "5809431207",
"account_type": "Checking"
}
'
const fetch = require('node-fetch');
const url = 'https://api.gusto-demo.com/v1/contractors/{contractor_uuid}/bank_accounts';
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: 'Bearer <<COMPANY_API_TOKEN>>'
},
body: JSON.stringify({
name: 'BoA Checking Account',
routing_number: '266905059',
account_number: '5809431207',
account_type: 'Checking'
})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('error:' + err));
Sample response
{
"uuid": "ede6bca0-b717-4c0b-a029-20d4f23ce3c4",
"contractor_uuid": "cd84ccd5-3acb-4783-a8fa-722a135d76e2",
"name": "BoA Checking Account",
"routing_number": "266905059",
"hidden_account_number": "XXXX1207",
"account_type": "Checking"
}
3. Mark the contractor as onboarded
With the basic details, address, and payment method complete, the final step is to mark the contractor as onboarding_completed using the PUT contractors/{contractor_uuid}/onboarding_status endpoint.
Sample request
curl --request PUT \
--url https://api.gusto-demo.com/v1/contractors/{contractor_uuid}/onboarding_status \
--header 'accept: application/json' \
--header 'authorization: Bearer <<COMPANY_API_TOKEN>>' \
--header 'content-type: application/json' \
--data '
{
"onboarding_status": "onboarding_completed"
}
'
const fetch = require('node-fetch');
const url = 'https://api.gusto-demo.com/v1/contractors/{contractor_uuid}/onboarding_status';
const options = {
method: 'PUT',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: 'Bearer <<COMPANY_API_TOKEN>>'
},
body: JSON.stringify({onboarding_status: 'onboarding_completed'})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('error:' + err));
Sample response
{
"uuid": "cd84ccd5-3acb-4783-a8fa-722a135d76e2",
"onboarding_status": "onboarding_completed",
"onboarding_steps": [
{
"title": "Basic details",
"id": "basic_details",
"required": true,
"completed": true,
"requirements": []
},
{
"title": "Enter compensation details",
"id": "compensation_details",
"required": true,
"completed": true,
"requirements": []
},
{
"title": "Add an address",
"id": "add_address",
"required": true,
"completed": true,
"requirements": []
},
{
"title": "Payment details",
"id": "payment_details",
"required": true,
"completed": true,
"requirements": []
},
{
"title": "Sign and acknowledge documents",
"id": "sign_documents",
"required": false,
"completed": false,
"requirements": [
"basic_details,",
"add_address"
]
},
{
"title": "File new hire report",
"id": "file_new_hire_report",
"required": false,
"completed": false,
"requirements": [
"basic_details"
]
}
]
}
FAQ
Whatβs the difference between onboarding by the employer and self-onboarding?
By employer
The employer is responsible for collecting and entering all contractorsβ information. This is typically done through paper or secure digital forms. Once entered, the employer completes the onboarding process on behalf of the employee.
Self-onboarding (by contractor)
The employer starts the process by entering only basic details, then invites the contractor to complete their own onboarding using the self-onboarding flow. Read more in Contractor self-onboarding.
Self-onboarding offers clear advantages:
- Contractors manage their own sensitive data, reducing the need to share it over insecure channels (like email).
- The process scales efficiently for organizations hiring many contractors.
- It saves time for both employers and contractors.
Gusto does not send emails directly to contractors. Any email or in-app invitations to self-onboard must be built into your Embedded Payroll implementation.
Updated 11 days ago