Skip to main content
iVentureTeam
Developer Guide

Odoo JSON-2 API Migration: Move XML-RPC Integrations to Odoo 20

Odoo JSON-2 API migration guide: XML-RPC deprecation dates, bearer API keys, Python call mapping, error handling and a cut-over checklist for Odoo 19 and 20.

Siddharth JambukiyaSiddharth JambukiyaOdoo Techno-Functional Consultant
October 26, 2026Updated October 25, 202615 min read3 views
Odoo JSON-2 API Migration: Move XML-RPC Integrations to Odoo 20 cover

Most Odoo shops run a script, connector or BI feed written against XML-RPC years ago. Those links now carry a deadline. Our Odoo integration services start by finding every one of them before the clock runs out.

This guide is for developers and technical leads who own Odoo integrations on Odoo 19 or Odoo 20. For the wider picture of connectors, webhooks and MCP, read our Odoo API and third-party integration guide first.

Why is XML-RPC deprecated in Odoo, and when does it stop working?

XML-RPC and JSON-RPC are deprecated because Odoo replaced them with the JSON-2 API in Odoo 19, and the remaining services are scheduled for removal in Odoo 22 and Odoo Online 21.1. The old endpoints still answer today, which is exactly why teams forget them.

Odoo's external JSON-2 API documentation is the source of record. It marks /xmlrpc, /xmlrpc/2 and /jsonrpc as deprecated and dates the removal of each service.

ServiceWhat it didStatus in Odoo 20Removal
commonversion, login, authenticateDeprecated, still worksOdoo 22 (fall 2028), Online 21.1 (winter 2027)
dbcreate, duplicate, dump, restore, dropRemovedOdoo 20 (fall 2026), Online 19.1 (winter 2025)
objectexecute and execute_kw on any modelDeprecated, still worksOdoo 22 (fall 2028), Online 21.1 (winter 2027)

Early Odoo 19 server logs and the first docs said the endpoints would go in Odoo 20. Odoo later moved the date to Odoo 22, so a ticket that says "fix before Odoo 20" has a new deadline but the same work.

Controllers your own modules declare with route type jsonrpc (type json until Odoo 18) are not part of this deprecation. For every other version change, see our Odoo 20 release notes.

How does the Odoo JSON-2 API differ from XML-RPC?

XML-RPC vs JSON-2: What changes in every call?

The JSON-2 API replaces one generic execute_kw entry point with a plain HTTP POST per model and method, authenticated by an API key and fed only with named arguments. Every other difference follows from those three changes.

FieldXML-RPC todayJSON-2 in Odoo 20
EndpointPOST /xmlrpc/2/object, method name inside the payloadPOST /json/2/{model}/{method}, model and method in the URL
Authenticationdatabase, user id and password on every callAuthorization header with bearer and an API key
Database selectionfirst argument of every callX-Odoo-Database header, only when one host serves several databases
Argumentspositional list plus an optional keyword dictionaryone JSON object, every argument named, plus ids and context
Record idsfirst positional argumentthe ids key in the body, empty for model-level methods
Errorsfault inside an HTTP 200 responsereal 4xx or 5xx status with a JSON error object
Version checkcommon.version()GET https://erp.iventureteam.com/web/version
User id lookupcommon.authenticate() returns uidPOST /json/2/res.users/context_get with no ids

There is no way to call a method with positional arguments in JSON-2, so every call site is rewritten with argument names. The response is the plain JSON return value of the method, with no result envelope around it.

Which Odoo plans and editions include the JSON-2 API?

JSON-2 ships in Odoo itself, so Community, Odoo.sh and on-premise Enterprise all have it, but on Odoo Online the external API is enabled only on the Custom plan. The same rule applied to the old RPC endpoints, so the migration adds no new license cost.

The docs note that external API access is not available on the One App Free or Standard plans of Odoo Online. On the Odoo pricing page, US Custom is US$61.00 per user a month billed yearly against US$31.10 for Standard; India Custom is Rs 1,350 against Rs 725.

Community users sometimes assume JSON-2 is a paid feature. When a Community user asked on the Odoo forum, the accepted answer was that the JSON-2 API is not a commercial feature and is already available in Odoo 19 Community.

