Skip to content
SyncMyShop

Systems

Odoo integration with your online store: orders in, stock per warehouse out

Since Odoo 19 an integration talks to Odoo over the JSON-2 API with an API key that expires after at most 90 days for a normal user, and XML-RPC is removed in Odoo 22. We build the integration on your Odoo version, plan and apps, then host and run it.

What Odoo is and who runs it

Odoo is an ERP from Belgium built as separate apps: Sales, Purchase, Inventory, Accounting, Manufacturing, CRM and its own website and store. There is an open-source Community edition and a paid Enterprise edition on subscription. Each installed app adds its own models and fields, and Odoo documents the API per database for that reason: two Odoo databases do not offer the same API.

Two things decide what an integration can do: where Odoo runs and which version it is.

Hosting Custom modules Versions
Odoo Online none, also no Apps Store modules major versions plus SaaS versions every 2 to 3 months
Odoo.sh yes major versions
Own server yes major versions, extended support available

Odoo ships a major version every fall with 3 years of standard support. Odoo 20.0 came out in September 2026, 19.0 in September 2025 and 18.0 in October 2024. An integration built today usually runs on 18 or 19 and goes through an upgrade within two years.

What connects to Odoo

In most setups Odoo owns products, stock, prices and invoices. The store owns the order and the new customer.

Flow Direction Odoo model
Orders store to Odoo sale.order with order_line
Customers and addresses store to Odoo res.partner
Products and variants Odoo to store product.template, product.product
Stock Odoo to store free_qty on product.product; stock.quant
Price lists Odoo to store product.pricelist, product.pricelist.item
Shipping and tracking Odoo to store stock.picking, field carrier_tracking_ref
Invoices Odoo to store account.move

An order goes in with its lines in one call. Customer and product travel as Odoo IDs, so the integration looks them up first. This is order SHOP-100482 from Harbor Supply Co. on Odoo 19:

POST /json/2/sale.order/create HTTP/1.1
Host: harborsupply.odoo.com
Authorization: bearer 3f9c...e1a7
Content-Type: application/json; charset=utf-8

{
  "vals_list": [{
    "partner_id": 4711,
    "partner_shipping_id": 4712,
    "client_order_ref": "SHOP-100482",
    "order_line": [[0, 0, {
      "product_id": 881, "product_uom_qty": 12,
      "price_unit": 17.08, "tax_ids": [[6, 0, [17]]]
    }]]
  }]
}

The three-element lists are Odoo's write commands for related records: 0 creates a line, 6 replaces the set of taxes. Over the API they have to be sent literally, as numbers. The store order number goes into client_order_ref, the Customer Reference field. The fields per flow are on order integration.

How Odoo exposes data

JSON-2 from Odoo 19, XML-RPC before it

Version External API Authentication
Odoo 17 and 18 XML-RPC and JSON-RPC on /xmlrpc/2 and /jsonrpc database, login, password or API key
Odoo 19 JSON-2 on /json/2/<model>/<method>; RPC deprecated API key as bearer token
Odoo 20 JSON-2; RPC database service removed API key as bearer token
Odoo 22 (fall 2028) JSON-2 only API key as bearer token

Both APIs reach the same models and methods Odoo uses internally: search_read, create, write, and the buttons on a form, such as action_confirm on a sales order. Which models and fields a database has depends on the installed apps. Methods whose name starts with an underscore cannot be called over the API. On a server with several databases the database name goes in the X-Odoo-Database header.

API keys that expire

An API key belongs to a user and Odoo shows it once. In Odoo 19 every key has an expiry date, and for a normal internal user the maximum is 90 days; only an administrator can create a key without one. Odoo recommends a separate bot user for an integration, with only the access rights it needs. A 90-day key means the integration stops after three months unless something replaces the key. Odoo provides res.users.apikeys/generate for that: the integration creates a new key with the current one and revokes the old one. By default a user may hold 10 keys created this way; the 11th returns HTTP 422.

Only on the Custom plan

Odoo states that data access through the external API is only available on Custom plans, not on One App Free or Standard. A store integration is external API use. The JSON-2 API documentation lists the plan rule, the authentication and the error responses.

Every call is its own transaction

Odoo's external API documentation gives no request limit per minute. What it does say: every JSON-2 call runs in its own database transaction, and chaining several calls into one transaction is not possible. An order therefore takes two transactions. create makes a quotation and action_confirm turns it into a sales order. When the second call fails, a quotation with the store order number stays behind.

A store order written to Odoo 19 in two calls, with a failed confirm and a retry The integration looks up the order by client_order_ref, finds nothing and creates quotation 2291. The confirm call fails and its transaction is rolled back, so the quotation stays unconfirmed. On the retry the lookup finds quotation 2291, so the integration only confirms it and no second quotation is created. Integration queue Odoo 19 JSON-2 API sale.order/search_read client_order_ref [] (not found) sale.order/create [2291] quotation sale.order/action_confirm error, transaction rolled back Each call is its own transaction. Quotation 2291 exists and is not confirmed. retry after 60 seconds sale.order/search_read client_order_ref [2291] state: draft sale.order/action_confirm [2291] true One sales order for SHOP-100482, not two.
An order takes two calls in Odoo, each in its own transaction. The lookup on client_order_ref keeps a retry from creating a second quotation.

