OdooWebApps.com

How Odoo's API Actually Works (XML-RPC, JSON-RPC and the ORM)

Published September 18, 2026

What protocols does Odoo's API actually use?

Odoo exposes its external API over two RPC protocols: XML-RPC and JSON-RPC. They're not two different feature sets; both are transport-layer options for calling the exact same underlying methods on Odoo's ORM. Which one a given integration uses is mostly a matter of what's convenient in the calling language; most modern client libraries default to JSON-RPC simply because JSON tooling is more universally available than XML-RPC tooling.

How does authentication work?

A client authenticates with a database name, a login, and either a password or an API key generated from that user's own Odoo preferences (the API-key option, available on modern Odoo versions, is the safer choice for integrations since it can be revoked independently of the user's login password). A successful authentication returns a user id, which is then passed alongside the database name on every subsequent call.

What can you actually call once authenticated?

Nearly everything the ORM itself supports, through a single generic dispatch method (commonly called execute_kw) that takes a model name, a method name, and its arguments. Standard CRUD methods are always available: search, search_read, read, create, write, unlink, and so is any other public method defined on that model, including business-logic methods like confirming a sales order or validating a stock transfer, which matters because those methods run the same side effects (state changes, related record updates) that clicking the equivalent button in Odoo's own interface would trigger.

What does a typical call actually look like?

Reading data is usually done with search_read, which takes a domain (a list of filter conditions, like [["state", "=", "sale"]]) and a list of fields to return, combining what would otherwise be a separate search-then-read round trip into one call. Aggregated numbers (totals, counts grouped by a field) generally go through read_group instead of pulling every record back and summing client-side. Writing data is a create or write call with a dictionary of field values, or a call to a specific method when the change needs to trigger Odoo's own business logic rather than just set a field.

Does the API respect Odoo's normal permissions?

Yes, entirely. Every call runs as the authenticated user, subject to that user's model-level access rights and row-level record rules exactly as if they were logged into the Odoo web client. There's no separate, more permissive "API mode," which is also why the right way to scope an integration is a dedicated API user with only the access it needs, not the main admin account.

What are the practical gotchas worth knowing up front?

A few things trip up integrations that weren't built with Odoo's specifics in mind: many2one fields come back as a two-item list ([id, display_name]) rather than a plain id; all datetimes are stored and returned in UTC regardless of the user's timezone, so conversion is the caller's job; and calling search in a loop followed by individual read calls per record ("N+1" calls) is a common, avoidable performance mistake when search_read would do it in one round trip. Field names and available methods can also shift slightly between major Odoo versions, which is worth knowing before assuming an integration will need zero maintenance forever. See the guide on Odoo upgrades linked below.

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.