What Is the Odoo XML-RPC API?
Odoo exposes its entire ORM through XML-RPC — a protocol that lets external programs call Odoo methods remotely. Every operation you can do in the Odoo UI, you can do through the API: create records, search, update, delete, run methods, and generate reports.
Connection Setup
import xmlrpc.client
URL = 'http://localhost:8069'
DB = 'production'
USER = 'admin'
PASS = 'admin'
# Step 1: Authenticate
common = xmlrpc.client.ServerProxy(f'{URL}/xmlrpc/2/common')
uid = common.authenticate(DB, USER, PASS, {})
print(f'Authenticated as uid={uid}')
# Step 2: Get models proxy
models = xmlrpc.client.ServerProxy(f'{URL}/xmlrpc/2/object')
# Helper function
def call(model, method, *args, **kwargs):
return models.execute_kw(DB, uid, PASS, model, method, list(args), kwargs)CRUD Operations
Create
# Create one record
partner_id = call('res.partner', 'create', [{
'name': 'Acme Corp',
'email': '[email protected]',
'is_company': True,
}])
print(f'Created partner id={partner_id}')
# Create multiple records
ids = call('res.partner', 'create', [
{'name': 'Alice', 'email': '[email protected]'},
{'name': 'Bob', 'email': '[email protected]'},
])Read
# Read specific fields by IDs
data = call('res.partner', 'read', [partner_id], fields=['name', 'email', 'phone'])
print(data) # [{'id': 1, 'name': 'Acme Corp', 'email': '[email protected]', 'phone': False}]Search
# Search returns IDs
ids = call('res.partner', 'search',
[('is_company', '=', True)],
limit=10, offset=0, order='name asc'
)
# Search + Read in one call
records = call('res.partner', 'search_read',
[('is_company', '=', True)],
fields=['name', 'email', 'country_id'],
limit=10, order='name asc'
)
# Count
count = call('res.partner', 'search_count',
[('is_company', '=', True)]
)Update
# Update one or more records
call('res.partner', 'write', [[partner_id], {
'phone': '+1-555-0100',
'city': 'New York',
}])Delete
# Delete records
call('res.partner', 'unlink', [[partner_id]])Aggregation (read_group)
# Group sales by month
result = call('sale.order', 'read_group',
[('state', 'in', ['sale', 'done'])],
['amount_total:sum'],
['date_order:month'],
orderby='date_order:month asc'
)
for row in result:
print(f"{row['date_order:month']}: ${row['amount_total']}")Calling Model Methods
# Call any public method on a model
call('sale.order', 'action_confirm', [[order_id]])
call('account.move', 'action_post', [[invoice_id]])Many2many and One2many Commands
# Commands for relational fields:
# (0, 0, values) — Create new linked record
# (1, id, values) — Update existing linked record
# (2, id, 0) — Delete linked record
# (3, id, 0) — Unlink (remove relationship, keep record)
# (4, id, 0) — Link existing record
# (5, 0, 0) — Unlink all
# (6, 0, [ids]) — Replace with list of IDs
# Add tags to a partner
call('res.partner', 'write', [[partner_id], {
'category_id': [(4, tag_id_1), (4, tag_id_2)], # Link existing tags
}])
# Replace all tags
call('res.partner', 'write', [[partner_id], {
'category_id': [(6, 0, [tag_id_1, tag_id_2, tag_id_3])],
}])Error Handling
import xmlrpc.client
try:
result = call('res.partner', 'create', [{'name': ''}]) # Missing required field
except xmlrpc.client.Fault as e:
print(f"Odoo error: {e.faultString}")
except ConnectionRefusedError:
print("Cannot connect to Odoo server")Best Practices
- Use search_read instead of search + read for fewer API calls
- Use read_group for aggregations instead of reading all records
- Batch operations — Create/update multiple records in one call
- Set limits on search operations to prevent loading millions of records
- Use a dedicated API user with appropriate permissions, not admin
DeployMonkey Integration
DeployMonkey's built-in AI agent uses XML-RPC internally to interact with your Odoo instance. For custom integrations, connect to your DeployMonkey-hosted Odoo via XML-RPC using the same patterns above.