<!-- BusyBot node reference — https://busybot.net/tools/odoo/ -->

> Node: Odoo (`odoo`) · Action · v1
> Category: Data & Storage · Credentials: Odoo API (`odooApi`)
> Updated: 2026-08-16

# Odoo

> Manage contacts, opportunities, notes, and custom resources in Odoo ERP

## Overview

Odoo is an open-source ERP and CRM platform. This tool uses the Odoo JSON-RPC 2.0 API to perform CRUD operations on Odoo models. It supports built-in resources (Contact, Opportunity, Note) as well as any custom Odoo model. Authentication uses the Odoo login endpoint to obtain a user ID, which is then included in all subsequent data operation requests. The tool supports filtering for list operations on custom resources, and field selection to limit returned data.

**Category:** Data & Storage  
**Tool Name:** `odoo`  
**Version:** 1

**Appearance:** Icon: `si-odoo` | Color: `#714B67`

## Node Type

**Action** — processes input items and produces output

## Input / Output

| Direction | Port(s) |
|-----------|--------|
| Input | `Input` |
| Output | `Output`, `Error` |

## Credentials

This tool requires **Odoo API** credentials.
See the [Credentials Guide](https://busybot.net/credentials/odoo-api/) for setup instructions.

### Resources

| Resource | Value |
|----------|-------|
| Contact | `contact` |
| Custom Resource | `custom` |
| Note | `note` |
| Opportunity | `opportunity` |

### Operations

Each resource carries its own operation selector, and all four offer the same five operations. Choose the resource first, then the operation.

| Resource | Operation | Value | Description |
|----------|-----------|-------|-------------|
| Contact | Create | `create` | Create a contact |
| Contact | Delete | `delete` | Delete a contact by ID |
| Contact | Get | `get` | Read one contact by ID |
| Contact | Get Many | `getAll` | Search contacts and return the matches |
| Contact | Update | `update` | Update a contact by ID |
| Custom Resource | Create | `create` | Create a record in any Odoo model |
| Custom Resource | Delete | `delete` | Delete a record by ID |
| Custom Resource | Get | `get` | Read one record by ID |
| Custom Resource | Get Many | `getAll` | Search records and return the matches |
| Custom Resource | Update | `update` | Update a record by ID |
| Note | Create | `create` | Create a note |
| Note | Delete | `delete` | Delete a note by ID |
| Note | Get | `get` | Read one note by ID |
| Note | Get Many | `getAll` | Search notes and return the matches |
| Note | Update | `update` | Update a note by ID |
| Opportunity | Create | `create` | Create a CRM opportunity |
| Opportunity | Delete | `delete` | Delete an opportunity by ID |
| Opportunity | Get | `get` | Read one opportunity by ID |
| Opportunity | Get Many | `getAll` | Search opportunities and return the matches |
| Opportunity | Update | `update` | Update an opportunity by ID |

### Parameters

Collection sub-fields carry their internal name in backticks, because that name — not the label — is the key you write in a JSON configuration.

#### Contact: Create

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Name (`contactName`) | `string` | Yes | — | The name of the contact to create. Supports expressions like {{ $json.name }}. |
| Additional Fields | `collection` | No | `{}` | Additional fields for the new contact. |
| — Address (`address`) | `fixedCollection` | No | `{}` | The contact's address. Each sub-field below is written to Odoo as its own address field on the contact. |
| — — City (`city`) | `string` | No | — | City name. |
| — — Country ID (`country_id`) | `number` | No | — | Numeric ID of the country in Odoo. Find in Odoo: Contacts > Configuration > Localization > Countries. |
| — — State ID (`state_id`) | `number` | No | — | Numeric ID of the state/province in Odoo. Find in Odoo: Contacts > Configuration > Localization > Fed. States. |
| — — Street (`street`) | `string` | No | — | First address line. |
| — — Street 2 (`street2`) | `string` | No | — | Second address line. |
| — — Zip Code (`zip`) | `string` | No | — | Postal code. |
| — Email (`email`) | `string` | No | — | Email address. |
| — Internal Notes (`comment`) | `string` | No | — | Free-text notes stored on the contact. |
| — Job Position (`function`) | `string` | No | — | Job title. |
| — Mobile (`mobile`) | `string` | No | — | Mobile phone number. |
| — Phone (`phone`) | `string` | No | — | Phone number. |
| — Tax ID (`vat`) | `string` | No | — | Tax identification (VAT) number. |
| — Website (`website`) | `string` | No | — | Website URL. |

#### Contact: Delete

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Contact ID | `string` | Yes | — | The numeric ID of the contact. Supports expressions like {{ $json.contactId }}. |

#### Contact: Get

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Contact ID | `string` | Yes | — | The numeric ID of the contact. Supports expressions like {{ $json.contactId }}. |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return (e.g. "name,email,phone"). Leave empty to return all fields. Find field names in Odoo Settings > Technical > Database Structure > Models > select model > Fields tab. |

#### Contact: Get Many

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Return All | `boolean` | No | `false` | Whether to return all results or only up to a given limit. |
| Limit | `number` | No | `50` | Max number of results to return. _(shown when Return All is `false`)_ |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return (e.g. "name,email,phone"). Leave empty to return all fields. Find field names in Odoo Settings > Technical > Database Structure > Models > select model > Fields tab. |

#### Contact: Update

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Contact ID | `string` | Yes | — | The numeric ID of the contact to update. Supports expressions like {{ $json.contactId }}. |
| Update Fields (`updateFields`) | `collection` | No | `{}` | Fields to update on the contact. |
| — Address (`address`) | `fixedCollection` | No | `{}` | The contact's address. Each sub-field below is written to Odoo as its own address field on the contact. |
| — — City (`city`) | `string` | No | — | City name. |
| — — Country ID (`country_id`) | `number` | No | — | Numeric ID of the country in Odoo. |
| — — State ID (`state_id`) | `number` | No | — | Numeric ID of the state/province in Odoo. |
| — — Street (`street`) | `string` | No | — | First address line. |
| — — Street 2 (`street2`) | `string` | No | — | Second address line. |
| — — Zip Code (`zip`) | `string` | No | — | Postal code. |
| — Email (`email`) | `string` | No | — | Email address. |
| — Internal Notes (`comment`) | `string` | No | — | Free-text notes stored on the contact. |
| — Job Position (`function`) | `string` | No | — | Job title. |
| — Mobile (`mobile`) | `string` | No | — | Mobile phone number. |
| — Name (`name`) | `string` | No | — | New name for the contact. |
| — Phone (`phone`) | `string` | No | — | Phone number. |
| — Tax ID (`vat`) | `string` | No | — | Tax identification (VAT) number. |
| — Website (`website`) | `string` | No | — | Website URL. |

#### Custom Resource: Create

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Custom Resource Model | `string` | Yes | — | The Odoo model name to operate on (e.g. "sale.order", "product.product", "account.move"). Find available models in Odoo Settings > Technical > Database Structure > Models. Supports expressions like {{ $json.model }}. |
| Fields (`fieldsToCreateOrUpdate`) | `fixedCollection` | No | `{}` | Field name-value pairs for the new record. Field names must match Odoo model field names (e.g. "name", "email", "partner_id"). |
| — Field Name (`fieldName`) | `string` | No | — | The Odoo field name. Find available fields in Odoo: Settings > Technical > Database Structure > Models > select model > Fields tab. |
| — New Value (`fieldValue`) | `string` | No | — | The value to set for this field. |

#### Custom Resource: Delete

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Custom Resource Model | `string` | Yes | — | The Odoo model name to operate on (e.g. "sale.order", "product.product", "account.move"). Find available models in Odoo Settings > Technical > Database Structure > Models. Supports expressions like {{ $json.model }}. |
| Custom Resource ID | `string` | Yes | — | The numeric ID of the record. Supports expressions like {{ $json.recordId }}. |

#### Custom Resource: Get

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Custom Resource Model | `string` | Yes | — | The Odoo model name to operate on (e.g. "sale.order", "product.product", "account.move"). Find available models in Odoo Settings > Technical > Database Structure > Models. Supports expressions like {{ $json.model }}. |
| Custom Resource ID | `string` | Yes | — | The numeric ID of the record. Supports expressions like {{ $json.recordId }}. |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return. Leave empty to return all fields. Field names depend on the selected custom resource model. |

#### Custom Resource: Get Many

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Custom Resource Model | `string` | Yes | — | The Odoo model name to operate on (e.g. "sale.order", "product.product", "account.move"). Find available models in Odoo Settings > Technical > Database Structure > Models. Supports expressions like {{ $json.model }}. |
| Return All | `boolean` | No | `false` | Whether to return all results or only up to a given limit. |
| Limit | `number` | No | `50` | Max number of results to return. _(shown when Return All is `false`)_ |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return. Leave empty to return all fields. Field names depend on the selected custom resource model. |
| Filters | `fixedCollection` | No | `{}` | Filter conditions for the search. Each filter has a field name, operator, and value. |
| — Field Name (`fieldName`) | `string` | No | — | The Odoo field name to filter on. |
| — Operator (`operator`) | `options` | No | `equal` | The comparison operator. |
| | | | | Options: `equal` (=), `notEqual` (!=), `greaterThen` (>), `lesserThen` (<), `greaterOrEqual` (>=), `lesserOrEqual` (<=), `like`, `in`, `notIn` (not in), `childOf` (child of) |
| — Value (`value`) | `string` | No | — | The value to compare against. |

#### Custom Resource: Update

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Custom Resource Model | `string` | Yes | — | The Odoo model name to operate on (e.g. "sale.order", "product.product", "account.move"). Find available models in Odoo Settings > Technical > Database Structure > Models. Supports expressions like {{ $json.model }}. |
| Custom Resource ID | `string` | Yes | — | The numeric ID of the record to update. Supports expressions like {{ $json.recordId }}. |
| Update Fields (`fieldsToCreateOrUpdate`) | `fixedCollection` | No | `{}` | Field name-value pairs to update on the record. |
| — Field Name (`fieldName`) | `string` | No | — | The Odoo field name to update. |
| — New Value (`fieldValue`) | `string` | No | — | The new value for this field. |

#### Note: Create

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Memo | `string` | Yes | — | The content of the note. Supports expressions like {{ $json.body }}. |

#### Note: Delete

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Note ID | `string` | Yes | — | The numeric ID of the note. Supports expressions like {{ $json.noteId }}. |

#### Note: Get

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Note ID | `string` | Yes | — | The numeric ID of the note. Supports expressions like {{ $json.noteId }}. |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return (e.g. "memo,create_date"). Leave empty to return all fields. |

#### Note: Get Many

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Return All | `boolean` | No | `false` | Whether to return all results or only up to a given limit. |
| Limit | `number` | No | `50` | Max number of results to return. _(shown when Return All is `false`)_ |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return (e.g. "memo,create_date"). Leave empty to return all fields. |

#### Note: Update

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Note ID | `string` | Yes | — | The numeric ID of the note to update. Supports expressions like {{ $json.noteId }}. |
| Memo | `string` | Yes | — | The updated content of the note. Supports expressions like {{ $json.body }}. |

#### Opportunity: Create

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Name (`opportunityName`) | `string` | Yes | — | The name of the opportunity to create. Supports expressions like {{ $json.dealName }}. |
| Additional Fields | `collection` | No | `{}` | Additional fields for the new opportunity. |
| — Email (`email_from`) | `string` | No | — | Contact email address for the opportunity. |
| — Expected Revenue (`expected_revenue`) | `number` | No | `0` | Expected revenue for the deal. |
| — Internal Notes (`description`) | `string` | No | — | Free-text description stored on the opportunity. |
| — Phone (`phone`) | `string` | No | — | Contact phone number. |
| — Priority (`priority`) | `options` | No | `1` | Priority of the opportunity. |
| | | | | Options: `1`, `2`, `3` |
| — Probability (`probability`) | `number` | No | `0` | Win probability, from 0 to 100. |

#### Opportunity: Delete

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Opportunity ID | `string` | Yes | — | The numeric ID of the opportunity. Supports expressions like {{ $json.opportunityId }}. |

#### Opportunity: Get

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Opportunity ID | `string` | Yes | — | The numeric ID of the opportunity. Supports expressions like {{ $json.opportunityId }}. |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return (e.g. "name,email_from,expected_revenue"). Leave empty to return all fields. |

#### Opportunity: Get Many

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Return All | `boolean` | No | `false` | Whether to return all results or only up to a given limit. |
| Limit | `number` | No | `50` | Max number of results to return. _(shown when Return All is `false`)_ |
| Options | `collection` | No | `{}` | Additional options for the request. |
| — Fields to Include (`fieldsList`) | `string` | No | — | Comma-separated list of field names to return (e.g. "name,email_from,expected_revenue"). Leave empty to return all fields. |

#### Opportunity: Update

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Opportunity ID | `string` | Yes | — | The numeric ID of the opportunity to update. Supports expressions like {{ $json.opportunityId }}. |
| Update Fields (`updateFields`) | `collection` | No | `{}` | Fields to update on the opportunity. |
| — Email (`email_from`) | `string` | No | — | Contact email address for the opportunity. |
| — Expected Revenue (`expected_revenue`) | `number` | No | `0` | Expected revenue for the deal. |
| — Internal Notes (`description`) | `string` | No | — | Free-text description stored on the opportunity. |
| — Name (`name`) | `string` | No | — | New name for the opportunity. |
| — Phone (`phone`) | `string` | No | — | Contact phone number. |
| — Priority (`priority`) | `options` | No | `1` | Priority of the opportunity. |
| | | | | Options: `1`, `2`, `3` |
| — Probability (`probability`) | `number` | No | `0` | Win probability, from 0 to 100. |

#### All Operations

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Max Concurrency | `number` | No | `10` | Maximum number of items to process concurrently. |

## Output Data

The Odoo record **is** the output item. Whatever the API returns is merged into the item JSON at the top level, so a record field named `email` is addressable downstream as `{{ $json.email }}`. The rest of the input item's JSON passes through unchanged except where a record field overwrites it, and binary data is forwarded.

| Operation | Fields merged onto the output item | Items produced per input item |
|-----------|------------------------------------|-------------------------------|
| `create` | `id` — the numeric ID Odoo assigned to the new record | One |
| `get` | The record's fields, or only the ones named in Fields to Include | One |
| `getAll` | Each matching record's fields, or only the ones named in Fields to Include | **One per matching record** — a Get Many that finds 200 records turns one input item into 200 output items. No matches yields a single item with its JSON unchanged |
| `update` | `id` — the ID of the record that was updated | One |
| `delete` | `success` (`true`) | One |

Two things to plan around:

- **Get Many fans out.** Every downstream node sees one item per record, not one item holding an array. Set Return All off and use Limit while you are building, then switch it on once the shape of the data is settled.
- **ID parameters are numeric strings.** Contact ID, Opportunity ID, Note ID and Custom Resource ID must resolve to a whole number; anything else fails that item before the request is sent.

## Usage Examples

- Create a new contact in Odoo
- List all CRM opportunities
- Update an Odoo note by ID
- Delete a custom resource record
- Get all contacts with specific fields

## Example Configuration

Create a contact with an address and the usual detail fields:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "contact",
    "operation": "create",
    "contactName": "John Doe",
    "additionalFields": {
      "email": "john.doe@example.com",
      "phone": "+1-555-0123",
      "mobile": "+1-555-0124",
      "function": "Sales Manager",
      "website": "https://example.com",
      "vat": "US123456789",
      "comment": "Important client contact",
      "address": {
        "value": {
          "street": "123 Main St",
          "street2": "Suite 100",
          "city": "New York",
          "state_id": 47,
          "zip": "10001",
          "country_id": 233
        }
      }
    }
  }
}
```

Read one contact and return only the fields you care about:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "contact",
    "operation": "get",
    "contactId": "123",
    "options": {
      "fieldsList": "name,email,phone,mobile"
    }
  }
}
```

