A reference guide for building AI agents: every method, how to authenticate, and the permissions each one needs.
The Gusto API is how an app or AI agent works with a company's payroll: reading employees, calculating and running payroll, paying contractors, and tracking time off. Access is granted through an OAuth token whose scopes, named by resource and action like payrolls:read, decide what each call can read or write, and a token is tied to a single company so it cannot reach another. Versions are dated, and Gusto can push events to a subscribed webhook URL when something happens in a company.
How an app or AI agent connects to Gusto determines what it can reach. There is a route for making calls, a route for receiving events, and a hosted server that helps an agent build against the API, and each is governed by the token behind it and the scopes that token carries.
The REST API answers at https://api.gusto.com/v1, with a separate demo host at https://api.gusto-demo.com/v1 for testing. A call authenticates with an OAuth bearer token and pins behavior with the X-Gusto-API-Version header.
Gusto POSTs events to a subscribed HTTPS URL. A subscription names the resource types to watch and is verified once with a token, after which each delivery carries an X-Gusto-Signature header that is an HMAC of the payload, keyed by the verification token, so a receiver can confirm the event came from Gusto.
A hosted Model Context Protocol server at https://embedded-payroll.readme.io/mcp lets an AI coding tool search and fetch the API reference and documentation while building against Gusto. It is in open beta, and it exposes reference and docs search rather than live payroll operations, so it helps write integration code, not run payroll.
An app sends an admin through the OAuth 2.0 authorization-code flow at api.gusto.com to authorize one company, then exchanges the code for an access token and a refresh token. The access token is a bearer token sent as Authorization: Bearer, and it is scoped to that single company under Gusto's strict access model.
A system-level token authenticates application-wide actions that are not tied to one company, such as creating a new company. It uses the same bearer scheme and is distinct from the per-company token issued through OAuth.
The Gusto Embedded API is split into areas an agent can act on, like employees, companies, payrolls, contractors, and time off. Each area has its own methods and its own scopes, and writes in some areas pay people or move money.
List a company's employees, read and update a single employee, and create a new one.
Read a company's details and update its settings.
List and read payrolls, calculate, prepare, and submit a payroll for processing.
List a company's contractors and read a single contractor.
List a company's pay schedules, read one, and create a new schedule.
Read how much a job is paid through its compensation records.
List a company's bank accounts, create one, and verify a new account.
List a company's time off requests and approve a request.
List a company's departments and create a new department.
Filter by method, access, or permission, or search any path. Select a row for version detail, rate limits, the related webhook event, and the source.
| Method | Endpoint | What it does | Access | Permission | Version | |
|---|---|---|---|---|---|---|
EmployeesList a company's employees, read and update a single employee, and create a new one.4 | ||||||
| GET | /v1/companies/{company_id}/employees | Get all employees for a company, including onboarding, active, and terminated. | read | employees:read | Current | |
Returns every employee for the company the token is scoped to. Read-only. Acts onemployee Permission (capability) employees:readVersionAvailable since the API’s base version Webhook event employee.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v1/employees/{employee_id} | Get a single employee by id. | read | employees:read | Current | |
Read-only. Acts onemployee Permission (capability) employees:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v1/companies/{company_id}/employees | Create an employee under a company. | write | employees:manage | Current | |
Creating an employee needs the employees:manage scope, which is broader than employees:write. Acts onemployee Permission (capability) employees:manageVersionAvailable since the API’s base version Webhook event employee.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/employees/{employee_id} | Update an employee's details. | write | employees:write | Current | |
An update sends the resource version to guard against overwriting newer data; a stale version returns 409. Acts onemployee Permission (capability) employees:writeVersionAvailable since the API’s base version Webhook event employee.updatedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CompaniesRead a company's details and update its settings.2 | ||||||
| GET | /v1/companies/{company_id} | Get a company's details. | read | companies:read | Current | |
Some extra fields, like home address, payroll admin, and signatory, need the employees:read, company_admin:read, or signatories:read scopes too. Read-only. Acts oncompany Permission (capability) companies:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/companies/{company_id} | Update a company's settings. | write | companies:write | Current | |
A company token is scoped to a single company and cannot reach another. Acts oncompany Permission (capability) companies:writeVersionAvailable since the API’s base version Webhook event company.updatedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
PayrollsList and read payrolls, calculate, prepare, and submit a payroll for processing.5 | ||||||
| GET | /v1/companies/{company_id}/payrolls | Get all payrolls for a company, by default the processed regular payrolls from the past six months. | read | payrolls:read | Current | |
Filterable by processing status and payroll type. Read-only. Acts onpayroll Permission (capability) payrolls:readVersionAvailable since the API’s base version Webhook event payroll.processedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v1/companies/{company_id}/payrolls/{payroll_id} | Get a single payroll for a company. | read | payrolls:read | Current | |
Read-only. Acts onpayroll Permission (capability) payrolls:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/companies/{company_id}/payrolls/{payroll_id}/prepare | Prepare a payroll for editing, returning the version used to make further updates. | write | payrolls:write | Current | |
Preparing a calculated payroll cancels its calculations so it can be edited again. Acts onpayroll Permission (capability) payrolls:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/companies/{company_id}/payrolls/{payroll_id}/calculate | Calculate an unprocessed payroll, returning the taxes and net pay. | write | payrolls:write | Current | |
Asynchronous; a successful request returns 202 and the result arrives by webhook. Acts onpayroll Permission (capability) payrolls:writeVersionAvailable since the API’s base version Webhook event payroll.calculatedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/companies/{company_id}/payrolls/{payroll_id}/submit | Submit an unprocessed payroll to be calculated and run. | write | payrolls:run | Current | |
This is the call that actually pays people. Asynchronous; a successful request returns 202. Acts onpayroll Permission (capability) payrolls:runVersionAvailable since the API’s base version Webhook event payroll.submittedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
ContractorsList a company's contractors and read a single contractor.2 | ||||||
| GET | /v1/companies/{company_id}/contractors | Get all contractors for a company, active and inactive, individual and business. | read | contractors:read | Current | |
Read-only. Acts oncontractor Permission (capability) contractors:readVersionAvailable since the API’s base version Webhook event contractor.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v1/contractors/{contractor_uuid} | Get a single contractor by id. | read | contractors:read | Current | |
Read-only. Acts oncontractor Permission (capability) contractors:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Pay schedulesList a company's pay schedules, read one, and create a new schedule.3 | ||||||
| GET | /v1/companies/{company_id}/pay_schedules | Get all pay schedules for a company. | read | pay_schedules:read | Current | |
Read-only. Acts onpay_schedule Permission (capability) pay_schedules:readVersionAvailable since the API’s base version Webhook event pay_schedule.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| GET | /v1/companies/{company_id}/pay_schedules/{pay_schedule_id} | Get a single pay schedule for a company. | read | pay_schedules:read | Current | |
Read-only. Acts onpay_schedule Permission (capability) pay_schedules:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v1/companies/{company_id}/pay_schedules | Create a new pay schedule for a company. | write | pay_schedules:write | Current | |
A company can have multiple pay schedules. Acts onpay_schedule Permission (capability) pay_schedules:writeVersionAvailable since the API’s base version Webhook event pay_schedule.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
CompensationsRead how much a job is paid through its compensation records.1 | ||||||
| GET | /v1/compensations/{compensation_id} | Get a compensation, which holds how much a job is paid. | read | compensations:read | Current | |
A compensation belongs to a job on an employee. Read-only. Acts oncompensation Permission (capability) compensations:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Company bank accountsList a company's bank accounts, create one, and verify a new account.3 | ||||||
| GET | /v1/companies/{company_id}/bank_accounts | Get all bank accounts for a company. | read | company_bank_accounts:read | Current | |
Read-only. Acts oncompany_bank_account Permission (capability) company_bank_accounts:readVersionAvailable since the API’s base version Webhook event bank_account.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v1/companies/{company_id}/bank_accounts | Create a company bank account, which triggers two verification deposits. | write | company_bank_accounts:write | Current | |
A new account starts with verification_status awaiting_deposits until it is verified. Acts oncompany_bank_account Permission (capability) company_bank_accounts:writeVersionAvailable since the API’s base version Webhook event bank_account.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/companies/{company_id}/bank_accounts/{bank_account_uuid}/verify | Verify a company bank account using the two micro-deposit amounts. | write | company_bank_accounts:write | Current | |
Verifying moves the account to verified so it can fund payroll. Acts oncompany_bank_account Permission (capability) company_bank_accounts:writeVersionAvailable since the API’s base version Webhook event bank_account.updatedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Time offList a company's time off requests and approve a request.2 | ||||||
| GET | /v1/companies/{company_id}/time_off_requests | Get all time off requests, past and present, for a company. | read | time_off_requests:read | Current | |
Narrowable with start_date and end_date. Read-only. Acts ontime_off_request Permission (capability) time_off_requests:readVersionAvailable since the API’s base version Webhook event time_off_request.createdRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| PUT | /v1/time_off/requests/{time_off_request_uuid}/approve | Approve a time off request. | write | time_off_requests:approve | Current | |
Approval is a separate scope from time_off_requests:write, so an agent can read and edit requests without being able to approve them. Acts ontime_off_request Permission (capability) time_off_requests:approveVersionAvailable since the API’s base version Webhook event time_off_request.updatedRate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
DepartmentsList a company's departments and create a new department.2 | ||||||
| GET | /v1/companies/{company_id}/departments | Get all departments for a company, with the employees and contractors in each. | read | departments:read | Current | |
Read-only. Acts ondepartment Permission (capability) departments:readVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
| POST | /v1/companies/{company_id}/departments | Create a department for a company. | write | departments:write | Current | |
Employees and contractors are assigned to a department after it is created. Acts ondepartment Permission (capability) departments:writeVersionAvailable since the API’s base version Webhook eventNone Rate limitStandard limits apply SourceOfficial documentation ↗ | ||||||
Gusto can notify an app or AI agent when something happens in a company, like a payroll being paid or an employee being onboarded. It posts an event to a subscribed URL, so an integration learns about activity without polling.
| Event | What it signals | Triggered by |
|---|---|---|
Company.updated | Fires when a company's details change. The Company subscription type also covers provisioned, onboarded, approved, suspended, and other lifecycle events. | /v1/companies/{company_id} |
Employee.created | Fires when an employee is created. The Employee subscription type also covers updated, onboarded, terminated, rehired, and deleted. | /v1/companies/{company_id}/employees/v1/companies/{company_id}/employees |
Employee.updated | Fires when an employee's details are updated. | /v1/employees/{employee_id} |
Contractor.created | Fires when a contractor is created. The Contractor subscription type also covers updated, onboarded, deactivated, reactivated, and deleted. | /v1/companies/{company_id}/contractors |
Payroll.calculated | Fires when a payroll finishes calculating, delivering the asynchronous result of a calculate call. | /v1/companies/{company_id}/payrolls/{payroll_id}/calculate |
Payroll.submitted | Fires when a payroll is submitted to be run. | /v1/companies/{company_id}/payrolls/{payroll_id}/submit |
Payroll.processed | Fires when a payroll is processed. The Payroll subscription type also covers paid, reversed, cancelled, and processing_failed. | /v1/companies/{company_id}/payrolls/v1/companies/{company_id}/payrolls/{payroll_id}/submit |
PaySchedule.created | Fires when a pay schedule is created. The PaySchedule subscription type also covers updated. | /v1/companies/{company_id}/pay_schedules/v1/companies/{company_id}/pay_schedules |
BankAccount.created | Fires when a company bank account is created. The BankAccount subscription type also covers updated and deleted. | /v1/companies/{company_id}/bank_accounts/v1/companies/{company_id}/bank_accounts |
BankAccount.updated | Fires when a company bank account changes, such as moving to verified. | /v1/companies/{company_id}/bank_accounts/{bank_account_uuid}/verify |
TimeOffRequest.created | Fires when a time off request is created. The TimeOffRequest subscription type also covers updated and deleted. | /v1/companies/{company_id}/time_off_requests |
TimeOffRequest.updated | Fires when a time off request changes, such as being approved. | /v1/time_off/requests/{time_off_request_uuid}/approve |
Gusto limits how fast an app or AI agent can call, through a per-token request quota measured over a rolling minute, returning a throttling response once the quota is spent.
Gusto meters requests per token over a rolling sixty-second window, allowing 200 requests per minute for each application-user pairing. The window starts at the first call and resets sixty seconds later. Going over returns HTTP 429 with the rate_limit_exceeded category, and only on a 429 does Gusto send a Retry-After header saying how many seconds to wait. Gusto recommends webhooks over polling to stay within the quota.
List endpoints page through the page parameter, which is 1-based, and the per parameter for page size. Page sizes vary by endpoint, for example payrolls default to 25 and cap at 100 per page. Responses carry pagination details in the X-Pagination headers, including the total count and the total number of pages.
Requests and responses are JSON. Page size is capped per endpoint, commonly at 100 records. There is no single documented payload size limit across the whole API.
The status codes an agent should handle, and what to do about each.
| Status | Code | Meaning | What to do |
|---|---|---|---|
| 401 | invalid_token | The token is missing, invalid, or expired. A Gusto access token expires after two hours. | Refresh the access token with the refresh token and client credentials, then retry. |
| 403 | missing_oauth_scopes | The token is valid but lacks a scope the request needs, such as payrolls:read or employees:write. | Grant the missing scope to the application in the Developer Portal, then retry. |
| 404 | not_found | The resource or endpoint does not exist in the requested API version, or the token cannot see it. | Confirm the path, the company the token is scoped to, and the X-Gusto-API-Version header. |
| 406 | invalid_api_version | The X-Gusto-API-Version header is malformed. It must be a date in YYYY-MM-DD form. | Send a valid dated version, such as 2026-06-15. |
| 409 | invalid_resource_version | An update used an out-of-date resource version, so the resource changed since it was last read. | Refetch the resource to get its current version, then resend the update. |
| 422 | invalid_attribute_value | Validation failed: a field is missing, malformed, or breaks a business rule. Related codes include missing_parameter, invalid_operation, and payroll_blocker. | Read the errors in the response body, correct the named field, and resend. |
| 429 | rate_limit_exceeded | The request quota for the token was exceeded over the rolling minute. | Wait for the Retry-After header's seconds, then retry with exponential backoff. |
| 500 | internal_error | An unexpected error on Gusto's side. Gusto's engineering team is notified automatically. | Retry after a short delay, and contact Gusto support if it persists. |
Gusto versions its API by date through the X-Gusto-API-Version header. The newest version is 2026-06-15, and an application has a default version it falls back to when no version header is sent.
The 2026-06-15 version is the newest dated release and carries backward-incompatible changes from the prior version. It is selected with the X-Gusto-API-Version header. Gusto ships backward-incompatible versions on a roughly quarterly cadence, and on this release the 2026-02-01 version entered its twelve-month deprecation, while 2024-04-01 reached end of support.
A dated release that became the prior version when 2026-06-15 shipped, entering its twelve-month deprecation window at that point. Recent additions across these releases include the Payroll Digests API for multi-company monitoring, payroll.deleted webhooks, time off requests with admin approval, and contractor management flows.
A dated release that entered its deprecation window when a newer version superseded it, following Gusto's twelve-month support policy of six months of full support and six months of critical fixes.
A dated release in Gusto's quarterly cadence, also the version pinned by Gusto's official API clients. Each dated version is supported for twelve months after a newer one launches.
An earlier dated release that reached end of support effective 15 June 2026, when 2026-06-15 launched. After end of support a version no longer receives fixes.
An integration can pin a version and move up on a schedule that suits it.
Gusto Embedded changelog ↗Bollard AI sits between a team's AI agents and Gusto. Grant each agent exactly the access it needs, read or write, resource by resource, and every call is checked and logged.