Suốt loạt bài, ta viết code bên trong Odoo. Nhưng rất nhiều tình huống cần bên ngoài gọi vào: một script đồng bộ đơn hàng từ sàn TMĐT, một app di động đọc điểm thành viên, một hệ thống kế toán khác ghi hoá đơn vào Odoo. Cách chuẩn, cũ mà bền, chạy được từ mọi ngôn ngữ, là XML-RPC. Không cần cài gì trong Odoo — nó có sẵn hai endpoint, bạn chỉ việc gọi. Bài này chỉ luồng đầy đủ (đăng nhập → đọc/ghi) và chạy thật một vòng CRUD từ một script Python ngoài Odoo 19.
Hai endpoint: common và object
Odoo phơi ra hai địa chỉ XML-RPC. /xmlrpc/2/common để đăng nhập (và hỏi phiên bản); /xmlrpc/2/object để gọi mọi model qua một hàm duy nhất execute_kw.

Hình 1: Luồng chuẩn. common.authenticate(db, user, password, {}) trả về uid (số). Sau đó mọi thao tác đi qua object.execute_kw(db, uid, password, model, method, args, kwargs) — search_read, create, write, unlink, search_count, fields_get... bất kỳ method public nào của model.
Chạy thật một vòng CRUD
Đây là kết quả thật khi chạy script Python ngoài gọi vào Odoo 19:

Hình 2: Thật, không bịa. version báo 19.0-20260908; authenticate trả uid=2; search_read đọc đúng 4 thẻ; rồi create (id 56) → write (điểm 99) → unlink — một vòng CRUD hoàn chỉnh từ bên ngoài, và dọn sạch để về nguyên trạng (total vẫn 4).
execute_kw: một hàm gọi mọi thứ
Điểm mạnh của XML-RPC Odoo là một hàm execute_kw gọi được mọi method của mọi model — không cần endpoint riêng cho từng thứ:
# search_read: lọc + chọn cột trong một lần
models.execute_kw(DB, uid, PW, 'res.partner', 'search_read',
[[['is_company', '=', True]]], # args: domain
{'fields': ['name', 'email'], 'limit': 10}) # kwargs
# create nhiều bản ghi, write, unlink
ids = models.execute_kw(DB, uid, PW, 'product.product', 'create',
[[{'name': 'Cà phê A'}, {'name': 'Cà phê B'}]])
# gọi cả method nghiệp vụ tuỳ ý (miễn là public)
models.execute_kw(DB, uid, PW, 'sale.order', 'action_confirm', [[order_id]])
args là danh sách tham số vị trí (domain, dict giá trị...), kwargs là tham số theo tên (fields, limit, order, context). Cùng đúng API ORM bạn dùng trong code server.
Bảo mật: đừng để hớ
XML-RPC mạnh nghĩa là nguy hiểm nếu để hở — nó cho phép đọc/ghi/xoá dữ liệu từ xa:
- Xác thực bắt buộc. Cần
login+password(hoặcuid+ password) cho mọi lời gọiexecute_kw. Từ Odoo 14+, nên dùng API key thay cho password thật: vào Preferences → Account Security → New API Key, rồi dùng key đó ở chỗ password. Rò rỉ API key thì thu hồi được, không phải đổi mật khẩu. - Luôn HTTPS. XML-RPC gửi credential trong payload; qua HTTP thường là lộ. Đặt sau nginx TLS.
- Quyền của
uidvẫn áp dụng. Lời gọi chạy dưới quyền user đăng nhập — Access Rights và Record Rules vẫn chặn. Dùng một user tài-khoản-dịch-vụ với đúng quyền cần, đừng dùng admin cho mọi tích hợp. - Giới hạn IP/tần suất ở tầng proxy nếu endpoint mở ra Internet.
XML-RPC hay JSON-RPC?
Odoo phơi ra cả hai giao thức cho cùng chức năng:
- XML-RPC (bài này): chuẩn lâu đời, thư viện có sẵn ở mọi ngôn ngữ (Python
xmlrpc.client, PHP, Java, Ruby...). Payload XML hơi nặng, nhưng ổn định, tài liệu nhiều. - JSON-RPC: nhẹ hơn, hợp khi gọi từ JavaScript/HTTP hiện đại — phần sau nói riêng.
Cùng model, cùng execute_kw, chỉ khác định dạng gói tin. Chọn XML-RPC khi cần tương thích rộng, JSON-RPC khi làm web/JS.
Ba ý mang về
- XML-RPC cho chương trình ngoài gọi Odoo không cần cài gì thêm:
common.authenticate(db, user, pass, {})lấyuid, rồiobject.execute_kw(db, uid, pass, model, method, args, kwargs)gọi mọi method (search_read, create, write, unlink...). - Một hàm
execute_kwgọi mọi model/method —args(vị trí: domain, dict),kwargs(theo tên: fields, limit, order, context); đúng API ORM như trong code server, chạy được từ Python/PHP/Java/bất kỳ. - Bảo mật là bắt buộc: xác thực mọi lời gọi (ưu tiên API key thay password, Odoo 14+), luôn HTTPS, dùng user dịch vụ đúng quyền (Record Rules vẫn áp) — đừng phơi admin ra Internet.
XML-RPC hợp cho backend đa ngôn ngữ; nhưng khi gọi từ web/JavaScript, JSON-RPC gọn hơn. Phần sau mổ xẻ gọi Odoo bằng JSON-RPC — cùng khả năng, định dạng nhẹ, và cách gọi từ fetch/JavaScript hay bất kỳ client HTTP nào.