List the first 50 contacts:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "contact",
    "operation": "getAll",
    "returnAll": false,
    "limit": 50,
    "options": {
      "fieldsList": "name,email,phone"
    }
  }
}
```

Update a contact, including its address:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "contact",
    "operation": "update",
    "contactId": "123",
    "updateFields": {
      "name": "John Smith",
      "email": "john.smith@example.com",
      "phone": "+1-555-9999",
      "mobile": "+1-555-8888",
      "function": "Senior Sales Manager",
      "website": "https://newsite.com",
      "vat": "US987654321",
      "comment": "Updated contact information",
      "address": {
        "value": {
          "street": "456 Oak Ave",
          "street2": "Floor 5",
          "city": "Boston",
          "state_id": 22,
          "zip": "02101",
          "country_id": 233
        }
      }
    }
  }
}
```

Delete a contact:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "contact",
    "operation": "delete",
    "contactId": "123"
  }
}
```

Create a CRM opportunity:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "opportunity",
    "operation": "create",
    "opportunityName": "Big Sales Deal",
    "additionalFields": {
      "email_from": "client@bigcompany.com",
      "phone": "+1-555-0200",
      "expected_revenue": 50000,
      "probability": 75,
      "priority": "2",
      "description": "Major client interested in our enterprise solution"
    }
  }
}
```

