Intégration de l'API Odoo : Guide REST, JSON-RPC et XML-RPC
Odoo 19 expose trois interfaces API qui couvrent tout, de la simple récupération de données à l'automatisation de flux de travail complexes. Que vous créiez une application mobile personnalisée, que vous la synchronisiez avec une plate-forme tierce ou que vous étendiez les capacités d'Odoo avec des microservices externes, la maîtrise de la couche API Odoo est fondamentale pour tout projet d'intégration sérieux.
Ce guide fournit des exemples de code de travail, des flux d'authentification et des recommandations architecturales pour les intégrations REST, JSON-RPC et XML-RPC — les trois interfaces principales disponibles dans Odoo 19 Enterprise.
Points clés à retenir
- Odoo 19 propose les interfaces REST (OpenAPI 3.0), JSON-RPC 2.0 et XML-RPC
- L'authentification utilise des clés API (recommandées) ou une connexion basée sur la session
- JSON-RPC est l'interface la plus complète en fonctionnalités pour les opérations complexes
- L'API REST suit les spécifications OpenAPI 3.0 et prend en charge les verbes HTTP standard
- XML-RPC est hérité mais toujours entièrement pris en charge pour une compatibilité ascendante
- La limitation du débit et la gestion des erreurs doivent être implémentées côté client
- Les Webhooks dans Odoo 19 transmettent des données à des systèmes externes sur les modifications enregistrées
- Tous les appels API respectent les droits d'accès et les règles d'enregistrement d'Odoo
Comparaison des interfaces API
Avant d'écrire une seule ligne de code, choisissez l'interface API adaptée à votre cas d'utilisation :
| Fonctionnalité | API REST | JSON-RPC | XML-RPC |
|---|---|---|---|
| Protocole | HTTP/HTTPS | HTTP/HTTPS | HTTP/HTTPS |
| Format de charge utile | JSON | JSON | XML |
| Spécification OpenAPI | Oui (Swagger) | Non | Non |
| Opérations CRUD | Oui | Oui | Oui |
| Appels de méthode | Limité | Complet | Complet |
| Déclencheurs de flux de travail | Via des actions | Via exécuter_kw | Via exécuter |
| Recommandé pour | Nouvelles intégrations | Logique complexe | Systèmes hérités |
| Bibliothèque Python | demandes | odoo-xmlrpc / requêtes | xmlrpc.client |
Quand utiliser REST : créer une application mobile, intégrer des plateformes webhook natives (Shopify, Stripe) ou lorsque votre équipe est plus à l'aise avec les conventions REST.
Quand utiliser JSON-RPC : exécution de méthodes complexes côté serveur Odoo, lecture de grands ensembles de données avec des filtres de domaine ou lorsque vous avez besoin d'accéder à des méthodes non exposées via REST.
Quand utiliser XML-RPC : maintenir les intégrations existantes créées avant que REST ne soit disponible, ou lorsque votre plate-forme dispose de bibliothèques client XML-RPC matures.
Authentification
Authentification par clé API (recommandé)
Odoo 19 prend en charge l'authentification par clé API pour les trois interfaces. Générez une clé API sous Paramètres → Utilisateurs → Votre utilisateur → Clés API.
import requests
ODOO_URL = "https://your-odoo.com"
API_KEY = "your_api_key_here"
DATABASE = "your_database"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {API_KEY}"
}
Les clés API sont limitées à un utilisateur spécifique et héritent des droits d'accès de cet utilisateur. Créez des utilisateurs de service dédiés avec les autorisations requises minimales pour les comptes d'intégration.
Authentification basée sur la session (JSON-RPC / XML-RPC)
Pour JSON-RPC, authentifiez-vous à l'aide du point de terminaison /web/dataset/call_kw après avoir établi une session :
import requests
import json
session = requests.Session()
# Authenticate
auth_payload = {
"jsonrpc": "2.0",
"method": "call",
"params": {
"db": "your_database",
"login": "admin",
"password": "your_password"
}
}
response = session.post(
f"{ODOO_URL}/web/session/authenticate",
json=auth_payload
)
uid = response.json()['result']['uid']
print(f"Authenticated as UID: {uid}")
Pour XML-RPC, utilisez l'authentification standard en deux étapes :
import xmlrpc.client
url = "https://your-odoo.com"
db = "your_database"
username = "admin"
password = "your_password"
# Step 1: Get UID
common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common")
uid = common.authenticate(db, username, password, {})
# Step 2: Use UID for subsequent calls
models = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/object")
API REST : OpenAPI 3.0
Odoo 19 introduit une API REST complète avec la spécification OpenAPI 3.0. Accédez à la documentation interactive sur https://your-odoo.com/api/docs.
Liste des enregistrements
# GET /api/sale.order — list all sales orders
response = requests.get(
f"{ODOO_URL}/api/sale.order",
headers=headers,
params={
"domain": '[["state", "=", "sale"]]',
"fields": '["name", "partner_id", "amount_total", "state"]',
"limit": 50,
"offset": 0
}
)
orders = response.json()
Lecture d'un seul enregistrement
# GET /api/sale.order/{id}
order_id = 123
response = requests.get(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers
)
order = response.json()
Création d'un enregistrement
# POST /api/sale.order
payload = {
"partner_id": 42,
"order_line": [
{
"product_id": 7,
"product_uom_qty": 5,
"price_unit": 100.0
}
]
}
response = requests.post(
f"{ODOO_URL}/api/sale.order",
headers=headers,
json=payload
)
new_order = response.json()
Mettre à jour un enregistrement
# PATCH /api/sale.order/{id}
response = requests.patch(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers,
json={"note": "Rush order — priority handling required"}
)
Supprimer un enregistrement
# DELETE /api/sale.order/{id}
response = requests.delete(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers
)
Interface JSON-RPC
JSON-RPC donne accès à l'API Python Odoo complète, y compris aux méthodes côté serveur qui ne sont pas exposées via REST. Le critère d'évaluation principal est /web/dataset/call_kw.
Recherche et lecture de base
def call_kw(model, method, args, kwargs=None):
payload = {
"jsonrpc": "2.0",
"method": "call",
"params": {
"model": model,
"method": method,
"args": args,
"kwargs": kwargs or {}
}
}
response = session.post(
f"{ODOO_URL}/web/dataset/call_kw",
json=payload
)
return response.json().get('result')
# Search for confirmed sales orders
order_ids = call_kw(
"sale.order",
"search",
[[["state", "=", "sale"]]],
{"limit": 100, "order": "date_order desc"}
)
# Read specific fields
orders = call_kw(
"sale.order",
"read",
[order_ids],
{"fields": ["name", "partner_id", "amount_total", "date_order"]}
)
Recherche Lecture (combinée)
orders = call_kw(
"sale.order",
"search_read",
[[["partner_id.country_id.code", "=", "US"]]],
{
"fields": ["name", "partner_id", "amount_total"],
"limit": 50,
"offset": 0,
"order": "amount_total desc"
}
)
Création d'enregistrements
new_id = call_kw(
"sale.order",
"create",
[{
"partner_id": 42,
"order_line": [
(0, 0, {
"product_id": 7,
"product_uom_qty": 10,
"price_unit": 150.0
})
]
}]
)
Appel de méthodes côté serveur
JSON-RPC donne accès à toutes les méthodes Python définies sur les modèles Odoo :
# Confirm a sales order (triggers workflow)
call_kw("sale.order", "action_confirm", [[order_id]])
# Validate an inventory transfer
call_kw("stock.picking", "button_validate", [[picking_id]])
# Get the action for a button (useful for understanding what a button does)
action = call_kw("sale.order", "action_quotations_with_onboarding", [[]])
Interface XML-RPC
XML-RPC est l'API Odoo d'origine et reste entièrement prise en charge. L'interface se compose de deux points de terminaison :
/xmlrpc/2/common— méthodes non authentifiées (authentifier, version)/xmlrpc/2/object— toutes les opérations du modèle (nécessite UID)
import xmlrpc.client
url = "https://your-odoo.com"
db, username, password = "mydb", "admin", "mypassword"
common = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/common")
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy(f"{url}/xmlrpc/2/object")
# Search for products
product_ids = models.execute_kw(
db, uid, password,
'product.template', 'search',
[[['sale_ok', '=', True]]],
{'limit': 100}
)
# Read product data
products = models.execute_kw(
db, uid, password,
'product.template', 'read',
[product_ids],
{'fields': ['name', 'list_price', 'categ_id']}
)
# Create a new product
new_product_id = models.execute_kw(
db, uid, password,
'product.template', 'create',
[{
'name': 'My New Product',
'list_price': 99.99,
'type': 'consu'
}]
)
Filtres de domaine
La syntaxe de filtre de domaine d'Odoo est utilisée dans les trois types d'API. Comprendre les domaines est essentiel pour une récupération efficace des données.
# Basic operators: =, !=, >, <, >=, <=, like, ilike, in, not in, child_of
domain = [
["state", "in", ["sale", "done"]], # Confirmed or done orders
["amount_total", ">=", 1000], # Total at least 1000
["partner_id.country_id.code", "=", "US"] # US customers (related field)
]
# Logical operators: & (AND, default), | (OR), ! (NOT)
domain = [
"|",
["state", "=", "draft"],
["state", "=", "cancel"]
]
# Complex: orders from US or UK customers with total > 5000
domain = [
"|",
["partner_id.country_id.code", "=", "US"],
["partner_id.country_id.code", "=", "GB"],
["amount_total", ">", 5000]
]
Webhooks et intégration basée sur les événements
Odoo 19 prend en charge les webhooks sortants déclenchés par les modifications d'enregistrement. Configurez les webhooks sous Paramètres → Technique → Webhooks.
Configuration du webhook :
- Accédez à Paramètres → Technique → Webhooks → Créer
- Définissez le Modèle (par exemple,
sale.order) - Sélectionnez Déclencheur : créer, écrire, dissocier ou méthode personnalisée.
- Saisissez l'URL du point de terminaison de votre service de réception.
- Vous pouvez éventuellement définir Domaine pour filtrer les enregistrements qui déclenchent le webhook.
- Configurez les Champs à inclure dans la charge utile
Réception d'événements webhook dans un service Flask :
from flask import Flask, request, jsonify
import hmac, hashlib
app = Flask(__name__)
WEBHOOK_SECRET = "your_webhook_secret"
@app.route("/odoo-webhook", methods=["POST"])
def handle_webhook():
# Verify signature
signature = request.headers.get("X-Odoo-Signature")
body = request.get_data()
expected = hmac.new(
WEBHOOK_SECRET.encode(),
body,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
return jsonify({"error": "Invalid signature"}), 401
event = request.json
model = event.get("model")
record_id = event.get("id")
# Process the event
if model == "sale.order":
handle_order_event(record_id, event)
return jsonify({"status": "ok"}), 200
Gestion des erreurs et logique de nouvelle tentative
Les intégrations robustes doivent gérer les erreurs de l'API Odoo avec élégance.
import time
import requests
from requests.exceptions import RequestException
def api_call_with_retry(url, payload, headers, max_retries=3, backoff=2):
for attempt in range(max_retries):
try:
response = requests.post(url, json=payload, headers=headers, timeout=30)
response.raise_for_status()
data = response.json()
if "error" in data:
error = data["error"]
code = error.get("code", 0)
message = error.get("data", {}).get("message", "Unknown error")
# Don't retry validation errors
if code in [200, 100]:
raise ValueError(f"Odoo validation error: {message}")
raise RuntimeError(f"Odoo API error {code}: {message}")
return data.get("result")
except (RequestException, RuntimeError) as e:
if attempt == max_retries - 1:
raise
wait = backoff ** attempt
print(f"Attempt {attempt + 1} failed: {e}. Retrying in {wait}s...")
time.sleep(wait)
Codes d'erreur courants :
| Codes | Signification | Actions |
|---|---|---|
| 100 | Erreur de serveur | Vérifier les journaux Odoo |
| 200 | Accès refusé | Vérifier les autorisations des utilisateurs |
| 300 | Enregistrement manquant | Vérifier que l'ID de l'enregistrement existe |
| 304 | Champ obligatoire manquant | Examiner la charge utile |
Meilleures pratiques en matière de performances
Opérations par lots : n'appelez jamais l'API en boucle pour des enregistrements individuels. Utilisez create_multi et write avec des listes :
# Bad: loop with individual creates
for product in products:
call_kw("product.template", "create", [product])
# Good: batch create
call_kw("product.template", "create", [products])
Sélection de champs : spécifiez toujours le paramètre fields pour éviter de récupérer tous les champs :
# Good: only fetch needed fields
orders = call_kw(
"sale.order", "search_read",
[[["state", "=", "sale"]]],
{"fields": ["name", "amount_total"], "limit": 1000}
)
Pagination : pour les ensembles de données volumineux, paginez à l'aide de limit et offset :
def fetch_all_records(model, domain, fields, batch_size=500):
records = []
offset = 0
while True:
batch = call_kw(
model, "search_read", [domain],
{"fields": fields, "limit": batch_size, "offset": offset}
)
records.extend(batch)
if len(batch) < batch_size:
break
offset += batch_size
return records
Questions fréquemment posées
Quelle est la différence entre JSON-RPC et l'API REST dans Odoo 19 ?
JSON-RPC donne accès à l'API Odoo Python complète, y compris toutes les méthodes côté serveur, tandis que REST suit les conventions OpenAPI 3.0 et expose une interface plus limitée mais standardisée. Pour les nouvelles intégrations où REST couvre votre cas d'utilisation, REST est préféré pour sa découvrabilité. Pour l'automatisation de flux de travail complexes ou l'accès à des méthodes Python personnalisées, utilisez JSON-RPC.
Comment gérer efficacement les exportations de données volumineuses (plus de 100 000 enregistrements) ?
Utilisez la pagination avec search_read et une taille de lot de 500 à 1 000 enregistrements. Pour les exportations très volumineuses, envisagez d'utiliser la fonction d'exportation d'Odoo via l'interface utilisateur pour des extractions ponctuelles, ou planifiez des tâches en arrière-plan à l'aide du modèle ir.cron d'Odoo pour traiter les données par morceaux pendant les heures creuses plutôt que d'effectuer des appels API en temps réel.
Puis-je utiliser des clés API au lieu d'un nom d'utilisateur/mot de passe pour XML-RPC ?
Oui. Dans Odoo 13+, les clés API peuvent être utilisées comme mots de passe dans l'appel d'authentification XML-RPC. Générez une clé API à partir de votre profil utilisateur et utilisez-la à la place de votre mot de passe : common.authenticate(db, username, api_key, {}). Il s'agit de l'approche recommandée pour les comptes de service.
Comment créer des enregistrements Many2many et One2many via l'API ?
Utilisez les tuples de commandes d'Odoo : (0, 0, vals) crée un nouvel enregistrement associé, (1, id, vals) met à jour un enregistrement associé existant, (2, id, 0) supprime un enregistrement associé, (4, id, 0) lie un enregistrement existant, (5, 0, 0) dissocie tous les enregistrements associés. Ces commandes fonctionnent de manière identique sur JSON-RPC, XML-RPC et REST.
Comment déclencher une action de workflow (comme la confirmation d'une commande) via l'API ?
Appelez la méthode correspondante sur le modèle. Pour confirmer une commande client, appelez action_confirm au sale.order. Pour valider une livraison, appelez button_validate au stock.picking. Ces méthodes sont visibles dans le code source d'Odoo et peuvent être découvertes en inspectant l'attribut name du bouton dans le mode développeur de l'interface utilisateur.
Quelles limites de débit Odoo impose-t-il aux appels d'API ?
Odoo n'applique pas nativement les limites de débit de l'API au niveau de l'application. La limitation de débit doit être configurée au niveau du proxy inverse (Nginx) ou de l'infrastructure. Une valeur par défaut raisonnable est de 60 requêtes par minute et par IP pour les intégrations externes. Pour les intégrations à haut débit, utilisez une approche basée sur la file d'attente avec un utilisateur de service dédié.
Prochaines étapes
Construire une intégration API Odoo fiable nécessite plus que des exemples de code fonctionnels : cela nécessite une gestion des erreurs, une surveillance, une gestion des informations d'identification et un alignement appropriés avec le modèle de données d'Odoo.
L'équipe d'intégration d'ECOSIRE a établi des connexions de niveau production entre Odoo et des dizaines de plateformes, notamment Shopify, Amazon, GoHighLevel, Power BI, des ERP personnalisés et des systèmes propriétaires. Nous gérons l'architecture d'authentification, la conception de webhooks, la transformation des données et la surveillance continue.
Parlez à ECOSIRE de votre projet d'intégration Odoo →
Que vous démarriez une nouvelle intégration ou répariez une intégration défaillante, nos ingénieurs examineront vos besoins et vous fourniront une solution qui gère les cas extrêmes dès le premier jour.
Rédigé par
ECOSIRE Research and Development Team
Création de produits numériques de niveau entreprise chez ECOSIRE. Partage d'analyses sur les intégrations Odoo, l'automatisation e-commerce et les solutions d'entreprise propulsées par l'IA.
Articles connexes
Odoo Accounting vs QuickBooks: Detailed Comparison 2026
In-depth 2026 comparison of Odoo Accounting vs QuickBooks covering features, pricing, integrations, scalability, and which platform fits your business needs.
AI + ERP Integration: How AI is Transforming Enterprise Resource Planning
Learn how AI is transforming ERP systems in 2026—from intelligent automation and predictive analytics to natural language interfaces and autonomous operations.
All-in-One vs Best-of-Breed: The Software Stack Decision
All-in-one vs best-of-breed software strategy for 2026: integration complexity, total cost, vendor risk, and when each approach is right for your business.