Call authenticate on the endpoint /xmlrpc/2/common passing the database name, username, API key (not password in production), and an empty options dict; store the returned integer uid
Use the uid on all subsequent calls to /xmlrpc/2/object via the execute_kw method: pass (db, uid, api_key, model_name, method_name, positional_args_list, keyword_args_dict)
To read records: call execute_kw with method 'search_read', a domain filter list as positional args, and {'fields': [...], 'limit': N} as kwargs
To create: method 'create' with a dict of field values; to write: method 'write' with ([id_list], {field: value}); to delete: method 'unlink' with ([id_list],)
Switch to JSON-RPC (/web/dataset/call_kw) for new integrations — the payload structure is analogous but uses JSON; JSON-RPC is the preferred path in Odoo 17+ documentation
Known gotchas
The uid returned by authenticate is not a session token and does not expire, but you still pass the password/API key on every call — there is no stateless token exchange in the XML-RPC protocol
Odoo domain filters use a Polish prefix notation list: [('field', 'operator', value)]; an empty list [] returns all records with no filter — always add a meaningful domain to avoid full-table fetches
XML-RPC in Python's standard library does not verify SSL certificates by default on some versions; use an explicit ssl.create_default_context() or an HTTP client library that does certificate validation
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp