ml-connector
OdooSalesforce

Odoo and Salesforce integration

Odoo runs your accounting, purchasing, and inventory. Salesforce runs your sales pipeline and customer relationships. Connecting them keeps your customer master data, sales orders, and revenue records in agreement across both systems. New customers in Odoo populate Salesforce Accounts automatically, sales orders created in Odoo flow into Salesforce with amounts and line items, and invoices post to both systems so your financial records match your CRM pipeline. ml-connector handles the different REST and XML-RPC transports on each side and moves data on a schedule you control.

How Odoo works

Odoo is a modular open-source ERP available as a cloud SaaS (Odoo Online at odoo.com), managed platform (Odoo.sh), or self-hosted deployment. It exposes customers, sales orders, invoices, invoice lines, GL accounts, payments, analytical accounts, products, and employees through XML-RPC over HTTP POST to xmlrpc/2 endpoints or through JSON-2 REST to json/2 endpoints (Odoo 19+). Authentication uses an API key paired with a username, obtained via authenticate() in XML-RPC or passed as a Bearer token in JSON-2. Odoo has no native webhooks, so records are read by polling write_date filters with high-water-mark timestamps. External API access requires the Custom pricing plan; XML-RPC is scheduled for removal in Odoo 22 in 2028.

How Salesforce works

Salesforce is a cloud-native CRM that exposes Accounts, Contacts, Opportunities, Orders, OrderItems, Invoices, Leads, Products, and Pricebooks through REST JSON APIs at the services/data endpoint. Authentication uses OAuth 2.0 Client Credentials Flow with a client ID, client secret, and My Domain URL; access tokens expire after a configurable session timeout (default 2 hours). Salesforce supports real-time change notifications via Change Data Capture and Pub/Sub API with 72-hour event retention, or polling via the updated/ endpoint with datetime ranges. Invoices require the Revenue Cloud or Order Management add-on; basic Sales Cloud orgs may lack the Invoice object.

What moves between them

The main flow is Odoo to Salesforce. Customer records from Odoo sync to Salesforce Accounts and Contacts on a polling schedule, including names, emails, and addresses. Sales orders flow from Odoo into Salesforce Orders with line items mapped from Odoo's sale.order.line to Salesforce OrderItems, and amounts and dates preserved. Invoices flow from Odoo account.move (type invoice) into Salesforce Invoices where the Revenue Cloud add-on is enabled, allocated to the matching Salesforce Account. Reference data such as product codes and prices are aligned in both directions so line items land on existing Salesforce products. Contacts in Salesforce can feed back to Odoo as partner contacts if bidirectional sync is enabled.

How ml-connector handles it

ml-connector stores both the Odoo API key and Salesforce OAuth credentials encrypted and refreshes the Salesforce OAuth token when a call returns a session-expired response. On the Odoo side it polls using the customer's configured base URL (Odoo Online, Odoo.sh, or self-hosted) and filters by write_date to capture only new and modified records since the last run. For Salesforce it uses the Client Credentials Flow to obtain a fresh token at each poll cycle. Because Salesforce's Pub/Sub API is not available in all org editions, ml-connector defaults to polling but can switch to streaming where CDC is enabled. Odoo customers map to Salesforce Accounts by matching on external ID; invoices map to Orders by their source sales order ID. Odoo's invoice totals are stored as OrderItem amounts in Salesforce so the two ledgers reconcile. Salesforce rate limits are monitored and backoff applied on 429 responses. Every record carries a full audit trail and can be replayed if a downstream insert fails.

A real-world example

A mid-sized B2B software reseller uses Odoo to manage contracts, billing, and GL accounting, and Salesforce to track customer relationships and sales pipelines. Before the integration, the sales team created deals in Salesforce and the operations team manually keyed the matching orders and contracts into Odoo, then spent hours at month-end reconciling invoice totals between Odoo GL and Salesforce revenue records. With Odoo and Salesforce connected, every order created in Odoo flows into Salesforce as an Order within minutes, sales team can see accurate contract values and due dates alongside each opportunity, and invoices post to both systems automatically so month-end reconciliation begins with revenue already aligned.

What you can do

  • Sync Odoo customers and contacts to Salesforce Accounts and Contacts with address and email details.
  • Map Odoo sales orders to Salesforce Orders with line items and amounts, keeping pipeline values in agreement.
  • Post Odoo invoices into Salesforce Invoices and Orders so revenue records reconcile across both systems.
  • Authenticate Odoo with API key and Salesforce with OAuth 2.0 Client Credentials Flow, with token refresh on expiry.
  • Poll on a schedule aligned with your sales and billing cycles, with retries and a full audit trail on every record.

Questions

Which direction does data move between Odoo and Salesforce?
The main flow is Odoo to Salesforce. Customers, sales orders, and invoices move from Odoo into Salesforce. Contact details, product information, and pricing can align in both directions. Salesforce is the system of record for sales pipeline; Odoo is the system of record for invoices and GL postings.
How does the integration handle Odoo's lack of webhooks?
ml-connector polls Odoo on a schedule by filtering on write_date with a high-water-mark timestamp, so only new and modified records since the last run are fetched. The polling cadence aligns with your typical sales and billing cycle, not real-time. If the same record is updated in Odoo multiple times between polls, only the latest version is sent to Salesforce.
What happens if Salesforce OAuth tokens expire during a sync?
ml-connector detects session-expired responses and automatically refreshes the OAuth token using the stored client credentials before retrying the failed request. The refresh does not interrupt the flow; the sync resumes without manual intervention.

Related integrations

Connect Odoo and Salesforce

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

Get started