Integración de API de Odoo: Guía REST, JSON-RPC y XML-RPC
Odoo 19 expone tres interfaces API que cubren todo, desde la simple recuperación de datos hasta la compleja automatización del flujo de trabajo. Ya sea que esté creando una aplicación móvil personalizada, sincronizándola con una plataforma de terceros o ampliando las capacidades de Odoo con microservicios externos, dominar la capa API de Odoo es fundamental para cualquier proyecto de integración serio.
Esta guía proporciona ejemplos de código de trabajo, flujos de autenticación y recomendaciones arquitectónicas para integraciones REST, JSON-RPC y XML-RPC, las tres interfaces principales disponibles en Odoo 19 Enterprise.
Conclusiones clave
- Odoo 19 ofrece interfaces REST (OpenAPI 3.0), JSON-RPC 2.0 y XML-RPC
- La autenticación utiliza claves API (recomendado) o inicio de sesión basado en sesión
- JSON-RPC es la interfaz con más funciones para operaciones complejas
- La API REST sigue las especificaciones de OpenAPI 3.0 y admite verbos HTTP estándar.
- XML-RPC es heredado pero aún es totalmente compatible para compatibilidad con versiones anteriores
- La limitación de velocidad y el manejo de errores deben implementarse en el lado del cliente.
- Los webhooks en Odoo 19 envían datos a sistemas externos sobre cambios de registros
- Todas las llamadas API respetan los derechos de acceso y las reglas de registro de Odoo.
Comparación de interfaces API
Antes de escribir una sola línea de código, elija la interfaz API adecuada para su caso de uso:
| Característica | API REST | JSON-RPC | XML-RPC |
|---|---|---|---|
| Protocolo | HTTP/HTTPS | HTTP/HTTPS | HTTP/HTTPS |
| Formato de carga útil | JSON | JSON | XML |
| Especificaciones de OpenAPI | Sí (arrogancia) | No | No |
| Operaciones CRUD | Sí | Sí | Sí |
| Llamadas a métodos | Limitado | Completo | Completo |
| Activadores del flujo de trabajo | A través de acciones | A través de ejecutar_kw | Vía ejecutar |
| Recomendado para | Nuevas integraciones | Lógica compleja | Sistemas heredados |
| Biblioteca de Python | solicitudes | odoo-xmlrpc/solicitudes | xmlrpc.cliente |
Cuándo usar REST: crear una aplicación móvil, integrarla con plataformas nativas de webhook (Shopify, Stripe) o cuando su equipo se sienta más cómodo con las convenciones REST.
Cuándo usar JSON-RPC: ejecutar métodos complejos del lado del servidor de Odoo, leer grandes conjuntos de datos con filtros de dominio o cuando necesita acceso a métodos no expuestos a través de REST.
Cuándo usar XML-RPC: mantener las integraciones existentes creadas antes de que REST estuviera disponible, o cuando su plataforma tiene bibliotecas cliente XML-RPC maduras.
Autenticación
Autenticación de clave API (recomendado)
Odoo 19 admite la autenticación de clave API para las tres interfaces. Genere una clave API en Configuración → Usuarios → Su usuario → Claves 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}"
}
Las claves API están dirigidas a un usuario específico y heredan los derechos de acceso de ese usuario. Cree usuarios de servicios dedicados con permisos mínimos requeridos para cuentas de integración.
Autenticación basada en sesiones (JSON-RPC / XML-RPC)
Para JSON-RPC, autentíquese utilizando el punto final /web/dataset/call_kw después de establecer una sesión:
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}")
Para XML-RPC, utilice la autenticación estándar de dos pasos:
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 presenta una API REST completa con la especificación OpenAPI 3.0. Acceda a la documentación interactiva en https://your-odoo.com/api/docs.
Listado de registros
# 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()
Leer un solo registro
# GET /api/sale.order/{id}
order_id = 123
response = requests.get(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers
)
order = response.json()
Creando un registro
# 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()
Actualización de un registro
# 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"}
)
Eliminar un registro
# DELETE /api/sale.order/{id}
response = requests.delete(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers
)
Interfaz JSON-RPC
JSON-RPC proporciona acceso a la API completa de Odoo Python, incluidos los métodos del lado del servidor que no están expuestos a través de REST. El criterio de valoración principal es /web/dataset/call_kw.
Búsqueda y lectura básica
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"]}
)
Búsqueda Lectura (Combinada)
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"
}
)
Creando registros
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
})
]
}]
)
Llamar a métodos del lado del servidor
JSON-RPC brinda acceso a todos los métodos de Python definidos en los modelos de 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", [[]])
Interfaz XML-RPC
XML-RPC es la API original de Odoo y sigue siendo totalmente compatible. La interfaz consta de dos puntos finales:
/xmlrpc/2/common— métodos no autenticados (autenticar, versión)/xmlrpc/2/object— todas las operaciones del modelo (requiere 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'
}]
)
Filtros de dominio
La sintaxis de filtro de dominio de Odoo se utiliza en los tres tipos de API. Comprender los dominios es esencial para una recuperación de datos eficiente.
# 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 e integración basada en eventos
Odoo 19 admite webhooks salientes activados por cambios de registros. Configure webhooks en Configuración → Técnico → Webhooks.
Configuración del webhook:
- Vaya a Configuración → Técnico → Webhooks → Crear
- Establezca el Modelo (por ejemplo,
sale.order) - Seleccione Activador: crear, escribir, desvincular o personalizar el método.
- Ingrese la URL del punto final de su servicio receptor.
- Opcionalmente, configure Dominio para filtrar qué registros activan el webhook.
- Configure Campos para incluirlos en la carga útil
Recepción de eventos de webhook en un servicio 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
Manejo de errores y lógica de reintento
Las integraciones sólidas deben manejar los errores de la API de Odoo con elegancia.
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)
Códigos de error comunes:
| Código | Significado | Acción |
|---|---|---|
| 100 | Error del servidor | Verifique los registros de Odoo |
| 200 | Acceso denegado | Verificar permisos de usuario |
| 300 | Registro faltante | Comprobar que el ID del registro existe |
| 304 | Falta campo obligatorio | Revisar la carga útil |
Mejores prácticas de rendimiento
Operaciones por lotes: nunca llame a la API en un bucle para registros individuales. Utilice create_multi y write con listas:
# Bad: loop with individual creates
for product in products:
call_kw("product.template", "create", [product])
# Good: batch create
call_kw("product.template", "create", [products])
Selección de campo: especifique siempre el parámetro fields para evitar recuperar todos los campos:
# Good: only fetch needed fields
orders = call_kw(
"sale.order", "search_read",
[[["state", "=", "sale"]]],
{"fields": ["name", "amount_total"], "limit": 1000}
)
Paginación: para conjuntos de datos grandes, pagina usando limit y 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
Preguntas frecuentes
¿Cuál es la diferencia entre JSON-RPC y la API REST en Odoo 19?
JSON-RPC proporciona acceso a la API completa de Odoo Python, incluidos todos los métodos del lado del servidor, mientras que REST sigue las convenciones de OpenAPI 3.0 y expone una interfaz más limitada pero estandarizada. Para nuevas integraciones en las que REST cubre su caso de uso, se prefiere REST por su capacidad de descubrimiento. Para una automatización de flujo de trabajo compleja o acceso a métodos Python personalizados, utilice JSON-RPC.
¿Cómo puedo manejar exportaciones de datos grandes (más de 100.000 registros) de manera eficiente?
Utilice paginación con search_read y un tamaño de lote de 500 a 1000 registros. Para exportaciones muy grandes, considere usar la función de exportación de Odoo a través de la interfaz de usuario para extracciones únicas, o programe trabajos en segundo plano usando el modelo ir.cron de Odoo para procesar datos en fragmentos durante las horas de menor actividad en lugar de realizar llamadas API en tiempo real.
¿Puedo usar claves API en lugar de nombre de usuario/contraseña para XML-RPC?
Sí. En Odoo 13+, las claves API se pueden usar como contraseñas en la llamada de autenticación XML-RPC. Genere una clave API a partir de su perfil de usuario y úsela en lugar de su contraseña: common.authenticate(db, username, api_key, {}). Este es el enfoque recomendado para las cuentas de servicio.
¿Cómo creo registros Many2many y One2many a través de la API?
Utilice las tuplas de comandos de Odoo: (0, 0, vals) crea un nuevo registro relacionado, (1, id, vals) actualiza un registro relacionado existente, (2, id, 0) elimina un registro relacionado, (4, id, 0) vincula un registro existente, (5, 0, 0) desvincula todos los registros relacionados. Estos comandos funcionan de manera idéntica en JSON-RPC, XML-RPC y REST.
¿Cómo activo una acción de flujo de trabajo (como confirmar un pedido) a través de la API?
Llame al método correspondiente en el modelo. Para confirmar un pedido de venta, llame a action_confirm al sale.order. Para validar una entrega, llame a button_validate al stock.picking. Estos métodos son visibles en el código fuente de Odoo y se pueden descubrir inspeccionando el atributo name del botón en el modo de desarrollador de la interfaz de usuario.
¿Qué límites de velocidad impone Odoo a las llamadas API?
Odoo no aplica límites de tasa de API de forma nativa a nivel de aplicación. La limitación de velocidad debe configurarse en el proxy inverso (Nginx) o en el nivel de infraestructura. Un valor predeterminado sensato es 60 solicitudes por minuto por IP para integraciones externas. Para integraciones de alto rendimiento, utilice un enfoque basado en colas con un usuario de servicio dedicado.
Próximos pasos
Construir una integración API de Odoo confiable requiere más que ejemplos de código funcional: exige un manejo adecuado de errores, monitoreo, administración de credenciales y alineación con el modelo de datos de Odoo.
El equipo de integración de ECOSIRE ha creado conexiones de nivel de producción entre Odoo y docenas de plataformas, incluidas Shopify, Amazon, GoHighLevel, Power BI, ERP personalizados y sistemas propietarios. Nos encargamos de la arquitectura de autenticación, el diseño de webhooks, la transformación de datos y el monitoreo continuo.
Hable con ECOSIRE sobre su proyecto de integración de Odoo →
Ya sea que esté iniciando una nueva integración o arreglando una rota, nuestros ingenieros revisarán sus requisitos y le brindarán una solución que maneje los casos extremos desde el primer día.
Escrito por
ECOSIRE Research and Development Team
Construyendo productos digitales de nivel empresarial en ECOSIRE. Compartiendo perspectivas sobre integraciones Odoo, automatización de eCommerce y soluciones empresariales impulsadas por IA.
Artículos relacionados
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.