Skip to main content
Odoo Community Association

REST API for Webhook

Beta License: AGPL-3 ecosoft-odoo/ecosoft-addons

This module provides a standard webhook framework for Odoo with full request/response logging and config-driven outbound push notifications.

Inbound (External → Odoo)

  • 5 REST API routes: create_data, update_data, create_update_data, search_data, call_function

  • Session-based and API Key authentication

  • Friendly relational field format: many2one, many2many, one2many resolved by name or id

  • auto_create support for missing related records

  • Automatic API log creation per request, with configurable per-route toggle

  • Request and response preview (first N characters, configurable) stored on the log record

  • Request and response size (character count) displayed on each log

  • Full payload stored as JSON attachment (accessible via Full Log button) when preview limit exceeded

  • Autovacuum cron to purge old logs, with optional chunk-based deletion

Outbound (Odoo → External)

  • webhook.outbound.rule - config-driven rules: which model + domain → which endpoint

  • webhook.outbound.mixin - add to any model with a single _inherit line; no per-model code required

  • Trigger domain: full Odoo domain expression evaluated after write(); webhook fires only when a record transitions into matching the domain

  • Endpoint source: static URL per rule, or per-record callback_url passed by the external system at create time

  • Payload fields: JSON list supporting field{sub1,sub2} expansion for relational fields - same syntax as search_data

  • Outbound calls logged in API Logs (log_type = send) with success/failed state

Table of contents

Configuration

System Parameters

Go to Settings > Technical > Parameters > System Parameters to adjust the following keys:

Key

Default

Description

webhook.preview_limit

2000

Maximum characters stored in the preview fields. Payloads longer than this are also saved as a full JSON attachment.

webhook.create_data_log

True

Enable logging for /api/create_data

webhook.update_data_log

True

Enable logging for /api/update_data

webhook.create_update_data_log

True

Enable logging for /api/create_update_data

webhook.search_data_log

True

Enable logging for /api/search_data

webhook.call_function_log

True

Enable logging for /api/call_function

webhook.rollback_state_failed

1

Roll back the transaction when the API response is not successful

webhook.rollback_except

1

Roll back the transaction when an unhandled exception occurs

webhook.ignore_checkcompany_model

[]

JSON list of model names excluded from company-scoped record lookup

Outbound Webhook Rules

Go to Settings > Technical > API Configuration > Outbound Webhook Rules to configure outbound push rules.

Field

Description

Model

The Odoo model to watch (e.g. sale.order)

Trigger Domain

Odoo domain evaluated after write(). Webhook fires when a record transitions into matching the domain. Uses the domain widget - select a model first to get field suggestions.

Endpoint Source

Static URL - always POST to the configured URL. Record Callback URL - use the callback_url stored from the inbound request.

Endpoint URL

Required when Endpoint Source is Static URL.

Payload Fields

JSON list of field names to include. Supports field{sub1,sub2} for relational expansion. Leave empty to send {"id": <record_id>} only.

Authorization Header

Optional Authorization header value sent with every outbound request, e.g. Bearer <token>.

Usage

Inbound (External → Odoo)

API Logs

Every API call is logged under Settings > Technical > API Configuration > API Logs. Each log record shows:

  • Request Preview / Response Preview - first N characters of the payload

  • Request Size / Response Size - total character count

  • Full Log button - opens the full JSON attachment when payload exceeds the preview limit

  • Callback URL - URL stored from the inbound request for later outbound push

Authentication

Authenticate via /web/session/authenticate before calling any route:

{
  "jsonrpc": "2.0",
  "method": "call",
  "params": {
    "db": "<db_name>",
    "login": "<username>",
    "password": "<password>"
  }
}

Alternative - API Key: send Authorization: Bearer <api_key> on every request. No session call needed.

Relational Field Format

Field type

Format

Example

many2one

{"<lookup_field>": "<value>"}

{"name": "Customer A"} or {"id": 5}

many2many

{"mode": "add"|"replace", "records": [...]} (mode defaults to "replace")

{"records": [{"name": "Tag1"}]}

one2many

[{<field>: <value>, ...}, ...]

[{"product_id": {"name": "A"}, "qty": 1}]

Multiple many2many items sharing the same lookup field are batched into a single DB query.

API Routes
1. /api/create_data - create a new record

Pass optional callback_url to enable outbound push when the record’s state changes later.

{
  "params": {
    "model": "<model name>",
    "vals": {
      "callback_url": "https://your-system/webhook",
      "payload": {
        "<field1>": "<value1>",
        "<many2one_field_id>": {"name": "<value>"},
        "<many2many_field_ids>": {"mode": "replace", "records": [{"name": "<val1>"}]},
        "<one2many_field_ids>": [
          {"<field>": "<value>", "<nested_m2o_id>": {"name": "<value>"}}
        ]
      },
      "auto_create": {
        "<many2one_field_id>": {"name": "<value>"}
      },
      "result_field": ["<field1>"]
    }
  }
}
2. /api/create_update_data - update if found, create if not
{
  "params": {
    "model": "<model name>",
    "vals": {
      "search_key": {"<key_field>": "<value>"},
      "payload": {
        "<field1>": "<value1>",
        "<many2one_field_id>": {"name": "<value>"}
      },
      "result_field": ["<field1>"]
    }
  }
}
3. /api/update_data - update an existing record
{
  "params": {
    "model": "<model name>",
    "vals": {
      "search_key": {"<key_field>": "<value>"},
      "payload": {
        "<field1>": "<value1>",
        "<many2one_field_id>": {"id": 5},
        "<many2many_field_ids>": {"mode": "add", "records": [{"name": "<val1>"}]}
      },
      "result_field": ["<field1>"]
    }
  }
}
4. /api/search_data - query records

