# Odoo

Create, find, update and delete contacts, CRM opportunities, activities and records of any Odoo model, and log notes on records.

## Connect Odoo

1. In the sidebar, open **Connections** and press **Add connection**.
2. Type `odoo` and choose **Odoo**.
3. Fill in the fields. Each one says **Required** or **Optional**.
4. Press **Test and save**. GoRunner checks the connection before it saves anything.

The sheet asks for:

- **Odoo address · Required**: The address you open Odoo at, such as https://mycompany.odoo.com or https://erp.example.de.
- **Database · Optional**: The database name. Empty on Odoo Online uses the subdomain (mycompany); a server with several databases needs it.
- **Username · Optional**: The login (usually the email) the API key belongs to. Needed for Odoo 18 and older (JSON-RPC); Odoo 19 reads the user from the key.
- **API key · Required**: The key from Account Security › New API Key.

Your Odoo address, database and an API key: in Odoo open your profile › Account Security › New API Key (Odoo 19 keys last at most three months, so renew it in time). Odoo Online needs a Custom plan for API access. For Odoo 18 and older also enter the username (login) the key belongs to.

[Connections](https://docs.gorunner.io/build/connections) says how to sign in again, rename or delete it. In a product that embeds GoRunner, **Add connection** can be missing: then [your provider makes connections](https://docs.gorunner.io/embed/customer-connections) for you.

## Start a workflow

Add a trigger and choose **Odoo**. The trigger uses the same connection as the steps.

### On Record Created or Changed

Checks an Odoo model about once a minute and starts a run for each record created (or changed) since the check before. The first check after publishing only takes note of what is there (it starts nothing); changing the trigger starts over the same way. Each change starts one run, at most 100 a minute (the rest follow the minute after); a record changed twice between checks starts one run with its latest values.

- **Model · Required**: The model to watch (such as res.partner for contacts, crm.lead for leads and opportunities).
- **Trigger on · Required**: What starts a run. Options: Record created, Record created or changed. Default: Record created.
- **Only Records Matching · Optional**: Watch only records matching these Odoo conditions, such as [["type", "=", "opportunity"], ["user_id", "=", 2]]. Empty watches every record.
- **Fields to Return · Optional**: Technical field names, comma-separated. Empty returns every field.

A later step can use its data, such as `{{trigger.change_type}}`, `{{trigger.create_date}}`, `{{trigger.display_name}}` and 2 more. See [Use data from earlier steps](https://docs.gorunner.io/build/use-data-from-earlier-steps).

## Do things in Odoo

Add an **Odoo** step, choose a **Resource**, then an **Operation**. Choose a row to see its fields.

- [Contact](https://docs.gorunner.io/apps/odoo#fields-f-contact): Create · Get · Get Many · Update · Delete
- [Opportunity](https://docs.gorunner.io/apps/odoo#fields-f-opportunity): Create · Get · Get Many · Update · Delete
- [Activity](https://docs.gorunner.io/apps/odoo#fields-f-activity): Create · Get · Get Many · Update · Delete
- [Note (chatter)](https://docs.gorunner.io/apps/odoo#fields-f-note): Create · Get Many
- [Custom Resource (any model)](https://docs.gorunner.io/apps/odoo#fields-f-custom): Create · Get · Get Many · Update · Delete

Later steps read a step’s output by its name: see [Use data from earlier steps](https://docs.gorunner.io/build/use-data-from-earlier-steps).

## Limits

- A reply from Odoo can be up to 16 MB (a file download can have its own limit). A larger one fails the step; it is never cut short.
- When Odoo says to slow down (429), the step waits as long as it asks, if the step’s time allows. Otherwise it fails and says when to try again.

Not in your list? See [When an app isn’t here](https://docs.gorunner.io/apps/when-an-app-isnt-here#q-not-in-list).

## For developers

In the API, which calls apps pieces, Odoo is `pieceId: "odoo"` with `actionId: "odoo"`, set by `resource` and an `operation_…` field, such as `operation_activity`. Its trigger is `odootrigger` / `odoo_poll`. [Get an app](https://docs.gorunner.io/api/apps/get-app) returns every field.

It can change something outside the run (`writes_external`). See [How versions and side effects work](https://docs.gorunner.io/apps#q-versions).

### Odoo › Contact

### Create

- **Name · Optional**: The person's or company's name.
- **Email · Optional**
- **Phone · Optional**
- **Is a Company · Optional**: A company rather than a person. Options: Leave as it is, Yes, No. Default: Leave as it is.
- **Company · Optional**: The id of the company contact this person works for.
- **Fields · Optional**: More field values by technical name, beside the fields above, such as {"street": "Hafenstraße 1", "city": "Hamburg"}.

### Get

- **Contact ID · Required**: The contact's id (the number in its Odoo address).
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, email, write_date). Empty returns every field of one record, or the usual fields of a list.

### Get Many

- **Filters · Optional**: Odoo search conditions, such as [["is_company", "=", true], ["city", "ilike", "Hamburg"]]. Several conditions must all match; put "|" before two to match either. Empty lists every contact.
- **Sort · Optional**: Field and direction, comma-separated (such as write_date desc, name). Empty sorts by id.
- **Return All · Optional**: Read every contact, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many contacts to return (1–2000). Default: 50. Shows when **Return All** is off.
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, email, write_date). Empty returns every field of one record, or the usual fields of a list.

### Update

- **Contact ID · Required**: The contact's id (the number in its Odoo address).
- **Name · Optional**: The person's or company's name.
- **Email · Optional**
- **Phone · Optional**
- **Is a Company · Optional**: A company rather than a person. Options: Leave as it is, Yes, No. Default: Leave as it is.
- **Company · Optional**: The id of the company contact this person works for.
- **Fields · Optional**: More field values by technical name, beside the fields above, such as {"street": "Hafenstraße 1", "city": "Hamburg"}.

### Delete

- **Contact ID · Required**: The contact's id (the number in its Odoo address).

### Odoo › Opportunity

### Create

- **Name · Optional**: The opportunity's title.
- **Customer · Optional**: The id of the customer's contact.
- **Email · Optional**
- **Phone · Optional**
- **Expected Revenue · Optional**
- **Probability (%) · Optional**
- **Expected Closing · Optional**
- **Fields · Optional**: More field values by technical name, beside the fields above, such as {"street": "Hafenstraße 1", "city": "Hamburg"}.

### Get

- **Opportunity ID · Required**: The opportunity's id (the number in its Odoo address).
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, email, write_date). Empty returns every field of one record, or the usual fields of a list.

### Get Many

- **Filters · Optional**: Odoo search conditions, such as [["is_company", "=", true], ["city", "ilike", "Hamburg"]]. Several conditions must all match; put "|" before two to match either. Empty lists every opportunity.
- **Sort · Optional**: Field and direction, comma-separated (such as write_date desc, name). Empty sorts by id.
- **Return All · Optional**: Read every opportunity, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many opportunitys to return (1–2000). Default: 50. Shows when **Return All** is off.
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, email, write_date). Empty returns every field of one record, or the usual fields of a list.

### Update

- **Opportunity ID · Required**: The opportunity's id (the number in its Odoo address).
- **Name · Optional**: The opportunity's title.
- **Customer · Optional**: The id of the customer's contact.
- **Email · Optional**
- **Phone · Optional**
- **Expected Revenue · Optional**
- **Probability (%) · Optional**
- **Expected Closing · Optional**
- **Fields · Optional**: More field values by technical name, beside the fields above, such as {"street": "Hafenstraße 1", "city": "Hamburg"}.

### Delete

- **Opportunity ID · Required**: The opportunity's id (the number in its Odoo address).

### Odoo › Activity

### Create

- **Linked Document Model · Optional**: The model of the record the activity is on (such as crm.lead, res.partner).
- **Linked Document · Optional**: That record's id.
- **Activity Type · Optional**: Call, email, meeting, to-do, ….
- **Summary · Optional**
- **Note · Optional**: Details (plain text; line breaks are kept).
- **Due Date · Optional**: YYYY-MM-DD. Empty on create uses the activity type's default.
- **Assigned To · Optional**: The id of the user who does it. Empty assigns the API key's user.
- **Fields · Optional**: More field values by technical name, beside the fields above, such as {"street": "Hafenstraße 1", "city": "Hamburg"}.

### Get

- **Activity ID · Required**: The activity's id (the number in its Odoo address).
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, email, write_date). Empty returns every field of one record, or the usual fields of a list.

### Get Many

- **Filters · Optional**: Odoo search conditions, such as [["is_company", "=", true], ["city", "ilike", "Hamburg"]]. Several conditions must all match; put "|" before two to match either. Empty lists every activity.
- **Sort · Optional**: Field and direction, comma-separated (such as write_date desc, name). Empty sorts by id.
- **Return All · Optional**: Read every activity, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many activitys to return (1–2000). Default: 50. Shows when **Return All** is off.
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, email, write_date). Empty returns every field of one record, or the usual fields of a list.

### Update

- **Activity ID · Required**: The activity's id (the number in its Odoo address).
- **Summary · Optional**
- **Note · Optional**: Details (plain text; line breaks are kept).
- **Due Date · Optional**: YYYY-MM-DD. Empty on create uses the activity type's default.
- **Assigned To · Optional**: The id of the user who does it. Empty assigns the API key's user.
- **Fields · Optional**: More field values by technical name, beside the fields above, such as {"street": "Hafenstraße 1", "city": "Hamburg"}.

### Delete

- **Activity ID · Required**: The activity's id (the number in its Odoo address).

### Odoo › Note (chatter)

### Create

- **Model · Required**: The model of the record (such as res.partner, crm.lead, sale.order).
- **Record ID · Required**: The record's id.
- **Kind · Optional**: An internal note (Log note), or a message the record's followers get by email (Send message). Options: Internal note, Message to followers. Default: Internal note.
- **Text · Required**: The note's text (plain text; line breaks are kept).

### Get Many

- **Model · Required**: The model of the record (such as res.partner, crm.lead, sale.order).
- **Record ID · Required**: The record's id.
- **Return All · Optional**: Read every message, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many messages to return (1–2000). Default: 50. Shows when **Return All** is off.

### Odoo › Custom Resource (any model)

### Create

- **Model · Required**: The Odoo model (such as sale.order, project.task, account.move).
- **Fields · Required**: Field values by technical name, such as {"street": "Hafenstraße 1", "zip": "20457", "city": "Hamburg", "country_id": 57}.

### Get

- **Model · Required**: The Odoo model (such as sale.order, project.task, account.move).
- **Record ID · Required**: The record's id (the number in its Odoo address).
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, state, write_date). Empty returns every field (slower on large models).

### Get Many

- **Model · Required**: The Odoo model (such as sale.order, project.task, account.move).
- **Filters · Optional**: Odoo search conditions, such as [["is_company", "=", true], ["city", "ilike", "Hamburg"]]. Several conditions must all match; put "|" before two to match either. Empty lists every record.
- **Sort · Optional**: Field and direction, comma-separated (such as write_date desc, name). Empty sorts by id.
- **Return All · Optional**: Read every record, page by page (at most 2000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many records to return (1–2000). Default: 50. Shows when **Return All** is off.
- **Fields to Return · Optional**: Technical field names, comma-separated (such as name, state, write_date). Empty returns every field (slower on large models).

### Update

- **Model · Required**: The Odoo model (such as sale.order, project.task, account.move).
- **Record ID · Required**: The record's id (the number in its Odoo address).
- **Fields · Required**: Field values by technical name, such as {"street": "Hafenstraße 1", "zip": "20457", "city": "Hamburg", "country_id": 57}.

### Delete

- **Model · Required**: The Odoo model (such as sale.order, project.task, account.move).
- **Record ID · Required**: The record's id (the number in its Odoo address).

Source: https://docs.gorunner.io/apps/odoo
