@@ -7,32 +7,153 @@ External JSON-2 API
7
7
Odoo is usually extended internally via modules, but many of its features and all of its data are
8
8
also available from the outside for external analysis or integration with various other softwares.
9
9
Part of the :ref: `reference/orm/model ` API is easily available over HTTP via the ``/json/2 ``
10
- endpoint. The actual models, their fields and methods are specific to every database and can be
11
- consulted at the ``/doc `` page.
10
+ endpoint. The actual models, fields and methods available are specific to every database and can be
11
+ consulted on their ``/doc `` page.
12
12
13
+ API
14
+ ===
13
15
14
- Request
16
+ POST a json object at the ``/json/2/<model>/<method> `` URL.
17
+
18
+ Headers:
19
+
20
+ :Autorization: Required, ``bearer `` followed by an API Key.
21
+ :Content-Type: Required, ``application/json; charset=utf-8 ``, other charsets are supported as well.
22
+ :X-Odoo-Database: Optional, the name of the database on which to connect.
23
+ :User-Agent: Recommended when integrating with another software.
24
+
25
+ Body:
26
+
27
+ :ids: a JSON array of record ids on which to call the method.
28
+ :context: a JSON object of additional values like the lang, used when crafting the environment.
29
+
30
+ The body must be a json-object containing the arguments for the model's method. Both ``ids `` and
31
+ ``context `` are special arguments: they are used to craft the environment and recordset on which the
32
+ method is executed.
33
+
34
+ The headers ``Host ``, ``Authorization `` with an API key and ``Content-Type `` are required. The
35
+ ``X-Odoo-Database `` header is only necessary when multiple databases are hosted behind a same
36
+ ``Host ``. A ``User-Agent `` with the name of the software where the request comes from is
37
+ recommended.
38
+
39
+ In case of **success **, a **200 ** status, and the return value of the called method serialized as
40
+ json in the body.
41
+
42
+ In case of **error **, a **4xx **/**5xx ** status, and the error message serialized as a json string in
43
+ the body. The complete traceback is available in the server log, at the same date and time as the
44
+ error response.
45
+
46
+
47
+ Configuration
48
+ =============
49
+
50
+ API Key
51
+ -------
52
+
53
+ An API key must be set in the ``Authorization `` request header, as a bearer token.
54
+
55
+ Create a new API key for a user via :guilabel: `Preferences `, :guilabel: `Account Security `, and
56
+ :guilabel: `New API Key `.
57
+
58
+ .. have the three images appear next to each other
59
+ .. list-table ::
60
+
61
+ * - .. image:: external_api/preferences2.png
62
+ :align: center
63
+
64
+ - .. image:: external_api/account-security2.png
65
+ :align: center
66
+
67
+ - .. image:: external_api/new-api-key.png
68
+ :align: center
69
+
70
+ A description and a duration are needed to create a new api key. The description makes it possible
71
+ to identify the key, and to determine later whether the key is still in use or should be removed.
72
+ The duration determines the lifetime of the key after which the the key becomes invalid. It is
73
+ recommended to set a short duration (typically 1 day) for interactive usage. It is not possible to
74
+ create keys that last for more than 3 months, it means that long lasting keys must be rotated at
75
+ least once every 3 months.
76
+
77
+ The :guilabel: `Generate Key ` creates a 160 bits strong random key. Its value appears on screen, this
78
+ is the only time and place the key is visible on screen. It must be copied, kept secret and stored
79
+ somewhere secure. If it ever gets compromized or lost, then it must be removed.
80
+
81
+ Please refer to OWASP's `Secrets Management Cheat Sheet `_ for further guidance on the management of
82
+ API keys.
83
+
84
+ .. _Secrets Management Cheat Sheet : https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#secrets-management-cheat-sheet
85
+
86
+
87
+ Access Rights
88
+ -------------
89
+
90
+ The JSON-2 API uses the standard :ref: `security <reference/security >` model of Odoo. All operations
91
+ are validated against the access rights, record rules and field accesses of the user.
92
+
93
+ For **interfactive usage **, such as discovering the API or running one-time scripts, it is fine to
94
+ use a **personal account **.
95
+
96
+ For **extended automated usage **, such as an integration with another software, it is recommended to
97
+ create and use **dedicated bot users **.
98
+
99
+ Using dedicated bot users has several benefits:
100
+
101
+ * The minimum required permissions can be granted to the bot, limiting the impact may the API key
102
+ gets compromised;
103
+ * The password can be set empty to disable login/password authentication, limiting the likelihood
104
+ the account gets compromized;
105
+ * The :ref: `reference/fields/automatic/log_access ` use the bot account. No user gets impersonalized.
106
+
107
+
108
+ Database
109
+ --------
110
+
111
+ Depending on the deploiement, the ``Host `` and/or ``X-Odoo-Database `` request headers might be
112
+ required. The ``Host `` header is required on servers where Odoo is installed next to other web
113
+ applications, so a web-server/reverse-proxy is able to route the request to the Odoo server. The
114
+ ``X-Odoo-Database `` header is required when a single Odoo server hosts multiple databases, and that
115
+ :ref: `dbfilter ` wasn't configured to use the ``Host `` header.
116
+
117
+ Most HTTP client libraries automatically set the ``Host `` header using the connection url.
118
+
119
+
120
+ Transaction
121
+ ===========
122
+
123
+ .. note ::
124
+
125
+ Under construction
126
+
127
+
128
+ Example
15
129
=======
16
130
17
- POST a json object at the ``/json/2/<model>/<method> `` URL.
131
+ The following example showcases how to call the ``search_read `` method of the
132
+ :ref: `reference/orm/models/crud ` on a fake database ``mycompany `` hosted on a fake website
133
+ ``https://mycompany.example.com ``.
18
134
135
+ The comprehensive documentation listing the models, fields and methods available in this database
136
+ would be available at the https://mycompany.example.com/doc page.
137
+
138
+ Request
139
+ -------
19
140
20
141
.. tabs ::
21
142
22
143
.. code-tab :: http
23
144
24
145
POST /json/2/res.partner/search_read HTTP/1.1
25
- Host: mycompany.odoo .com
146
+ Host: mycompany.example .com
26
147
X-Odoo-Database: mycompany
27
- Authorization: Bearer 6578616d706c65206a736f6e20617069206b6579
148
+ Authorization: bearer 6578616d706c65206a736f6e20617069206b6579
28
149
Content-Type: application/json; charset=utf-8
29
150
User-Agent: mysoftware python-requests/2.25.1
30
151
31
152
{
32
153
"ids": [],
33
154
"context": {
34
155
"lang": "en_US"
35
- }
156
+ },
36
157
"domain": [
37
158
["name", "ilike", "%deco%"],
38
159
["is_company", "=", true]
@@ -44,21 +165,22 @@ POST a json object at the ``/json/2/<model>/<method>`` URL.
44
165
45
166
import requests
46
167
47
- HOST = "https://mycompany.odoo.com"
48
- DATABASE = "mycompany"
168
+ BASE_URL = "https://mycompany.example.com/json/2"
49
169
API_KEY = ... # get it from a secure location
170
+ headers = {
171
+ "Authorization": f"bearer {API_KEY}",
172
+ "X-Odoo-Database": "mycompany",
173
+ "User-Agent": "mysoftware " + requests.utils.default_user_agent(),
174
+ }
50
175
51
176
response = requests.post(
52
- HOST + "/json/2/res.partner/search_read",
53
- headers={
54
- "Authorization": f"Bearer {API_KEY}",
55
- "X-Odoo-Database": DATABASE,
56
- },
177
+ f"{BASE_URL}/res.partner/search_read",
178
+ headers=headers,
57
179
json={
58
180
"ids": [],
59
181
"context": {
60
182
"lang": "en_US",
61
- }
183
+ },
62
184
"domain": [
63
185
("name", "ilike", "%deco%"),
64
186
("is_company", "=", True),
@@ -72,55 +194,52 @@ POST a json object at the ``/json/2/<model>/<method>`` URL.
72
194
.. code-tab :: javascript
73
195
74
196
(async () => {
75
- const HOST = "https://mycompany.odoo.com";
76
- const DATABASE = "mycompany";
197
+ const BASE_URL = "https://mycompany.example.com/json/2";
77
198
const API_KEY = ; // get it from a secure location
199
+ const headers = {
200
+ "Content-Type": "application/json",
201
+ "Authorization": "bearer " + API_KEY,
202
+ "X-Odoo-Database": DATABASE,
203
+ }
78
204
79
205
const request = {
80
206
method: "POST",
81
- headers: {
82
- "Content-Type": "application/json",
83
- "Authorization": "Bearer " + API_KEY,
84
- "X-Odoo-Database": DATABASE,
85
- },
207
+ headers: headers,
86
208
body: {
209
+ "ids": [],
210
+ "context": {
211
+ "lang": "en_US",
212
+ },
87
213
domain: [
88
214
["name", "ilike", "%deco%"],
89
215
["is_company", "=", true],
90
216
],
91
217
fields: ["name"],
92
218
},
93
219
};
94
-
95
- const response = await fetch(HOST + "/json/2/res.partner/search_read", request );
220
+ const response = await fetch(BASE_URL + "/res.partner/search_read", request);
221
+ const data = await response.json( );
96
222
if (response.ok) {
97
- const data = await response.json();
98
- console.log(data)
223
+ console.log(data);
99
224
} else {
100
- // Handle errors
225
+ // Handle error, data holds the error message as string
101
226
}
102
227
})();
103
228
104
- The body must be a json-object containing the arguments for the model's method. Both ``ids `` and
105
- ``context `` are special arguments: they are used to craft the environment and recordset on which the
106
- method is executed.
107
-
108
- The headers ``Host ``, ``Authorization `` with an API key and ``Content-Type `` are required. The
109
- ``X-Odoo-Database `` header is only necessary when multiple databases are hosted behind a same
110
- ``Host ``. A ``User-Agent `` with the name of the software where the request comes from is
111
- recommended.
112
229
113
- The available models and methods depend on the list of modules that are installed in the database.
114
- The exact list of what's available is accessible on the ``/doc `` page of every database.
230
+ The above example would be equivalent to running::
115
231
232
+ with odoo.sql_db.db_connect('mycompany') as cr:
233
+ env = odoo.api.Environment(cr, uid=..., context={'lang': 'en_US'})
234
+ records = env['res.partner'].search_read(
235
+ domain=[("name", "ilike", "%deco%"), ("is_company", "=", True)],
236
+ fields=["name"],
237
+ )
238
+ return json.dumps(records)
116
239
117
- Response
118
- ========
119
240
120
- Success
121
- -------
122
-
123
- A **200 OK ** status with the method's return value serialized as json in the body.
241
+ Success response
242
+ ----------------
124
243
125
244
.. code :: http
126
245
@@ -131,93 +250,20 @@ A **200 OK** status with the method's return value serialized as json in the bod
131
250
{"id": 25, "name": "Deco Addict"}
132
251
]
133
252
134
- Error
135
- -----
136
-
137
- A **4xx **/**5xx ** status with the error message serialized as a json string in the body.
253
+ Error response
254
+ --------------
138
255
139
256
.. code :: http
140
257
141
258
HTTP/1.1 401 Unauthorized
142
- Date: Fri, 18 Jul 2025 08:33:35 GMT
143
259
Content-Type: application/json; charset=utf-8
144
260
145
261
"Invalid apikey"
146
262
147
- The complete traceback is available in the server log, at the same date as the error response.
148
-
149
-
150
- API Key
151
- =======
152
-
153
- An API key must be set in the ``Authorization `` request header, as a bearer token.
154
-
155
- Create a new API key for a user via :guilabel: `Preferences `, :guilabel: `Account Security `, and
156
- :guilabel: `New API Key `.
157
-
158
- .. have the three images appear next to each other
159
- .. list-table ::
160
-
161
- * - .. image:: external_api/preferences2.png
162
- :align: center
163
263
164
- - .. image:: external_api/account-security2.png
165
- :align: center
166
-
167
- - .. image:: external_api/new-api-key.png
168
- :align: center
169
-
170
- A description and a duration are needed to create a new api key. The description makes it possible
171
- to identify the key, and to determine later whether the key is still in use or should be removed.
172
- The duration determines the lifetime of the key after which the the key becomes invalid. It is
173
- recommended to set a short duration (typically 1 day) for interactive usage. It is not possible to
174
- create keys that last for more than 3 months, it means that long lasting keys must be rotated at
175
- least once every 3 months.
176
-
177
- The :guilabel: `Generate Key ` creates a 160 bits strong random key. Its value appears on screen, this
178
- is the only time and place the key is visible on screen. It must be copied, kept secret and stored
179
- somewhere secure. If it ever gets compromized or lost, then it must be removed.
180
-
181
- Please refer to OWASP's `Secrets Management Cheat Sheet `_ for further guidance on the management of
182
- API keys.
183
-
184
- .. _Secrets Management Cheat Sheet : https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html#secrets-management-cheat-sheet
185
-
186
-
187
- Access Rights
188
- =============
189
-
190
- The JSON-2 API uses the standard :ref: `security <reference/security >` model of Odoo. All operations
191
- are validated against the access rights, record rules and field accesses of the user.
192
-
193
- For **interfactive usage **, such as discovering the API or running one-time scripts, it is fine to
194
- use a **personal account **.
195
-
196
- For **extended automated usage **, such as an integration with another software, it is recommended to
197
- create and use **dedicated bot users **.
198
-
199
- Using dedicated bot users has several benefits:
200
-
201
- * The minimum required permissions can be granted to the bot, limiting the impact may the API key
202
- gets compromised;
203
- * The password can be set empty to disable login/password authentication, limiting the likelihood
204
- the account gets compromized;
205
- * The :ref: `reference/fields/automatic/log_access ` use the bot account. No user gets impersonalized.
206
-
207
-
208
- Database
209
- ========
210
-
211
- Depending on the deploiement, the ``Host `` and/or ``X-Odoo-Database `` request headers might be
212
- required. The ``Host `` header is required on servers where Odoo is installed next to other web
213
- applications, so a web-server/reverse-proxy is able to route the request to the Odoo server. The
214
- ``X-Odoo-Database `` header is required when a single Odoo server hosts multiple databases, and that
215
- :ref: `dbfilter ` wasn't configured to use the ``Host `` header.
216
-
217
- Most HTTP client libraries automatically set the ``Host `` header using the connection url.
218
-
219
-
220
- Transaction
221
- ===========
264
+ Migrating from XML-RPC / JSON-RPC
265
+ =================================
222
266
267
+ .. note ::
223
268
269
+ Under construction
0 commit comments