Use field{subfield1,subfield2} to expand relational fields inline.

{
  "params": {
    "model": "<model name>",
    "vals": {
      "payload": {
        "search_field": [
          "<field1>",
          "<m2o_field>{<subfield1>,<subfield2>}",
          "<o2m_field>{<subfield1>}"
        ],
        "search_domain": "[('<field>', '<operator>', '<value>')]",
        "limit": 10,
        "order": "<field1> asc, <field2> desc"
      }
    }
  }
}
5. /api/call_function - call a method on a record
  • method (str): method name

  • parameter (dict, optional): keyword arguments

  • context (dict, optional): merged into env.context before the call

{
  "params": {
    "model": "account.move",
    "vals": {
      "search_key": {"id": 26},
      "payload": {
        "method": "action_post",
        "context": {"lang": "th_TH"}
      }
    }
  }
}
Attaching Files

Add attachment_ids at any payload level:

"attachment_ids": [{"name": "<filename>", "datas": "<base64>"}]

Outbound (Odoo → External)

When Odoo performs an action (confirm, validate, etc.), the outbound webhook automatically POSTs updated record data back to the external system - no per-model code required.

Step 1 - Add mixin to the target model

In any private addon, add one _inherit line:

from odoo import models

class SaleOrder(models.Model):
    _name = "sale.order"
    _inherit = ["sale.order", "webhook.outbound.mixin"]

All outbound behaviour is driven by rules configured in the UI.

Step 2 - Configure an Outbound Webhook Rule

Go to Settings > Technical > API Configuration > Outbound Webhook Rules. See CONFIGURE.md for the full field reference.

Trigger domain examples:

# Simple
[("state", "=", "sale")]

# Multiple conditions
[("state", "=", "done"), ("amount_total", ">", 100)]

# Multiple accepted values
[("state", "in", ["done", "validated"])]

The webhook fires only when a field in the domain is being written and the record matches the full domain after the write. This prevents re-triggering when unrelated fields are edited on an already-matching record.

Payload Fields - relational expansion

Use field{sub1,sub2} syntax (same as search_data) to expand relational fields:

["name", "state", "currency_id{id,name,code}", "order_line{product_id,qty_done,price_unit}"]

Result posted to the external system:

{
  "name": "SO001",
  "state": "sale",
  "currency_id": [{"id": 3, "name": "Thai Baht", "code": "THB"}],
  "order_line": [
    {"product_id": 5, "qty_done": 2.0, "price_unit": 500.0}
  ]
}

many2one fields expand to a list with one item (consistent with search_data behaviour).

Per-record Callback URL

Pass callback_url in the inbound create_data request. Odoo stores it linked to the created record. When the outbound rule fires with Endpoint Source = Record Callback URL, the system looks up that URL and POSTs to it.

{
  "params": {
    "model": "sale.order",
    "vals": {
      "callback_url": "https://ext-system/webhook/so-status",
      "payload": {
        "partner_id": {"name": "ABC Co."},
        "order_line": [{"product_id": {"name": "Product A"}, "product_uom_qty": 1}]
      }
    }
  }
}

When the SO is confirmed → Odoo automatically POSTs to https://ext-system/webhook/so-status.

Outbound Logs

All outbound calls appear in API Logs with Log Type = Send. Failed calls are marked state = failed with the error in the response preview.

Bug Tracker

Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. If you spotted it first, help us to smash it by providing a detailed and welcomed feedback.

Do not contact contributors directly about support or help with technical issues.

Credits

Authors

  • Ecosoft

Contributors

Maintainers

This module is part of the ecosoft-odoo/ecosoft-addons project on GitHub.

You are welcome to contribute.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file odoo_addon_usability_webhooks-18.0.4.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for odoo_addon_usability_webhooks-18.0.4.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8203653ffd427294bd1550658187747b41e8683c34a2b32c225dce181a8b6a6f
MD5 22150f0dae2d33a34c5af4c6962aae8b
BLAKE2b-256 50cd56be86663720a9b027f62042c4c2a62db2afdb4787abfab144de44805f8d

See more details on using hashes here.

Release history Release notifications | RSS feed

18.0.4.1.0

1 file

This release

18.0.4.0.1 This release

1 file

18.0.4.0.0

1 file

18.0.3.0.1

1 file

18.0.3.0.0

1 file

18.0.2.0.0

1 file

18.0.1.0.1

1 file

18.0.1.0.0.2

1 file

15.0.3.0.1

1 file

15.0.3.0.0

1 file

15.0.2.0.0

1 file

15.0.1.2.0

1 file

15.0.1.1.0

1 file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page