ml-connector
OdooGusto

Odoo and Gusto integration

Odoo runs your accounting, purchasing, and HR. Gusto runs payroll and benefits. Connecting the two keeps your employee rosters and GL accounts aligned with payroll processing, so new hires in Odoo flow into Gusto with the right job codes and cost centers, and payroll-generated GL transactions can be read back into Odoo for accounting reconciliation. ml-connector bridges Odoo's REST and XML-RPC APIs with Gusto's OAuth2 and webhook system, moving data on a schedule you define.

How Odoo works

Odoo exposes employees, GL accounts, cost centers, purchase orders, invoices, and analytic accounts through XML-RPC over HTTP POST and JSON-2 REST APIs (Odoo 19+). Authentication requires an API key paired with a username, which ml-connector uses to obtain a session token for XML-RPC or presents as a Bearer token for JSON-2. Odoo Online instances use subdomain URLs; self-hosted and Odoo.sh instances have custom base URLs. External API access requires a Custom pricing plan. Odoo has no production-grade webhook system, so ml-connector polls using write_date filters to detect changes incrementally.

How Gusto works

Gusto exposes employees, jobs, pay schedules, payroll records, company benefits, contractors, and bank accounts through REST JSON APIs at https://api.gusto.com. Authentication uses OAuth2 Authorization Code flow, with tokens that expire in 2 hours and refresh tokens that never expire. Each OAuth token is scoped to a single company, so multi-company setups require separate tokens per company. Gusto supports webhooks for payroll, company, employee, contractor, and bank account events, retrying failed webhook deliveries up to 16 times over 3 days. Webhook signatures are verified with HMAC-SHA256. Rate limit is 200 requests per minute per OAuth grant.

What moves between them

Employee records flow from Odoo into Gusto so payroll rosters stay current with Odoo hires and transfers. GL accounts, cost centers, and job codes from Odoo are read and mapped to Gusto compensation records and earning types. Pay schedules, payroll run data, and compensation records flow from Gusto back to Odoo via webhooks or polling, allowing payroll events to update GL journals and employee records. Contractor and bank account data are read-only from Gusto into Odoo for reconciliation purposes.

How ml-connector handles it

ml-connector stores both credential sets encrypted, presenting Odoo's API key on each REST or XML-RPC call and maintaining Gusto's OAuth2 bearer token, refreshing it every 2 hours or when a call returns 401. Since Odoo lacks webhooks, ml-connector polls employee and GL account tables using write_date timestamps, storing a high-water mark per query to detect only new and modified records. Gusto webhooks are listened to for real-time payroll events; ml-connector validates each webhook signature with HMAC-SHA256 and the subscription verification token. Employee records from Odoo are mapped to Gusto compensation records using job code and cost center fields. Because Gusto is single-company-per-token, ml-connector stores the company UUID and routes all Gusto calls through that token. Rate limits are monitored; ml-connector respects Gusto's 200-req/min rolling window and Odoo's integration user access rules. Every webhook received and every polling cycle carries a full audit trail.

A real-world example

A small accounting firm uses Odoo for invoicing, GL accounts, and employee tracking, and Gusto for payroll and benefits for its own staff of 20 people across two departments. Before the integration, the HR person manually entered new employees from Odoo into Gusto, assigned them to the right cost centers, and reviewed payroll after each run to ensure GL coding matched. With Odoo and Gusto connected, new hires in Odoo are pushed to Gusto automatically with their department and cost center mapped, and payroll webhooks alert the accounting team when runs are processed, letting them reconcile GL accounts without re-keying employee data.

What you can do

  • Sync employees from Odoo to Gusto with job codes, cost centers, and department assignments.
  • Map Odoo GL accounts and analytic accounts to Gusto earning types and company benefits for accurate payroll GL coding.
  • Receive payroll events from Gusto via webhooks and log them to Odoo with signature verification and audit trails.
  • Poll Odoo on a schedule to detect employee and GL account changes incrementally using write_date timestamps.
  • Handle Gusto OAuth2 token refresh, single-company scoping, and Odoo API key authentication transparently.

Questions

Which direction does data move between Odoo and Gusto?
Employee records and GL dimensions flow from Odoo into Gusto so payroll rosters and cost centers align. Payroll run data, pay schedules, and compensation records flow from Gusto back to Odoo via webhooks and polling for GL reconciliation. Contractor and bank account data are read-only from Gusto.
How does ml-connector detect changes in Odoo if it has no webhooks?
ml-connector polls Odoo's employee and GL account tables on a schedule you define, using write_date filters to detect only new and modified records since the last poll. ml-connector stores a high-water mark timestamp per table and continues from there, so every polling cycle processes only changed data.
Does Gusto's single-company-per-token limit affect multi-company setups?
Yes. Each Gusto OAuth token is scoped to a single company, so if you run multiple Gusto companies, ml-connector requires a separate token per company and routes payroll and employee records through the correct token based on the company UUID.

Related integrations

Connect Odoo and Gusto

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started