How do you authenticate with an Odoo JSON-2 API key?

You create an API key for a user under Preferences, Account Security, New API Key, then send it on every request as a bearer token in the Authorization header. The key replaces both the password and the user id that XML-RPC needed.

RuleWhat Odoo enforcesWhat it means for your integration
Key creationdescription and duration are mandatoryname one key per service so you can revoke it alone
Maximum lifeno key lasts more than three monthsrotate keys at least quarterly
Visibilitythe 160-bit key is shown once, never againstore it in a secrets manager at creation
Access rightsthe key's user rights, record rules and field access applygive the bot user minimum permissions
Programmatic keysgenerate and revoke methods on res.users.apikeys, default limit 10 per userautomate rotation; needs Settings rights or the base.enable_programmatic_api_keys parameter
Over the limitHTTP 422 Unprocessable Contentrevoke unused keys first

Odoo recommends a dedicated bot user for automated use: an empty password blocks interactive login, permissions can be trimmed, and audit fields show the bot rather than a person. When rotating, authenticate with the new key to revoke the old one; the two keys do not have to match.

The pain point developers raise most is cost, since each bot user is a full internal user and a paid seat on Enterprise. A forum thread confirmed there are no native scoped API keys without additional billable users, so most teams run one bot user with one named key per integration.

How do you convert an XML-RPC call to JSON-2 in Python?

Replace the xmlrpc.client ServerProxy with a requests session, move the model and method into the URL, and turn every positional argument into a named key in the JSON body. The steps below map the JSON-2 replacement for each execute_kw pattern.

StepRequest detailNotes
1. HeadersAuthorization set to bearer plus the key; Content-Type application/json; X-Odoo-Database set to the database name; User-Agent set to your software namebuild once on a requests.Session
2. Version checkGET https://mycompany.example.com/web/versionreplaces common.version()
3. Who am IPOST /json/2/res.users/context_get with an empty bodyreplaces authenticate(); the user comes from the key
4. Search and readPOST /json/2/res.partner/search_read with body keys domain, fields, limit and contextreturns a JSON array of records
5. CreatePOST /json/2/res.partner/create with body key vals_list holding a list of objectsreturns the new ids
6. UpdatePOST /json/2/res.partner/write with body keys ids and valsreturns true
7. Business actionPOST /json/2/sale.order/action_confirm with body key idsone transaction, one method
8. DeletePOST /json/2/res.partner/unlink with body key idssame access rules as the user

In Python each step is one call to requests.post with the URL, the headers dictionary and the body as the json parameter. Call raise_for_status, then read response.json() for the return value. No login call and no uid variable remain.

One2many and many2many fields still use Odoo command lists. A developer creating a sales order with lines through JSON-2 hit an "unhashable type: dict" error until they found that each order line needs the two zeros, as in 0, 0 and then the values object.

Every database lists its own models, fields and methods on its /doc page; check argument names there before rewriting a call.

How should you handle JSON-2 API errors, retries and transactions?

Treat every non-2xx status as a structured error, retry only idempotent calls on 5xx and network failures, and never split one business step across several JSON-2 calls. XML-RPC code often ignored all three rules because faults came back inside a 200 response.

HTTP statusError object nameUsual causeRight response
401werkzeug.exceptions.Unauthorizedexpired, revoked or mistyped keyrotate the key, alert, do not retry
403AccessError, or a failed revokebot user lacks rights, or the key to revoke is invalidfix access rights, do not retry
4xxodoo.exceptions.ValidationError or UserErrorbad data, missing field, wrong argument namefix the payload, log the message field
5xxserver or database erroroverload, lock, deployment in progressback off and retry idempotent calls

The error body has five keys: name, message, arguments, context and debug. Log name and message, keep debug out of production, and map name to your own exception types.

Every JSON-2 call runs in its own SQL transaction that commits on success and rolls back on error, and calls cannot be chained. A search followed by a separate read can fail if another user deletes a record in between.

Odoo's advice is to call one method that does the whole job: search_read instead of search then read, or action_confirm on sale.order instead of writing state fields. If no such method exists, add a small module with one method. Our Odoo development company team builds these wrappers often.

How do you find every integration still using XML-RPC?

