Skip to content
OdooWebApps.com

Odoo REST API: what exists in Odoo 19, and what came before

By Tal Oz, OdooWebApps. Published 18 September 2026, updated 22 September 2026.

Does Odoo actually have a REST API?

Since Odoo 19, yes: a plain HTTP JSON API that Odoo calls JSON-2. You POST a JSON body to /json/2/<model>/<method> with an Authorization: bearer <api key> header and get the method's return value back as JSON, with normal HTTP status codes for errors. Before Odoo 19 the answer was no: the external API was only exposed over two RPC protocols, XML-RPC and JSON-RPC, which call the same ORM methods through a single generic execute_kw dispatcher. Those RPC endpoints still work on Odoo 19 but are officially deprecated, with removal scheduled for Odoo 22 in fall 2028.

Two things people miss when they read "REST": JSON-2 is still organised around model methods, not resource URLs (there is no GET /api/sale.order/42; you call /json/2/sale.order/read with an id list), and on Odoo Online the external API, JSON-2 included, is only available on the Custom plan, not on One App Free or Standard. Self-hosted and Odoo.sh databases are not limited that way.

What does a JSON-2 call look like?

One request per method call. The URL names the model and method, the body carries the arguments as named JSON fields, and ids carries the records to act on (empty or omitted for model-level methods such as search_read). Odoo's own example searches partners:

POST /json/2/res.partner/search_read
Host: mycompany.example.com
Authorization: bearer <api key>
Content-Type: application/json

{
  "domain": [["is_company", "=", true], ["name", "ilike", "%deco%"]],
  "fields": ["name"]
}

HTTP/1.1 200 OK
[{ "id": 25, "name": "Deco Addict" }]

The API key comes from the user's Preferences under Account Security. Odoo 19 caps every key at three months, so a production integration needs a rotation routine; keys can also be generated and revoked programmatically through res.users.apikeys/generate once the base.enable_programmatic_api_keys parameter is on. Each JSON-2 call runs in its own database transaction, so a multi-step operation (create an order, then confirm it) is two transactions; when that matters, call one method that does the whole job, such as sale.order/action_confirm.

What did Odoo expose before JSON-2?

A single generic dispatch method, execute_kw, reached over XML-RPC at /xmlrpc/2/object or over JSON-RPC at /jsonrpc. It takes a database name, user id, password or API key, model name, method name and arguments, and runs the method against Odoo's ORM as that user. Standard CRUD (search, search_read, create, write, unlink) and business actions like confirming a sales order are all reached the same way. Odoo 16, 17 and 18 only have this interface, which is why every integration library and most tutorials still speak RPC. See the guide on how Odoo's API actually works, linked below, for authentication and the calling mechanics.

Which one should a new integration use?

On Odoo 19 or later, JSON-2: it is the supported path, the request shape is simpler, and the RPC endpoints have an end date. On Odoo 16 to 18, JSON-RPC (it is the same JSON transport most HTTP clients already handle, and easier to debug than XML-RPC). If an integration has to span versions, keep the model and method names in one place and swap only the transport layer; the ORM methods you call are identical on both.

Does any of this stop you from integrating with Odoo?

No. Every language with an HTTP library can call JSON-2, and every language with an XML-RPC or HTTP library can call the older RPC endpoints. The practical effect of Odoo's design is that calling code thinks in model names and method calls (sale.order/search_read) rather than REST-style resource URLs and verbs: a different shape of code, not a harder problem.

When does a thin REST layer in front of Odoo make sense?

It's a genuinely common and reasonable pattern: build a small server that exposes a handful of resource-style REST (or GraphQL) endpoints your own frontend or a third-party system can call, and have that server translate each request into the equivalent Odoo JSON-2 or RPC calls behind the scenes. This makes sense when the consuming client expects conventional REST (a mobile app framework, a no-code tool, a partner system you don't control), when you want to expose only a narrow, deliberately scoped slice of Odoo's data instead of the full ORM surface to that client, or when you want a layer that can cache, rate-limit, or reshape Odoo's data before it reaches the outside world.

When is it not worth building that layer?

If the thing calling Odoo is a web app or backend you're building yourself, there's usually no reason to invent a REST layer in between: calling Odoo's API directly from that app's own backend is simpler and has one fewer moving part to maintain. The extra REST layer earns its cost specifically when something outside your control needs a conventional REST contract, not as a default architectural step for every Odoo integration.

Want this looked at for your setup?

Every Odoo instance is configured a little differently. Tell us what you're working with and we'll give you a straight answer.