# Odoo API Auth in Practice: XML-RPC vs JSON-RPC

A practical look at Odoo XML-RPC and JSON-RPC authentication, API calls, security, and what developers should use for new integrations.

![](https://cdn.hashnode.com/uploads/covers/685a6d69d4d0ea366852534c/26d1f10c-8cdf-4d60-a1f6-90edc72d7ea8.png align="center")

  
Connecting an external application to Odoo usually starts with one question:

**How should the application authenticate and communicate with Odoo?**

For years, two common answers have been **XML-RPC and JSON-RPC**.

Both can connect external applications with Odoo models, but they differ in payload format, client implementation, and developer experience.

There is also an important change for modern Odoo projects: Odoo 19 deprecates the legacy external XML-RPC and JSON-RPC endpoints in favor of the newer **JSON-2 API**.

So if you're working with **Odoo XMLRPC JSONRPC** integrations today, understanding both the existing authentication flow and the migration direction matters.

* * *

## The Basic Odoo API Flow

A traditional external Odoo integration usually follows this pattern:

```text
External Application
        │
        ▼
 Authentication
        │
        ▼
      User ID
        │
        ▼
 Odoo Object Service
        │
        ▼
     Odoo Model
        │
        ▼
      Records
```

Typical connection information includes:

```text
Odoo URL
Database
Username
Password / API Key
```

Once authenticated, the integration can interact with models such as:

```text
res.partner
sale.order
product.product
account.move
stock.picking
```

The user's normal Odoo access rights and record rules still determine what the integration can access.

For larger integrations involving CRM, eCommerce, payments, logistics, or other enterprise systems, a structured [Odoo integration approach](https://sdlccorp.com/services/odoo-services/odoo-integration-services/) is important because authentication is only one part of reliable data synchronization.

* * *

## XML-RPC Authentication

XML-RPC is one of Odoo's long-standing external API mechanisms.

In Python, the standard library already provides an XML-RPC client.

```python
import xmlrpc.client

url = "https://example.odoo.com"
db = "example"
username = "integration@example.com"
api_key = "YOUR_API_KEY"

common = xmlrpc.client.ServerProxy(
    f"{url}/xmlrpc/2/common"
)

uid = common.authenticate(
    db,
    username,
    api_key,
    {}
)

print(uid)
```

If authentication succeeds, Odoo returns a user ID:

```text
7
```

That `uid` is then used for model operations.

* * *

## Calling an Odoo Model With XML-RPC

Create another proxy:

```python
models = xmlrpc.client.ServerProxy(
    f"{url}/xmlrpc/2/object"
)
```

Now we can query contacts:

```python
partners = models.execute_kw(
    db,
    uid,
    api_key,
    "res.partner",
    "search_read",
    [[["is_company", "=", True]]],
    {
        "fields": ["name", "email"],
        "limit": 5
    }
)

print(partners)
```

Conceptually, the call is:

```text
Application
     │
     ▼
/xmlrpc/2/object
     │
     ▼
execute_kw()
     │
     ▼
res.partner.search_read()
```

The approach is straightforward, particularly for Python scripts and existing integrations.

* * *

## What About API Keys?

For integrations, avoid hardcoding a user's main password whenever possible.

Odoo supports API keys that can replace the password in traditional RPC calls.

So instead of:

```python
password = "user-password"
```

you can use:

```python
api_key = os.environ["ODOO_API_KEY"]
```

and authenticate with that credential.

Keep it outside your source code:

```bash
export ODOO_API_KEY="..."
```

Treat the API key like a password.

Anyone who obtains it may receive the permissions associated with that Odoo user.

* * *

## JSON-RPC Authentication

JSON-RPC uses JSON rather than XML to represent requests and responses.

A typical request structure looks conceptually like this:

```json
{
  "jsonrpc": "2.0",
  "method": "call",
  "params": {
    "...": "..."
  },
  "id": 1
}
```

Because JSON maps naturally to JavaScript objects, JSON-RPC has historically been convenient for web-oriented integrations.

A request can be made using a normal HTTP client:

```python
import requests

payload = {
    "jsonrpc": "2.0",
    "method": "call",
    "params": {
        "service": "common",
        "method": "authenticate",
        "args": [
            db,
            username,
            api_key,
            {}
        ]
    },
    "id": 1
}

response = requests.post(
    f"{url}/jsonrpc",
    json=payload
)

uid = response.json()["result"]
```

The authentication concept remains similar:

```text
Database
   +
Username
   +
Credential
   ↓
Authenticate
   ↓
User ID
```

The major difference is how the RPC request is encoded and transported.

* * *

## XML-RPC vs JSON-RPC

Here's the practical comparison:

| Area | XML-RPC | JSON-RPC |
| --- | --- | --- |
| Encoding | XML | JSON |
| Payload | More verbose | Generally lighter |
| Python support | Excellent | Excellent |
| JavaScript friendliness | Moderate | High |
| Human readability | Lower | Higher |
| Legacy Odoo integrations | Very common | Common |
| Odoo 19 external RPC status | Deprecated | Deprecated |
| Long-term direction | JSON-2 | JSON-2 |

If you're maintaining an older Python integration, XML-RPC can still be perfectly understandable and functional for supported versions.

For a new long-lived integration, however, protocol choice shouldn't be made without considering Odoo's deprecation roadmap.

* * *

## The Important Odoo 19 Change

This is where older Odoo API tutorials can become misleading.

Starting with Odoo 19, the external endpoints:

```text
/xmlrpc
/xmlrpc/2
/jsonrpc
```

are deprecated.

Odoo's replacement is the **External JSON-2 API**.

The newer architecture looks more like:

```text
POST /json/2/<model>/<method>
```

with an API key supplied through the authorization header.

For example:

```python
import requests

response = requests.post(
    f"{url}/json/2/res.partner/search_read",
    headers={
        "Authorization": f"bearer {api_key}"
    },
    json={
        "domain": [
            ["is_company", "=", True]
        ],
        "fields": [
            "name",
            "email"
        ],
        "limit": 5
    }
)

partners = response.json()
```

Notice what's missing:

```text
username
password
uid
execute_kw
```

Authentication becomes API-key based.

The request itself identifies the model and method:

```text
/json/2/res.partner/search_read
        │
        ├── Model  → res.partner
        │
        └── Method → search_read
```

This produces a cleaner HTTP integration model.

* * *

## Authentication: Old RPC vs JSON-2

The difference is easier to see side by side.

### XML-RPC / Legacy JSON-RPC

```text
Database
   +
Username
   +
Password/API Key
       │
       ▼
  authenticate()
       │
       ▼
      UID
       │
       ▼
   execute_kw()
```

### JSON-2

```text
API Key
   │
   ▼
Authorization: bearer <key>
   │
   ▼
/json/2/model/method
   │
   ▼
Odoo
```

For new Odoo 19+ integrations, this newer model deserves serious consideration.

* * *

## Use a Dedicated Integration User

Whichever API style you use, don't automatically connect integrations through an administrator account.

Create a dedicated user such as:

```text
erp-integration-bot
```

and grant only the permissions required by the integration.

For example, an application that synchronizes customers may need:

```text
Contacts → Read
Sales → Read
```

but probably doesn't need:

```text
Settings → Administration
Accounting → Full Access
Users → Manage
```

This follows the principle of least privilege.

If an integration credential is compromised, the account's permissions determine the potential impact.

* * *

## Keep Authentication Configuration Outside Code

Avoid this:

```python
username = "admin@example.com"
api_key = "abcd1234..."
```

Prefer environment variables or a secrets manager:

```python
import os

url = os.environ["ODOO_URL"]
db = os.environ["ODOO_DB"]
username = os.environ["ODOO_USER"]
api_key = os.environ["ODOO_API_KEY"]
```

Your repository then contains integration logic—not production credentials.

For custom modules and workflows that require API hooks or external data exchange, [custom Odoo development](https://sdlccorp.com/services/odoo-services/odoo-development-company/) can also separate integration logic from core ERP functionality and make future upgrades easier to manage.

## Handle Authentication Failures Clearly  
  
Don't assume authentication always succeeds.

For XML-RPC:

```python
uid = common.authenticate(
    db,
    username,
    api_key,
    {}
)

if not uid:
    raise RuntimeError(
        "Odoo authentication failed"
    )
```

For HTTP-based APIs, also check:

```text
HTTP status
Timeouts
Invalid JSON
Expired credentials
Access errors
```

A production integration should distinguish between:

```text
Authentication failure
Authorization failure
Network failure
Odoo server failure
Invalid request
```

They require different fixes.

* * *

## Which Should You Use?

The answer depends largely on the Odoo version and whether you're maintaining or creating the integration.

### Existing XML-RPC integration

If it's stable and running against a supported Odoo version, you don't necessarily need an immediate rewrite.

But plan for migration.

### Existing JSON-RPC integration

The same principle applies.

Keep it operational while preparing for JSON-2.

### New Odoo 19+ integration

Prefer evaluating **JSON-2** first.

Building a brand-new integration around an already deprecated API creates avoidable future migration work.

### Older Odoo environment

XML-RPC may remain the simplest option, especially for Python automation.

Compatibility with your actual Odoo version matters more than following the newest API blindly.

* * *

## A Practical Decision Guide

```text
What are you building?
        │
        ▼
Existing integration?
   │           │
  YES          NO
   │           │
   ▼           ▼
XML/JSON RPC   Odoo 19+?
still works?    │
   │         ┌─┴─┐
  YES       YES  NO
   │         │    │
   ▼         ▼    ▼
Maintain   JSON-2  Check version
+
Plan migration
```

The key is not simply choosing XML or JSON.

It's choosing an API strategy that matches the lifecycle of your Odoo installation.

* * *

## Security Checklist

Before shipping an Odoo API integration:

*   Use HTTPS.
    
*   Prefer API keys over embedding user passwords.
    
*   Store credentials outside source code.
    
*   Use a dedicated integration account.
    
*   Apply minimum required permissions.
    
*   Rotate and revoke credentials when appropriate.
    
*   Handle authentication errors explicitly.
    
*   Log failures without logging secrets.
    
*   Test record rules and access permissions.
    
*   Plan migration away from deprecated APIs.
    

Authentication is only secure when the entire integration respects the same trust boundary.

* * *

## Final Takeaway

The **Odoo XMLRPC JSONRPC** comparison is no longer simply about XML versus JSON.

For existing Odoo integrations:

```text
XML-RPC → Mature and widely used
JSON-RPC → JSON-based alternative
```

But for modern Odoo development:

```text
XML-RPC
     \
      → Deprecated → JSON-2
     /
JSON-RPC
```

If you're maintaining an older integration, understand its authentication flow, protect API credentials, and keep permissions narrow.

If you're starting a new integration on Odoo 19 or later, evaluate JSON-2 before committing to either legacy RPC interface.

That small architecture decision today can save a much larger migration later.