Search the server logs for requests to /xmlrpc, /xmlrpc/2 and /jsonrpc, then match each caller to a system owner before you write any code. The hidden ones are usually not in your code repository at all.

  1. Server and proxy logs: filter for the three deprecated paths and group by source IP and user agent for at least two weeks, so monthly jobs show up.
  2. API keys per user: list every key and its description under Account Security; an old key with no owner is a forgotten integration.
  3. Automation platforms: check n8n, Zapier, Make and similar tools; the n8n Odoo node still used XML-RPC at the time of writing.
  4. Connectors and BI: eCommerce connectors, Power BI gateways, shipping and payment plugins and warehouse scanners often ship with an XML-RPC client inside.
  5. Spreadsheets and scripts: finance teams keep Python or VBA scripts that pull invoices through execute_kw; ask them directly.
  6. Odoo Online version: record the release your database runs, because the Online removal in 21.1 arrives before the Odoo 22 self-hosted date.

Record the result as an inventory with system, owner, direction, models, call volume and deprecated service. That inventory is the migration scope and the cut-over test plan.

What does a safe XML-RPC to JSON-2 cut-over checklist look like?

Port one integration at a time, test it against a neutralized copy of production, run old and new side by side, then revoke the old credentials only after a full business cycle. Skipping the parallel run is the most common cause of silent data loss.

  1. Create the bot user with minimum access rights and an empty password, and document which models and methods it may touch.
  2. Generate one named key per integration with a 90-day expiry, store it in your secrets manager and schedule the rotation job.
  3. Rewrite the client to the JSON-2 shape: URL per method, bearer header, named arguments, ids and context, and real HTTP status handling.
  4. Test on a staging copy of production; Odoo neutralizes test databases, so mails and scheduled actions will not fire by accident.
  5. Compare outputs by running the XML-RPC and JSON-2 clients against the same records and diffing the JSON field by field.
  6. Run both in parallel through at least one month-end, with the JSON-2 client writing to a log instead of to Odoo if it creates records.
  7. Switch the writer to JSON-2, keeping the XML-RPC client disabled but deployable for one more cycle as the rollback path.
  8. Reconcile order counts, invoice totals and stock moves for the first week, then revoke the old password and keys and confirm the logs are clean.

The reconciliation step borrows from upgrade practice, where problems hide until the month closes; our guide on Odoo upgrade verification lists those checks. If the integration feeds a webstore, read our post on Odoo 20 upgrade and eCommerce integrations.

How much does an Odoo JSON-2 API migration cost and how long does it take?

A single one-way script usually takes a few developer days to port and test, while a two-way connector across several models takes weeks, and the inventory step decides which one you have. The figures below are illustrative estimates from our own projects, not quotes.

  • Read-only report or BI feed: search_read on one to three models, about 1 to 3 developer days; the main risk is field name drift between versions.
  • One-way order import: create and write on sale.order and res.partner, about 3 to 8 developer days; watch command lists for order lines and duplicate detection.
  • Two-way connector: five or more models synced on a schedule, about 2 to 5 developer weeks; the risks are transaction boundaries, idempotency and reconciliation.

Effort rises with positional calls scattered across many files, logic split over several RPC calls that now needs one server-side method, and no test environment. Pairing the migration with an Odoo upgrade shares the staging work.

For a quick first number, run the Odoo project estimate tool with your integration count. To add capacity instead of outsourcing, see how to hire an Odoo developer from our team.

Which industries feel the XML-RPC deprecation first?

Businesses whose revenue flows through an integration feel it first, because a broken order import or stock sync shows up as lost sales the same day. This is where we most often find XML-RPC in production.

IndustryPain or cost driverOdoo approachHow iVentureTeam helps
eCommerce and marketplacesorder and stock sync scripts written for Odoo 12 to 16JSON-2 connector with idempotent writes and action methodsinventory, port, parallel run, reconciliation
Logistics and 3PLWMS and carrier plugins calling execute_kw thousands of times a daybatch search_read and single-method writesperformance testing before cut-over
Manufacturingshop-floor and MES systems posting work ordersbot users per plant with scoped access rightscustom server methods for multi-step operations
Finance and BIPower BI, spreadsheets and bank feeds on XML-RPCread-only bot user, quarterly key rotationre-point reports, verify totals at month-end