The arithmetic for 600 orders on a busy day: one lookup for the customer, one for the products of all lines together, one create and one action_confirm. That is 4 calls per order and 2,400 a day. Reads are paged: 15,000 variants through search_read with a limit of 1,000 is 15 calls. How fast Odoo answers depends on hosting and installed apps, so we measure it on your database before go-live. The general pattern is on integration throughput.

Where an Odoo integration gets stuck

What the store needs In Odoo Without a rule
One unique SKU per variant default_code on product.product, not enforced unique two variants share a code, the order lands on the wrong one
Sellable stock qty_available, free_qty, virtual_available stock in the store too high
Changed stock since the last run computed fields, no write_date change on the product stock changes missed
Customer price rules in product.pricelist.item, no public method wrong price in a B2B store
A field name after an upgrade tax_id became tax_ids in Odoo 19 every order fails after the upgrade

Variants and a code that is not unique. A product in Odoo is a product.template and each variant is a product.product. The store SKU belongs on the variant, in default_code (Internal Reference). Odoo warns about a duplicate code on the form and accepts it over the API. The barcode field is unique per company. The integration checks before each run that a SKU resolves to exactly one variant and puts a duplicate on the exception list. See variant mapping.

Three stock numbers and no change date. qty_available is what is physically there. free_qty is that minus what is reserved for confirmed orders. virtual_available adds planned receipts and deliveries. The store usually needs free_qty. With warehouse_id or location in the call context Odoo returns the number for one warehouse or location; without it, all internal locations are added up. All three are computed, so a stock move does not change the product's write_date, and an integration that filters products on write_date misses every stock change. We read changes from stock.quant instead. Odoo stores datetimes in UTC without a time zone, so a filter for midnight in New York during daylight saving time is 04:00:00 UTC. See which stock counts.

Customer prices. The price for a customer comes from that customer's price list: rules with a fixed price, a discount or a formula, a min_quantity and a date_start. The methods that turn those rules into a price start with an underscore and cannot be called over the API. The integration reads the rules and computes the price itself, or on Odoo.sh and a self-hosted server a small module does it. See customer-specific pricing.

Field names that change per version. The tax field on an order line was tax_id up to Odoo 18 and is tax_ids in Odoo 19. An integration that keeps sending the old name fails on every order after the upgrade. Before an upgrade the integration therefore runs as a dry run against a copy of the database. On Odoo Online that is a duplicate: at most 5 per database, valid for 15 days, and with "For testing purposes" checked, emails, payments and deliveries are switched off in the copy.

Platforms we integrate with Odoo

The integration is built on your Odoo, with your apps, price lists and warehouses. The store side is described per platform on Shopify, WooCommerce and Magento. For the ERP side in general see e-commerce ERP integration; other ERPs we integrate include Business Central and NetSuite.

We build the integration for a fixed price, then host, run and monitor it for a monthly fee. Before go-live it runs as a dry run: you see per order which customer, variants and taxes would be created in Odoo, without anything being written. All integrations come with a dashboard, logs and a per-run diff. Tell us your Odoo version and plan.

Frequently asked questions

Does the integration work with Odoo Online, Odoo.sh and a self-hosted server?

Yes. All three expose the same external API. The difference is what runs next to it: Odoo Online accepts no custom modules and no modules from the Odoo Apps Store, so everything goes through the standard models and public methods. On Odoo.sh and your own server a small module can be added, for example to compute a customer price inside Odoo.

Do I need the Odoo Custom plan?

Odoo's documentation says access to data through the external API is only available on Custom plans, not on One App Free or Standard. A store integration that reads and writes Odoo from outside is external API use. Calls that Odoo itself makes to a payment provider or carrier are not counted as external API on Odoo's pricing page.

Which Odoo version do I need?

Any version in standard support. Odoo 19 and 20 have the JSON-2 API; Odoo 17 and 18 have XML-RPC and JSON-RPC only. Standard support for Odoo 17 ended in September 2026 and runs to September 2027 for Odoo 18. A database on 17 or 18 will be upgraded soon, and the upgrade changes the API and some field names.

What happens to an XML-RPC integration when Odoo removes it?

The database service of XML-RPC and JSON-RPC is already gone in Odoo 20. The common and object services, which integrations use, are removed in Odoo 22, planned for fall 2028, and on Odoo Online in version 21.1, winter 2027. An integration on /xmlrpc/2/object has to move to /json/2 before then, and from a login and password to an API key in the header.

Can Odoo send a webhook when something changes?

Yes, through an automation rule with the action Send Webhook Notification, which POSTs the fields you select to a URL. Odoo's documentation describes no retries when the receiver is down. We treat the webhook as a signal and run a reconciliation pass on write_date next to it, so a missed call does not become a missed order. See why webhooks are not a guarantee.

Odoo has its own eCommerce app. Why an integration?

With Odoo eCommerce the store and the ERP are one database and nothing needs integrating. This page is about a store on another platform, such as Shopify, WooCommerce or Magento, with Odoo behind it. Then there are two systems, each with its own product ID, customer and order, and the mapping between them is the work.

Tell us what you need

Tell us which systems you use and what needs to work better. We reply personally within one working day. We help you define the work, then agree the price and timing before you commit.

  • You know the price and the timeline before you commit to anything
  • We work out the connection that takes the work off your hands
  • We handle the build, hosting, monitoring and maintenance
  • Your team has less information to retype and fewer discrepancies to chase

Suppliers, products, orders per day, a rough estimate is fine.

Or email directly: carsten@syncmyshop.com