Read one opportunity:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "opportunity",
    "operation": "get",
    "opportunityId": "456",
    "options": {
      "fieldsList": "name,expected_revenue,probability,stage_id"
    }
  }
}
```

Move an opportunity forward:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "opportunity",
    "operation": "update",
    "opportunityId": "456",
    "updateFields": {
      "name": "Confirmed Big Sales Deal",
      "expected_revenue": 75000,
      "probability": 90,
      "priority": "3",
      "description": "Deal confirmed, moving to final negotiations"
    }
  }
}
```

Create a note:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "note",
    "operation": "create",
    "memo": "Important meeting notes from client call on 2024-01-15"
  }
}
```

Replace a note's content:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "note",
    "operation": "update",
    "noteId": "789",
    "memo": "Updated meeting notes with additional action items"
  }
}
```

Create a record in a model that has no built-in resource — here a sales order:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "custom",
    "customResource": "sale.order",
    "operation": "create",
    "fieldsToCreateOrUpdate": {
      "fields": [
        { "fieldName": "partner_id", "fieldValue": "123" },
        { "fieldName": "date_order", "fieldValue": "2024-01-15" },
        { "fieldName": "amount_total", "fieldValue": "1500.00" }
      ]
    }
  }
}
```

Search a custom model with two filter conditions:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "custom",
    "customResource": "product.product",
    "operation": "getAll",
    "returnAll": false,
    "limit": 20,
    "options": {
      "fieldsList": "name,default_code,list_price,categ_id"
    },
    "filterRequest": {
      "filter": [
        { "fieldName": "active", "operator": "equal", "value": "true" },
        { "fieldName": "list_price", "operator": "greaterThen", "value": "100" }
      ]
    }
  }
}
```

Update a record in a custom model:

```json
{
  "type": "odoo",
  "parameters": {
    "resource": "custom",
    "customResource": "account.move",
    "operation": "update",
    "customResourceId": "999",
    "fieldsToCreateOrUpdate": {
      "fields": [
        { "fieldName": "ref", "fieldValue": "INV/2024/001" },
        { "fieldName": "invoice_date", "fieldValue": "2024-01-15" },
        { "fieldName": "state", "fieldValue": "posted" }
      ]
    }
  }
}
```

### Error Handling

| Mode | Behavior |
|------|----------|
| **stop** | Halts workflow on first error |
| **continue** | Skips failed items, passes successful ones through |
| **errorPort** | Routes failed items to Error output port |

## Tips

Manage contacts, opportunities, notes, and custom resources in the Odoo ERP platform via JSON-RPC.

### Error Prevention

- Always verify field names match Odoo model definitions
- Ensure numeric IDs are passed as strings for ID parameters
- Use proper data types for field values (strings for text, numbers for numeric fields)