How iVentureTeam helps with Odoo JSON-2 API migration

Porting integrations? Size the work first

iVentureTeam audits, ports and cuts over Odoo integrations from XML-RPC to JSON-2 with tests, key rotation and a rollback path. We have delivered 150+ ERP projects across 35+ countries with 40+ Odoo specialists over 13+ years.

  • Integration inventory: log analysis and key review to list every caller still on /xmlrpc or /jsonrpc, with owners and deadlines.
  • Porting and testing: JSON-2 clients in Python or your stack, with diff tests against the old client and month-end reconciliation.
  • Security setup: bot users, named keys per integration, automated rotation and least-privilege access rights.
  • Upgrade pairing: our Odoo upgrade services run the API migration inside the same staging and test cycle as a version upgrade.
  • AI and MCP: when assistants need to act on Odoo data, our Odoo 20 MCP server guide shows how JSON-2 keys and access rights carry over.

Odoo API integration case study: a Lightspeed to Odoo connector

A North American online retailer kept its Lightspeed eCommerce storefront and gained an Odoo back office, with a scheduled connector syncing both ways. Before the project, every product, order and customer existed twice and web stock drifted from the warehouse.

iVentureTeam built a bidirectional connector configured entirely from the Odoo back end, with credential setup and mapping inside Odoo and no external middleware. It imports nine record types from Lightspeed, including products, categories, brands, taxes, customers, suppliers and orders with status.

Three data streams flow back: product prices, live inventory positions, and order and shipment status. Delivered in 6 weeks, the connector left zero manual re-entry steps between the systems. Read the full Lightspeed and Odoo bidirectional integration case study.

The bottom line on Odoo JSON-2 API migration

Move every XML-RPC and JSON-RPC integration to JSON-2 now, while the old endpoints still work and you can run both side by side. Odoo Online loses the old services in 21.1 and self-hosted systems in Odoo 22, and waiting turns a planned port into an emergency.

Start with the inventory, give each integration its own key, rewrite calls with named arguments and real error handling, and reconcile through one month-end before revoking old credentials. The code change is modest; the discipline around it protects your ledger.

Ready to move your Odoo integrations off XML-RPC?

Request a free API audit

Get a list of every integration still on the deprecated endpoints and a plan to port them. Request an Odoo integration audit, call +91-90235-15208, or email business@iventureteam.com.

Frequently Asked Questions

Is XML-RPC removed in Odoo 20?

+

Not fully. Only the db service of the old RPC APIs is gone in Odoo 20. The common and object services, which carry execute_kw, are deprecated but still work, with removal scheduled for Odoo 22 and Odoo Online 21.1.

What is the Odoo JSON-2 API?

+

It is Odoo's external API introduced in Odoo 19. You POST a JSON body to /json/2/{model}/{method} with a bearer API key, and Odoo returns the method's result as JSON. It exposes the same ORM methods as XML-RPC, with named arguments and real HTTP status codes.

How long is an Odoo API key valid?

+

An API key needs a description and a duration when created, and Odoo does not allow keys that last more than three months. Long-running integrations must rotate keys at least quarterly, using the generate and revoke methods on res.users.apikeys.

Do I need the Custom plan to use the Odoo API?

+

On Odoo Online, yes. The external API is not available on the One App Free or Standard plans. Odoo Community, Odoo.sh and on-premise Enterprise include the JSON-2 API without a plan restriction.

Can I still use positional arguments with JSON-2?

+

No. Every argument in a JSON-2 request is named inside the JSON body, along with the ids and context keys. Calls written for execute_kw with positional lists must be rewritten with the method's argument names.

How do I get the user id with JSON-2 if there is no authenticate call?

+

Send a POST to /json/2/res.users/context_get with no ids. Odoo identifies the user from the API key and returns the context, including the user id, so the XML-RPC login step disappears.

Will my n8n, Zapier or Make workflows break?

+

They keep working while the deprecated endpoints exist, but they depend on the vendor shipping a JSON-2 connector. Check your Odoo logs for calls to /xmlrpc or /jsonrpc from those platforms and track their release notes.

Ready to put this into action?

Talk to iVentureTeam about Odoo, AI automation, or custom development — get a free, no-obligation consultation.