Connecting an enterprise ERP to an artificial intelligence agent used to require verbose XML-RPC connectors, fragile session cookie handling, or positional array serialization that large language models (LLMs) frequently misformatted. With the introduction of the External JSON-2 API in Odoo 19, integration architecture enters a new era: every model and public ORM method is exposed through a stateless HTTP contract built around named JSON parameters.

This guide explains how to connect an AI agent to Odoo via the JSON-2 API, which endpoints are accessible, and what you can safely automate in production.

Architecture diagram showing how an AI agent connects to Odoo via the JSON-2 API with security guardrails

Why Odoo's JSON-2 API is built for AI agent tool calling

Legacy integrations relied on /xmlrpc/2/object (execute_kw) or /jsonrpc. For LLM tool calling, those endpoints had two major drawbacks: deeply nested positional lists ([[['is_company', '=', True]], {'fields': ['name']}]) and non-standard HTTP semantics.

The JSON-2 API solves both challenges through four design choices:

  1. Clean URL routing per model and method: Every request targets POST /json/2/<model>/<method>, where <model> is the technical Odoo object (res.partner, sale.order, account.move) and <method> is the ORM or business method (search_read, read_group, create, write).
  2. Stateless Bearer token authentication: A revocable personal API key is passed in the Authorization: Bearer <API_KEY> header. No session_id cookie or CSRF dance is needed.
  3. Named JSON request bodies: Agents pass a flat JSON object (domain, fields, ids, vals_list, context), matching the exact JSON Schema structure expected by modern LLM function calling.
  4. Self-documented /doc endpoint: Every Odoo instance exposes an interactive API explorer at /doc (available on Odoo Custom plans and On-Premise / Odoo.sh deployments).

Step-by-step connection setup

1. Provision a least-privilege service user in Odoo

Never hand an administrator API key to an AI agent. Create a dedicated technical user (e.g., ai-agent@company.ch), assign only the minimum access groups (CRM read/write, draft sales quotes, analytic read), and generate an API key under Preferences → Account Security → New API Key.

2. Calling /json/2/<model>/<method> from Python

Every request includes Authorization, Content-Type: application/json; charset=utf-8, and X-Odoo-Database:

import os
import requests

ODOO_URL = os.environ["ODOO_BASE_URL"]          # e.g. https://erp.company.ch
ODOO_DB = os.environ["ODOO_DATABASE"]           # e.g. company_prod
ODOO_API_KEY = os.environ["ODOO_AGENT_API_KEY"] # Scoped service user API key

def call_odoo_json2(model: str, method: str, payload: dict) -> dict | list:
    """Execute a stateless call against Odoo's JSON-2 API."""
    url = f"{ODOO_URL}/json/2/{model}/{method}"
    headers = {
        "Authorization": f"Bearer {ODOO_API_KEY}",
        "Content-Type": "application/json; charset=utf-8",
        "X-Odoo-Database": ODOO_DB,
        "User-Agent": "21datas-agent-connector/1.0",
    }
    response = requests.post(url, headers=headers, json=payload, timeout=30)
    response.raise_for_status()
    return response.json()

Accessible ORM and workflow endpoints

The JSON-2 API dynamically exposes public methods permitted by the caller's ACLs (ir.model.access) and Record Rules (ir.rule):

JSON-2 endpointKey JSON body fieldsPurpose for an AI agent
POST /json/2/<model>/search_readdomain, fields, limit, offset, orderFilter and fetch records in a single round-trip.
POST /json/2/<model>/read_groupdomain, fields, groupby, lazyCompute SQL-level sums, averages, and counts without flooding LLM context.
POST /json/2/<model>/search_countdomainCount matching records (e.g., overdue invoices).
POST /json/2/<model>/fields_getattributes (string, type, relation, selection)Inspect model schemas and custom x_studio_* fields dynamically.
POST /json/2/<model>/createvals_list, contextCreate new records (CRM leads, draft quotes, project tasks).
POST /json/2/<model>/writeids, valsUpdate specific fields on existing record IDs.
POST /json/2/<model>/message_postids, body, message_type, subtype_xmlidPost internal analysis notes directly into the Odoo chatter.
POST /json/2/sale.order/action_confirmidsTrigger business workflow transitions (confirming a quotation).

What you can truly automate in production (and essential guardrails)

1. High-ROI autonomous capabilities

  • Natural-language analytics with read_group: Never let an LLM fetch 25,000 invoice lines via search_read to sum them in its prompt. By binding a tool to /json/2/account.move/read_group, PostgreSQL computes exact revenue and margin aggregations by month or salesperson and returns a compact summary table.
  • CRM qualification and draft quotation generation (crm.lead & sale.order): When an inbound inquiry arrives, the agent checks res.partner, retrieves customer pricing from product.pricelist, updates crm.lead, and creates a complete draft quotation (state = 'draft') in sale.order.
  • Support triage and chatter summaries (helpdesk.ticket & project.task): The agent inspects incoming tickets, searches technical documentation, checks SLA status, and posts a drafted solution as an internal note via /json/2/helpdesk.ticket/message_post.
  • Assisted timesheet logging (account.analytic.line): Translating Slack updates or calendar events into structured timesheet entries linked to the right project and task.

2. Production guardrails: where human-in-the-loop is mandatory

  1. Disable unlink and autonomous accounting posts: Never grant the agent permission to delete records (unlink) or call action_post on account.move (invoices/journal entries) or account.payment without human approval. Have the agent prepare the draft record and notify the accountant in the chatter.
  2. Wrap JSON-2 behind typed MCP tools: Expose narrow, schema-validated functions (search_customer_invoices, create_draft_quotation) that enforce limit <= 100 rather than raw unconstrained ORM access.
  3. Enforce idempotency: Check external references before calling create so network retries never duplicate partners or orders.

Want to connect your Odoo ERP to governed AI agents or deploy 21brain across your ERP and data engineering stack? Book a meeting or contact our team.

in Data