Odoo API 集成:REST、JSON-RPC 和 XML-RPC 指南
Odoo 19 公开了三个 API 接口,涵盖从简单的数据检索到复杂的工作流程自动化的所有内容。无论您是构建自定义移动应用程序、与第三方平台同步,还是通过外部微服务扩展 Odoo 的功能,掌握 Odoo API 层都是任何重要集成项目的基础。
本指南提供了适用于 REST、JSON-RPC 和 XML-RPC 集成(Odoo 19 Enterprise 中提供的三个主要接口)的工作代码示例、身份验证流程和架构建议。
要点
- Odoo 19 提供 REST (OpenAPI 3.0)、JSON-RPC 2.0 和 XML-RPC 接口
- 身份验证使用 API 密钥(推荐)或基于会话的登录
- JSON-RPC是功能最齐全的复杂操作接口
- REST API 遵循 OpenAPI 3.0 规范并支持标准 HTTP 动词
- XML-RPC 是遗留的,但仍然完全支持向后兼容
- 速率限制和错误处理必须在客户端实现
- Odoo 19 中的 Webhook 将记录更改的数据推送到外部系统
- 所有 API 调用均尊重 Odoo 的访问权限和记录规则
API接口对比
在编写一行代码之前,请为您的用例选择正确的 API 接口:
| 特色 | 休息 API | JSON-RPC | XML-RPC |
|---|---|---|---|
| 协议 | HTTP/HTTPS | HTTP/HTTPS | HTTP/HTTPS |
| 有效负载格式 | JSON | JSON | XML |
| OpenAPI 规范 | 是的(大摇大摆) | 没有 | 没有 |
| CRUD 操作 | 是的 | 是的 | 是的 |
| 方法调用 | 有限公司 | 完整 | 完整 |
| 工作流程触发器 | 通过行动 | 通过execute_kw | 通过执行 |
| 推荐用于 | 新的集成 | 复杂逻辑 | 遗留系统 |
| Python 库 | 请求 | odoo-xmlrpc / 请求 | xmlrpc.client |
何时使用 REST:构建移动应用程序、与 webhook 本机平台(Shopify、Stripe)集成,或者当您的团队更熟悉 REST 约定时。
何时使用 JSON-RPC:执行复杂的 Odoo 服务器端方法、使用域过滤器读取大型数据集,或者当您需要访问未通过 REST 公开的方法时。
何时使用 XML-RPC:维护在 REST 可用之前构建的现有集成,或者当您的平台具有成熟的 XML-RPC 客户端库时。
身份验证
API密钥认证(推荐)
Odoo 19 支持所有三个接口的 API 密钥身份验证。在 设置 → 用户 → 您的用户 → API 密钥 下生成 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}"
}
API 密钥的范围仅限于特定用户并继承该用户的访问权限。创建具有集成帐户所需的最低权限的专用服务用户。
基于会话的身份验证(JSON-RPC / XML-RPC)
对于 JSON-RPC,在建立会话后使用 /web/dataset/call_kw 端点进行身份验证:
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}")
对于 XML-RPC,使用标准的两步身份验证:
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")
REST API:OpenAPI 3.0
Odoo 19 引入了符合 OpenAPI 3.0 规范的完整 REST API。访问 https://your-odoo.com/api/docs 处的交互式文档。
列出记录
# 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()
读取单个记录
# GET /api/sale.order/{id}
order_id = 123
response = requests.get(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers
)
order = response.json()
创建记录
# 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()
更新记录
# 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"}
)
删除记录
# DELETE /api/sale.order/{id}
response = requests.delete(
f"{ODOO_URL}/api/sale.order/{order_id}",
headers=headers
)
JSON-RPC 接口
JSON-RPC 提供对完整 Odoo Python API 的访问,包括不通过 REST 公开的服务器端方法。主要终点是 /web/dataset/call_kw。
基本搜索和阅读
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"]}
)
搜索阅读(合并)
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"
}
)
创建记录
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
})
]
}]
)
调用服务器端方法
JSON-RPC 允许访问 Odoo 模型上定义的所有 Python 方法:
# 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", [[]])
XML-RPC 接口
XML-RPC 是原始的 Odoo API,并且仍然得到完全支持。该接口由两个端点组成:
/xmlrpc/2/common— 未经身份验证的方法(身份验证、版本)/xmlrpc/2/object— 所有模型操作(需要 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'
}]
)
域过滤器
Odoo 的域过滤器语法适用于所有三种 API 类型。了解域对于有效的数据检索至关重要。
# 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]
]
Webhook 和事件驱动集成
Odoo 19 支持由记录更改触发的出站 Webhook。在 设置 → 技术 → Webhooks 下配置 Webhooks。
网络钩子配置:
- 导航至 设置 → 技术 → Webhooks → 创建
- 设置 型号(例如
sale.order) - 选择触发器:创建、写入、取消链接或自定义方法
- 输入接收服务的 端点 URL
- (可选)设置 Domain 来过滤哪些记录触发 webhook
- 配置 Fields 以包含在有效负载中
在 Flask 服务中接收 webhook 事件:
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
错误处理和重试逻辑
强大的集成必须妥善处理 Odoo API 错误。
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)
常见错误代码:
| 代码 | 意义 | 行动 |
|---|---|---|
| 100 | 100服务器错误 | 检查 Odoo 日志 |
| 200 | 200访问被拒绝 | 验证用户权限 |
| 300 | 300失踪记录 | 检查记录ID是否存在 |
| 304 | 304缺少必填字段 | 审查有效负载 |
性能最佳实践
批量操作:切勿在循环中为单个记录调用 API。将 create_multi 和 write 与列表一起使用:
# Bad: loop with individual creates
for product in products:
call_kw("product.template", "create", [product])
# Good: batch create
call_kw("product.template", "create", [products])
字段选择:始终指定 fields 参数以避免获取所有字段:
# Good: only fetch needed fields
orders = call_kw(
"sale.order", "search_read",
[[["state", "=", "sale"]]],
{"fields": ["name", "amount_total"], "limit": 1000}
)
分页:对于大型数据集,使用 limit 和 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
常见问题
Odoo 19 中 JSON-RPC 和 REST API 有什么区别?
JSON-RPC 提供对完整 Odoo Python API 的访问,包括所有服务器端方法,而 REST 遵循 OpenAPI 3.0 约定并公开更有限但标准化的接口。对于 REST 涵盖您的用例的新集成,REST 因其可发现性而成为首选。对于复杂的工作流程自动化或访问自定义 Python 方法,请使用 JSON-RPC。
如何高效处理大数据导出(10万+条记录)?
使用带有 search_read 的分页和 500–1000 条记录的批量大小。对于非常大的导出,请考虑通过 UI 使用 Odoo 的导出功能进行一次性提取,或者使用 Odoo 的 ir.cron 模型安排后台作业,以便在非高峰时段处理大块数据,而不是进行实时 API 调用。
我可以使用 API 密钥代替 XML-RPC 的用户名/密码吗?
是的。在 Odoo 13+ 中,API 密钥可以用作 XML-RPC 身份验证调用中的密码。从您的用户配置文件生成 API 密钥并使用它代替您的密码:common.authenticate(db, username, api_key, {})。这是服务帐户的推荐方法。
如何通过 API 创建 Many2many 和 One2many 记录?
使用 Odoo 的命令元组: (0, 0, vals) 创建新的相关记录, (1, id, vals) 更新现有的相关记录, (2, id, 0) 删除相关记录, (4, id, 0) 链接现有记录, (5, 0, 0) 取消链接所有相关记录。这些命令在 JSON-RPC、XML-RPC 和 REST 中的工作方式相同。
如何通过 API 触发工作流程操作(例如确认订单)?
调用模型上相应的方法。要确认销售订单,请致电 sale.order 上的 action_confirm。要验证交货,请致电 stock.picking 上的 button_validate。这些方法在 Odoo 的源代码中可见,并且可以通过在 UI 开发者模式中检查按钮的 name 属性来发现。
Odoo 对 API 调用施加什么速率限制?
Odoo 本身并不在应用程序级别强制执行 API 速率限制。必须在反向代理 (Nginx) 或基础设施级别配置速率限制。对于外部集成,合理的默认值是每个 IP 每分钟 60 个请求。对于高吞吐量集成,请使用基于队列的方法和专门的服务用户。
后续步骤
构建可靠的 Odoo API 集成需要的不仅仅是工作代码示例 - 它还需要正确的错误处理、监控、凭证管理以及与 Odoo 数据模型的一致性。
ECOSIRE 的集成团队已在 Odoo 与数十个平台(包括 Shopify、Amazon、GoHighLevel、Power BI、自定义 ERP 和专有系统)之间建立了生产级连接。我们处理身份验证架构、Webhook 设计、数据转换和持续监控。
无论您是开始新的集成还是修复损坏的集成,我们的工程师都会审查您的需求,并从第一天起就提供处理边缘情况的解决方案。
作者
ECOSIRE Research and Development Team
在 ECOSIRE 构建企业级数字产品。分享关于 Odoo 集成、电商自动化和 AI 驱动商业解决方案的洞见。
相关文章
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.