Migrate an existing company
Learn how to migrate a Gusto.com company to your Embedded Payroll system
For existing Gusto.com customers, you can migrate their company to your Embedded Payroll product, using OAuth2 for authentication, instead of creating a new company for them. Find libraries supporting OAuth on the OAuth2 homepage.
Only primary or full-access admins can authorize new apps. Some users manage payroll for multiple companies and must select which one to connect to during authorization, so your integration should be ready to handle this.
1. OAuth connect
Securely connect an existing Gusto company to your Embedded Payroll integration using the OAuth authentication flow. This ensures only authorized administrators can grant access and maintain control over their company data.
Below is an overview of the OAuth flow:

Retrieve an authorization code
To begin the migration, the companyβs primary or full-access administrator must approve your application accessing their information on Gusto.
Theyβll be directed to Gustoβs login and authorization screen, where they authenticate and grant your application permission.
Authorization URL structure
https://api.gusto.com/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code
Parameters
client_id
: Your applicationβs unique identifier, generated for you when you create an app in the Gusto Developer Portal.redirect_uri
: Sometimes called a βcallback URI,β this is the URL to which the user will be redirected after authorization. OAuth does not support wildcard URIs or URIs with fragments (e.g #).response_type
: Always set tocode
.
After successful authentication, Gusto redirects the user to your redirect_uri
, appending an authorization code as a query parameter:
https://example.com/callback?code=AUTHORIZATION_CODE
The authorization code is valid for 10 minutes. It must be exchanged for an access token before it expires.
Exchange the authorization code for an access token
Once you have the authorization code, exchange it for an access token by making a POST /oauth/token
request.
Sample request
curl --request POST \
--url https://api.gusto.com/oauth/token \
--header 'Content-Type: application/json' \
--data '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"redirect_uri": "https://example.com/callback",
"code": "AUTHORIZATION_CODE",
"grant_type": "authorization_code"
}'
Sample response
{
"access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1"
}
Youβll use the access token in the Authorization
header when calling the API. Tokens are tied to one company. For guidance on refreshing and storing tokens, see Authentication and authorization.
2. Retrieve information from the token
After obtaining an access token, use the GET /v1/token_info endpoint to retrieve the company's unique identifier.
Sample request
curl --request GET \
--url https://api.gusto-demo.com/v1/token_info \
--header 'accept: application/json' \
--header 'authorization: Bearer COMPANY_ACCESS_TOKEN'
Sample response
{
"resource_type": "Company",
"resource_uuid": "123e4567-e89b-12d3-a456-426614174000"
}
3. Accept terms of service (TOS)
Using the uuid
for the company you want to migrate, accept Gustoβs Terms of Service using the POST /v1/partner_managed_companies/{company_uuid}/accept_terms_of_service endpoint. Each company added must accept the Terms of Service.
Sample request
curl --request POST \
--url https://api.gusto-demo.com/v1/partner_managed_companies/123e4567-e89b-12d3-a456-426614174000/accept_terms_of_service \
--header 'accept: application/json' \
--header 'authorization: Bearer COMPANY_ACCESS_TOKEN' \
--header 'content-type: application/json' \
--data '{
"email": "[email protected]",
"external_user_id": "USER_12345",
"ip_address": "192.168.1.1"
}'
Sample response
{
"status": "accepted",
"company_uuid": "123e4567-e89b-12d3-a456-426614174000",
"timestamp": "2025-01-29T12:34:56Z"
}
4. Migrate the company
Once the Terms of Service have been accepted, finalize the migration to Embedded Payroll by using the PUT /v1/partner_managed_companies/{company_uuid}/migrate endpoint.
- The email you pass to the migrate endpoint must be the company signatory email, which you can retrieve using the GET /v1/companies/{company_uuid}/signatories endpoint.
Sample request
curl --request PUT \
--url https://api.gusto-demo.com/v1/partner_managed_companies/123e4567-e89b-12d3-a456-426614174000/migrate \
--header 'accept: application/json' \
--header 'authorization: Bearer COMPANY_ACCESS_TOKEN' \
--header 'content-type: application/json' \
--data '{
"email": "[email protected]",
"ip_address": "192.168.1.1",
"external_user_id": "USER_12345"
}'
Sample response
{
"status": "migrated",
"company_uuid": "123e4567-e89b-12d3-a456-426614174000",
"timestamp": "2025-01-29T13:45:00Z"
}
5. (Recommended) Add admin users
The user who authenticated in step is now the primary payroll administrator of the migrated company. You can add administrators or change the administrator, use the POST /v1/companies/{company_id}/admins endpoint.
Sample request
curl --request POST \
--url https://api.gusto-demo.com/v1/companies/123e4567-e89b-12d3-a456-426614174000/admins \
--header 'accept: application/json' \
--header 'authorization: Bearer COMPANY_ACCESS_TOKEN' \
--header 'content-type: application/json' \
--data '{
"first_name": "Harold",
"last_name": "Hill",
"email": "[email protected]"
}'
const fetch = require('node-fetch');
const url = 'https://api.gusto-demo.com/v1/companies/company_id/admins';
const options = {
method: 'POST',
headers: {
accept: 'application/json',
'content-type': 'application/json',
authorization: 'Bearer <<COMPANY_ACCESS_TOKEN>>'
},
body: JSON.stringify({first_name: 'Harold', last_name: 'Hill', email: '[email protected]'})
};
fetch(url, options)
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('error:' + err));
Sample response
{
"id": "987654321",
"first_name": "Harold",
"last_name": "Hill",
"email": "[email protected]",
"role": "payroll_admin",
"company_id": "123e4567-e89b-12d3-a456-426614174000"
}
Updated 7 days ago