KodDeltaGuides

Odoo integration: which API, which plan, and what changes before 2028

~11 min read

Odoo exposes its models through an external API, historically over XML-RPC and JSON-RPC, where every call carries the database name, user id and password because the interface is stateless. Two facts decide the project before any code is written: on Odoo Online the external API is only available on Custom plans, and the legacy RPC endpoints are scheduled for removal — Online 21.1 in winter 2027, Odoo 22 in autumn 2028. New work should target the API-key-based JSON-2 interface introduced in Odoo 19.

Most Odoo integration guides open with a code sample. That is the wrong place to start, because two non-technical facts decide whether the code will ever run — and both are usually discovered after the estimate has been given.

  1. On Odoo Online, the external API is not available on every pricing plan.
  2. The RPC endpoints everyone writes against have a published removal date.

Get those two right and the rest of the work is ordinary.

1. The plan requirement

On Odoo Online, access to data through the external API is available only on Custom pricing plans. It is not available on One App Free or on Standard.

This is worth confirming in the first conversation, because the remedies are commercial rather than technical: move the subscription to a plan that includes API access, or run a self-hosted deployment where the question does not arise. Neither is a decision a developer can make, and both change the budget.

A related surprise arrives immediately afterwards. On Odoo Online, users are created without a local password — sign-in goes through the Odoo Online authentication system rather than the instance itself. The account works perfectly in a browser and fails on the first API call until a password is set explicitly on the user the integration will run as.

2. How the legacy RPC interface works

Odoo has historically exposed its models over XML-RPC and JSON-RPC. Both reach the same place: the public methods of Odoo's models, including the generic ORM methods.

The important property is that the interface is stateless. There is no session to hold open, so the database name, the user id and the password travel with every single call.

StepCallWhat you get back
1authenticate with database, login, passwordA numeric user id
2execute_kw with database, uid, password, model, methodThe method's result

execute_kw is the workhorse: it takes the model name, the method to run, a list of positional arguments and an optional dictionary of keyword arguments. Because it reaches the ORM directly, a record created through it runs the same constraints, computed fields and accounting logic as one keyed in by a person.

3. The deprecation, and what it means for scoping

The endpoints at /xmlrpc, /xmlrpc/2 and /jsonrpc are scheduled for removal:

DeploymentRemoval inExpected
Odoo OnlineOnline 21.1Winter 2027
Self-hostedOdoo 22Autumn 2028

Online customers lose them roughly a year before self-hosted ones. Anything written against those endpoints today therefore has a known end date, and that belongs in the project's stated assumptions rather than in a surprise a year later.

It is not a reason to postpone the work. It is a reason to isolate the transport.

4. What to build on instead

Odoo 19 introduces the External JSON-2 API. The substantive difference is authentication: instead of resending a user password on every call, the interface uses API keys. Keys can be created manually or managed programmatically, and rotation and revocation are part of the documented lifecycle — which matters, because a leaked user password on the old interface is a full user credential, while a key can be revoked on its own.

Odoo publishes a migration path from the RPC services, mapping the common, database and object service operations onto the new interface. The important consequence for planning is that the migration is a transport change, not a data-model change: the same models, the same methods, the same fields. That is what makes the following pattern cheap.

Isolate the transport in one layer

Whatever your target instance runs today, put a single adapter between your application and Odoo:

Your application

Calls your own interface — createOrder, getStock — and knows nothing about Odoo's transport.

Adapter

The only place that speaks XML-RPC today and JSON-2 tomorrow. Switching transports touches this module and nothing else.

Queue

Holds writes while the instance restarts for an upgrade, then replays them in order with your document reference for de-duplication.

Without the adapter, the transport is smeared across every call site and the 2027 deadline becomes a rewrite. With it, the deadline is an afternoon.

5. Do not write to the database directly

Odoo stores its data in PostgreSQL, and the temptation to skip the API is strong — especially for bulk loads.

It does not work, for the same reason it does not work in any other ERP: the business logic lives in the model layer, not in the database. Computed fields, constraints, workflow transitions and journal entries are all produced by the ORM. A direct INSERT leaves a row the application can display but has never processed — stock is not moved, no accounting entry exists, and the inconsistency is usually found during a reconciliation weeks later.

Reading is a different matter. Reporting queries straight against the database are common and sensible, particularly for dashboards that would otherwise generate a large number of API calls.

6. Surviving upgrades

Odoo Online applies upgrades on its own schedule, and self-hosted instances restart when yours are applied. During those windows the API is unavailable.

