Actions and Methods
The 9 actions ODXProxy allows through to Odoo's execute_kw (v1), and the named kwargs each Odoo method takes on JSON-2 (v2).
What you can call depends on the API version. v1 has a fixed allowlist of nine actions with positional arguments; v2 calls any public model method with named arguments. Both reach the same Odoo methods — only the shape differs, so don't mix the two.
v1: the 9 allowed actions
The action field must be one of these 9 values. Anything else is rejected with
HTTP 400 and JSON-RPC code -32001.
| Action | Meaning |
|---|---|
search_count | Count records matching a domain. |
search | Return record IDs matching a domain. |
read | Read fields for given IDs. |
fields_get | Describe a model's fields. |
search_read | Combined search + read. |
create | Create record(s). |
write | Update record(s) by ID. |
unlink | Delete record(s) by ID. |
call_method | Invoke an arbitrary model method named by fn_name. |
The action is passed straight through as the Odoo method name in execute_kw,
except for call_method, where fn_name is used instead.
The model and fields are arbitrary — they are named in the request body and forwarded as-is. The proxy never hardcodes or mirrors your Odoo schema, so a model or field you add in Odoo is reachable immediately, with no proxy redeploy, config change, or schema regeneration. That holds on v2 too.
call_method requires a non-empty fn_name. Omitting it returns HTTP 400
with JSON-RPC code -32002. Any model method outside this allowlist must be
invoked through call_method.
params and keyword per action
params is the positional-argument list of execute_kw, so for the search-style
actions the domain is its first element — hence the doubled brackets. keyword
carries kwargs such as fields, limit, offset, order, and context.
| Action | params | keyword | result |
|---|---|---|---|
search_count | [domain] | {context} | integer |
search | [domain] | {limit, offset, order} | array of ids |
read | [ids, fields] (fields optional) | {context} | array of records |
fields_get | [] | {attributes} | object keyed by field name |
search_read | [domain] | {fields, limit, offset, order} | array of records |
create | [vals] | {context} | the new id |
write | [ids, vals] | {context} | true |
unlink | [ids] | {context} | true |
call_method | the method's positional args, e.g. [ids] | the method's kwargs | whatever the method returns |
{ "action": "search_read", "model_id": "res.partner",
"params": [[["is_company", "=", true]]],
"keyword": { "fields": ["name", "email"], "limit": 50, "order": "name asc" } }
{ "action": "write", "model_id": "res.partner",
"params": [[42], { "name": "Acme LLC" }] }
{ "action": "call_method", "model_id": "sale.order", "fn_name": "action_confirm",
"params": [[42]] }v2: methods and their kwargs
On v2 (POST /v2/odoo/execute, Odoo 19+), method names the Odoo method directly
and kwargs carries every argument by name. There is no allowlist, no
fn_name, and no positional params. Odoo checks each key against the method's
Python signature, so the keys below must be spelled exactly as shown.
| Operation | method | kwargs | result |
|---|---|---|---|
| search + read | search_read | domain, fields, offset, limit, order | array of records |
| search | search | domain, offset, limit, order | array of ids |
| count | search_count | domain, limit | integer |
| read | read | ids, fields, load | array of records |
| schema | fields_get | allfields, attributes | object keyed by field name |
| create | create | vals_list — always an array | array of ids, always |
| update | write | ids, vals | true |
| delete | unlink | ids | true |
| anything else | the method's name | ids (record methods only) + the method's named args | whatever the method returns; a recordset becomes an array of ids |
Any call can also carry context (lang, tz, allowed_company_ids, …).
{ "model_id": "res.partner", "method": "search_read",
"kwargs": { "domain": [["is_company", "=", true]], "fields": ["name", "email"], "limit": 50 } }
{ "model_id": "res.partner", "method": "create",
"kwargs": { "vals_list": [{ "name": "Acme Inc" }] } }
{ "model_id": "sale.order", "method": "action_confirm",
"kwargs": { "ids": [42] } }
{ "model_id": "res.partner", "method": "name_search",
"kwargs": { "name": "Acm", "limit": 5 } }The rules that matter:
- Keys are Odoo's Python names, verbatim.
vals_list, notvalsList;allfields, notallFields. Field names insidevals,domain, andcontextare sent exactly as Odoo writes them too. - The domain is the list itself —
"domain": [["is_company", "=", true]]. An empty domain is[]. - Leave out what you don't set. Odoo's own defaults then apply;
nullmeans PythonNone, which is not the same thing. idsonly for record methods. Sendingidsto an@api.modelmethod (search,search_read,search_count,fields_get,create,name_search, …) fails with error code422, as does an unknown or misspelled key.model_idandmethodmay contain onlyA-Z a-z 0-9 _ .and can't start with.; anything else is rejected with HTTP 400 /-32007before Odoo is contacted. Odoo refuses private (_-prefixed) methods with code403.
Finding a method's parameter names
For methods beyond the table above, the parameter names are in the method's
Python definition. On Odoo 19+, /doc/<model> in the web UI lists every public
method of a model with its parameters.
Relational fields (both versions)
For one2many and many2many fields, Odoo uses command tuples inside the values dict —
[[6, 0, [ids]]] to replace, [[4, id]] to link, [[0, 0, {vals}]] to create and
link. They pass through create and write unchanged on both versions. Check the
field's type with fields_get first.