---
updatedAt: 2026-04-28T00:28:57.000Z
agentTools:
  siteIndex: https://docs.gusto.com/llms.txt
  projectIndex: https://docs.gusto.com/embedded-payroll/llms.txt
---

# Onboard a Contractor

Add a 1099 worker to your company payroll

Onboarding a Contractor is similar to [onboarding a W2 Employee](https://docs.gusto.com/embedded-payroll/docs/onboard-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:

1. By employer
2. By contractor (“Self-onboarding”)

Both can be done using Gusto's [pre-built flows](https://docs.gusto.com/embedded-payroll/docs/flow-types) or using the Contractor APIs to build custom UI/UX. The `contractor_management` flow is the recommended steady-state interface for managing contractors—it supports onboarding, dismissals, rehires, and ongoing contractor management in a single flow.

To learn more about the difference between contractor onboarding methods, review the [FAQ](https://docs.gusto.com/embedded-payroll/docs/onboard-a-contractor#faq) or see our guide on [Contractor self-onboarding](https://docs.gusto.com/embedded-payroll/docs/contractor-self-onboarding).

## 1. Create a contractor

You can create a contractor using the [POST companies/\{company\_id}/contractors](https://docs.gusto.com/embedded-payroll/reference/post-v1-companies-company_uuid-contractors) endpoint.

The example below shows a contractor "self-onboarding".

**Sample request**

```curl
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": "happinesspie@example.com",
     "work_state": "GA",
     "hourly_rate": "40.0"
}
'
```
```javascript
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: 'happinesspie@example.com',
    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**

```json
{
  "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": "happinesspie@example.com",
  "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

<Callout icon="📘" theme="info">
  After creating the contractor, it has an `address` by 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.
</Callout>

1. To update a contractor's address, you first need to get the version of the address using the [GET contractors/\{contractor\_uuid}/address](https://docs.gusto.com/embedded-payroll/reference/get-v1-contractors-contractor_uuid-address) endpoint.\
   **Sample request**
   ```curl
   curl --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**
   ```json
   {
     "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
   }
   ```
2. Use the `version` to update the contractor’s address details using the [PUT contractors/\{contractor\_uuid}/address](https://docs.gusto.com/embedded-payroll/reference/put-v1-contractors-contractor_uuid-address) endpoint.\
   **Sample request**

   ```curl
   curl --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"
   }
   '
   ```
   ```javascript
   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**

   ```json
   {
     "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](https://docs.gusto.com/embedded-payroll/reference/put-v1-contractors-contractor_id-payment_method) endpoint.

To create a bank account for a contractor use the [POST contractors/\{contractor\_uuid}/bank\_accounts](https://docs.gusto.com/embedded-payroll/reference/post-v1-contractors-contractor_uuid-bank_accounts) endpoint.

<Callout icon="📘" theme="info">
  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.
</Callout>

**Sample request**

```curl
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"
}
'
```
```javascript
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](https://docs.gusto.com/embedded-payroll/reference/put-v1-contractors-contractor_uuid-onboarding_status) endpoint.

**Sample request**

```curl
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"
}
'
```
```javascript
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**

```json
{
  "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](https://docs.gusto.com/embedded-payroll/docs/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.

<Callout icon="📘" theme="info">
  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.
</Callout>