API Reference
ODXProxy endpoints (v1 and v2) and the execute request/response shapes.
The reference below is generated from ODXProxy's OpenAPI spec (apispec.yaml,
reconciled with SYSTEM_ARCHITECTURE.md). It stays in sync with the wire
protocol — when the spec changes, this page changes with it.
Prefer Postman or raw HTTP? Download the Postman collection —
ready-made requests for every endpoint, with baseUrl, proxyApiKey, and target
Odoo instance values as collection variables. It has a folder per API version; the
v2 folder runs top to bottom (it creates a partner, reads, updates and deletes it) and
carries saved example responses, errors included. Import it in Postman via
Import → File.
There are two API versions with the same auth and envelope: v1
(/api/odoo/*, alias /v1/odoo/*; execute_kw, any Odoo up to 21) and v2
(/v2/odoo/*; Odoo JSON-2, Odoo 19+). API versions explains
which to use.
Before you read the endpoints, three things trip people up:
A 200 status can still carry an error
ODXProxy speaks JSON-RPC 2.0, not REST. Odoo-side logic errors (validation,
access-right denial) come back as HTTP 200 with a populated error object.
Always check the JSON-RPC error field, not just the HTTP status — only
proxy-layer failures use non-200 codes.
Two different secrets
x-api-key is the proxy's API key (authenticates you to ODXProxy).
odoo_instance.api_key is the Odoo user's API key (authenticates the proxy
to the target Odoo). They are never the same value — don't conflate them.
Actions and their fields
On v1, only the 9 allowlisted actions are directly callable;
anything else goes through call_method with a non-empty fn_name. params is a
JSON array (default []); keyword is a JSON object (default {}). On v2,
method is any public model method and kwargs is one JSON object of named
arguments, under Odoo's Python parameter names. The optional x-request-timeout
header overrides the per-request Odoo timeout on both (seconds, default 15).
Authorization
ProxyApiKeyAuth The proxy's static API key (the value of PROXY_API_KEY). This is NOT the
Odoo user's API key — that is carried per-request in odoo_instance.api_key.
In: header
Header Parameters
Upstream Odoo timeout in integer seconds. Missing, non-numeric, or 0
falls back to the proxy default (DEFAULT_ODOO_TIMEOUT_SECS, default 15).
int640 <= valueRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/api/odoo/execute" \ -H "Content-Type: application/json" \ -d '{ "id": "01J9Z8K3QJ7Y5T2N6V4W8X0ABC", "action": "search_read", "model_id": "res.partner", "params": [ [ [ "is_company", "=", true ] ] ], "keyword": { "fields": [ "name", "email" ], "limit": 10 }, "odoo_instance": { "url": "https://erp.example.com", "db": "prod", "user_id": 2, "api_key": "<ODOO_USER_API_KEY>" } }'{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}Authorization
ProxyApiKeyAuth The proxy's static API key (the value of PROXY_API_KEY). This is NOT the
Odoo user's API key — that is carried per-request in odoo_instance.api_key.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
curl -X POST "https://example.com/api/odoo/version" \ -H "Content-Type: application/json" \ -d '{ "id": "string", "url": "https://erp.example.com" }'{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}Authorization
ProxyApiKeyAuth The proxy's static API key (the value of PROXY_API_KEY). This is NOT the
Odoo user's API key — that is carried per-request in odoo_instance.api_key.
In: header
Header Parameters
Upstream Odoo timeout in integer seconds. Missing, non-numeric, or 0
falls back to the proxy default (DEFAULT_ODOO_TIMEOUT_SECS, default 15).
int640 <= valueRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
text/plain
application/json
application/json
application/json
curl -X POST "https://example.com/v2/odoo/execute" \ -H "Content-Type: application/json" \ -d '{ "id": "01J9Z8K3QJ7Y5T2N6V4W8X0ABC", "model_id": "res.partner", "method": "search_read", "kwargs": { "domain": [ [ "is_company", "=", true ] ], "fields": [ "name", "email" ], "limit": 10, "context": { "lang": "en_US", "allowed_company_ids": [ 1 ] } }, "odoo_instance": { "url": "https://erp.example.com", "db": "prod", "api_key": "<ODOO_USER_API_KEY>" } }'{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}"Failed to deserialize the JSON body into the target type: kwargs: invalid type: sequence, expected a map"{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}Authorization
ProxyApiKeyAuth The proxy's static API key (the value of PROXY_API_KEY). This is NOT the
Odoo user's API key — that is carried per-request in odoo_instance.api_key.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
curl -X POST "https://example.com/v2/odoo/version" \ -H "Content-Type: application/json" \ -d '{ "id": "string", "url": "https://erp.example.com" }'{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}Response Body
application/json
curl -X GET "https://example.com/_/license"{ "licensee": "Acme Pte. Ltd.", "valid_until": "2026-12-31", "is_valid": true}Response Body
application/json
curl -X GET "https://example.com/_/about"{ "jsonrpc": "2.0", "id": "string", "result": null, "error": { "code": -32000, "message": "Authentication failed", "data": null }}Response Body
text/plain
curl -X GET "https://example.com/_/metrics""string"