The pattern is the same one every ERP integration needs: a queue between your application and the instance, with an idempotency reference on every write. Your application generates its own document number, sends it with the record, and a replayed request carrying the same number updates the existing record instead of creating a second one. Retries are then safe by construction, and an upgrade window costs nothing but a delay.

Checklist before estimating

  1. Which plan? If it is Odoo Online on One App Free or Standard, the API is not available and the conversation is commercial before it is technical.
  2. Which version? This decides whether JSON-2 is available now or whether you start on RPC behind an adapter.
  3. Does the integration user have a password set? On Odoo Online, by default it does not.
  4. Online or self-hosted? It changes the deprecation date by roughly a year and it changes who controls upgrade timing.
  5. Read volume? High-frequency reads belong in a cache or a reporting query, not in per-view API calls.

Answering those five before writing code removes almost every unpleasant surprise from an Odoo project.

If the integration is a distributor-facing one, the ordering-side rules — reading price from the ERP, showing free stock rather than physical, checking credit limits before the write — are covered in B2B dealer portal ERP integration. To scope work on the Odoo instance you already run, tell us about your process; the first call takes 30 minutes and costs nothing, and the bands are on the pricing page.

Frequently asked questions

What is the Odoo external API?

It is the interface that lets an outside application read and write Odoo records through the same model methods the user interface uses, including the generic ORM methods. Historically it is offered over XML-RPC and JSON-RPC. Because a record is created through Odoo's own model layer rather than by writing to tables, the validation, computed fields and accounting logic all run exactly as they would if a person had keyed the record in.

How does authentication work in the Odoo external API?

The legacy RPC interface is stateless: there is no session to hold. You first call the authenticate method with the database name, login and password to obtain a numeric user id, and then every subsequent call to the object service carries the database name, that user id and the password again. The main entry point is execute_kw, which takes the model name, the method name, a list of positional arguments and an optional dictionary of keyword arguments.

Why does my Odoo Online user have no password for the API?

On Odoo Online, users are created without a local password because sign-in is handled by the Odoo Online authentication system rather than by the instance itself. To use the RPC API you have to set a password explicitly on the user account the integration will run as. This surprises most teams on day one, because the account works perfectly in the browser and fails immediately over the API.

Is the Odoo external API available on every plan?

No, and this is the fact that most often stops a project before it starts. On Odoo Online, access to data through the external API is only available on Custom pricing plans. It is not available on the One App Free or Standard plans. Confirm the plan before scoping the work, because the alternative is either a plan upgrade or a self-hosted deployment, and both are commercial decisions rather than technical ones.

Are XML-RPC and JSON-RPC being removed from Odoo?

Yes. The endpoints at /xmlrpc, /xmlrpc/2 and /jsonrpc are scheduled for removal in Odoo 22, expected autumn 2028, and in Odoo Online 21.1, expected winter 2027. Online customers therefore lose them roughly a year before self-hosted ones. Anything built on those endpoints today has a known end date, which should be written into the project's assumptions rather than discovered later.

What replaces XML-RPC and JSON-RPC?

The External JSON-2 API, introduced in Odoo 19. It authenticates with API keys rather than by resending a user password on every call, and the keys can be created manually or managed programmatically, with rotation and revocation as part of the documented lifecycle. Odoo publishes a migration path from the RPC services, mapping the common, database and object service operations onto the new interface.

Should a new Odoo integration still use XML-RPC?

Only when the target instance is on a version that predates the JSON-2 interface, and then behind an adapter. Keep the transport in one replaceable layer: the rest of your application should call your own interface, not Odoo's, so that switching to JSON-2 later touches a single module rather than every call site. The migration is a transport change, not a data-model change, because both interfaces address the same models and methods.

Should I write to Odoo tables directly through PostgreSQL?

No. Odoo's business logic lives in the model layer, not in the database: computed fields, constraints, workflow transitions and accounting entries are all produced there. A direct SQL insert creates a row that the application can see but never processed, so stock is not moved, no journal entry is written, and the inconsistency surfaces weeks later during a reconciliation. Read-only reporting queries against the database are a different matter and are common practice.

How should an integration handle Odoo being unavailable?

Put a queue between your application and Odoo. Instances restart for upgrades, and Odoo Online applies them on its own schedule. Requests should accumulate while the instance is unreachable and be replayed in order afterwards, each carrying your own document reference so a replayed request updates the existing record instead of creating a second one. Without this, the records created during an upgrade window are simply lost.

Let's talk about what you need.

The 30-minute discovery call is free and carries no commitment.