This is a module which exposes Odoo 18 as a REST API with proper JSON responses and Bearer token authentication.
- Download this module and put it to your Odoo addons directory
- Install requirements with pip install -r requirements.txt
- Ensure you have API keys configured in Odoo for authentication
This API uses Bearer token authentication with API keys. You need to include the Authorization header with your API key in all requests.
import json
import requests
# API endpoints
BASE_URL = 'http://localhost:8069'
API_BASE = f'{BASE_URL}/api/v1'
# Set up headers with API key
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer your_api_key_here'
}
# Example 1: Get users
USERS_URL = f'{API_BASE}/res.users'
res = requests.get(USERS_URL, headers=headers)
response_data = res.json()
if response_data['success']:
users = response_data['data']['records']
print(f"Found {len(users)} users")
else:
print(f"Error: {response_data['error']['message']}")
# Example 2: Get products with field selection
PRODUCTS_URL = f'{API_BASE}/product.product'
params = {'query': '{id, name}'}
res = requests.get(PRODUCTS_URL, params=params, headers=headers)
print(res.json())
All API responses follow a consistent JSON format:
Success Response:
{
"success": true,
"message": "Operation completed successfully",
"data": {
// Response data here
},
"timestamp": "2024-01-01T12:00:00.000Z"
}
Error Response:
{
"success": false,
"error": {
"code": 400,
"message": "Error description",
"type": "ValidationError",
"details": "Detailed error information"
},
"timestamp": "2024-01-01T12:00:00.000Z"
}
- query (optional): Field selection using query syntax
- filter (optional): JSON-encoded domain filter
- order (optional): JSON-encoded order specification
- limit (optional): Maximum number of records (max 1000)
- page_size (optional): Records per page for pagination (max 1000)
- page (optional): Page number for pagination
Basic request:
GET /api/v1/res.users?query={id, name}
Response:
{
"success": true,
"message": "Records retrieved successfully",
"data": {
"records": [
{"id": 2, "name": "Administrator"},
{"id": 6, "name": "Demo User"}
],
"pagination": {
"count": 2,
"total_count": 2,
"current_page": 1,
"total_pages": 1,
"page_size": null,
"prev_page": null,
"next_page": null
}
},
"timestamp": "2024-01-01T12:00:00.000Z"
}
Nested field selection:
GET /api/v1/res.users?query={id, name, company_id{name}}
Filtering:
GET /api/v1/product.template?filter=[["list_price", ">", 100]]&query={id, name, list_price}
Pagination:
GET /api/v1/product.template?page_size=10&page=2&query={id, name}
- query (optional): Field selection
GET /api/v1/product.template/95?query={id, name, list_price}
{
"data": {
"name": "New Product",
"list_price": 100.0
},
"context": {
"lang": "en_US"
}
}
{
"success": true,
"message": "Record created successfully",
"data": {
"id": 123,
"name": "New Product",
"list_price": 100.0
},
"timestamp": "2024-01-01T12:00:00.000Z"
}
{
"data": [
{"name": "Product 1", "list_price": 50.0},
{"name": "Product 2", "list_price": 75.0}
]
}
{
"data": {
"name": "Updated Product Name",
"list_price": 150.0
}
}
{
"filter": [["category_id", "=", 5]],
"data": {
"active": false
}
}
PUT /api/v1/product.template/?id=[1,2,3]
{
"data": {
"list_price": 200.0
}
}
For one2many and many2many fields, you can use these operations:
{
"data": {
"category_ids": {
"link": [1, 2, 3],
"unlink": [4, 5],
"delete": [6],
"set": [1, 2, 7, 8]
}
}
}
Operations:
- link: Add existing records to the relation
- unlink: Remove records from relation (but don't delete them)
- delete: Remove and delete records permanently
- set: Replace all related records with the specified list
- create: Create new records and link them
- update: Update existing related records
- clear: Remove all related records
{
"success": true,
"message": "Record deleted successfully",
"data": {
"success": true,
"message": "Record deleted successfully"
},
"timestamp": "2024-01-01T12:00:00.000Z"
}
{
"args": ["arg1", "arg2"],
"kwargs": {
"key1": "value1",
"key2": "value2"
}
}
{
"args": [],
"kwargs": {
"force": true
}
}
{
"domain": [["name", "ilike", "test"]],
"fields": ["id", "name", "email"],
"limit": 50,
"offset": 0,
"order": "name ASC"
}
Returns field definitions for the specified model.
Downloads binary field content.
Check API status (no authentication required).
Get API version and endpoint information.
The query parameter supports a powerful field selection syntax:
- {id, name} - Select specific fields
- {*} - Select all fields
- {-password} - Exclude specific fields
- {user{name, email}} - Nested field selection
- {*, user{-password}} - All fields with nested exclusions
The API returns appropriate HTTP status codes:
- 200 - Success
- 400 - Bad Request (validation errors)
- 404 - Not Found
- 500 - Internal Server Error
All errors include detailed error information in the response body.
- Create API keys in Odoo: Settings → Users & Companies → API Keys
- Set the scope to "odoo.api"
- Use the generated key in the Authorization header: Bearer your_api_key
- All timestamps are in ISO 8601 format
- Maximum limit per request is 1000 records
- Binary fields are base64 encoded in JSON responses
- The API supports Odoo's domain filter syntax for complex queries
- Relational fields return IDs by default, use nested queries for full objects