top of page
maesn 2.png

Understanding Odoo’s contact logic and Why It Can Break Your Data

  • Writer: Dr. Themo Voswinckel
    Dr. Themo Voswinckel
  • Jul 24
  • 4 min read

Updated: Aug 1


Visual showing DATEV and SaaS intgration

Odoo is a powerful CRM and ERP system, but its contact data model can lead to complications.


In most CRM or ERP systems, companies and contacts are stored as separate entities, often linked by an explicit relationship. Salesforce or HubSpot, for example, has a clear Account and Contact structure.


This separation makes it easier to maintain data integrity, sync relationships, and build well-structured CRM systems. Odoo, however, stores everything - companies, people, contacts - in a single model called res.partner.


In this post, we’ll break down:

  • How Odoo’s contact model works

  • Why it creates integration challenges

  • How to handle it properly if you’re syncing data


Odoo’s res.partner Model


In Odoo, every contact, whether it is a company or a person, is stored in the same model: res.partner.


There are two key fields that define what type of contact a record represents:


  • is_company: a boolean flag that indicates whether the record is a company (true) or a person (false)

  • parent_id: if set, this links a person to their associated company


In practice, this means:

  • A contact person with a parent_id refers to the company they belong to

  • A contact person without a parent_id is an independent contact

  • Companies have is_company set to true and typically do not have a parent_id


However, Odoo’s API responses do not separate persons from companies automatically.

Both types appear together in list queries unless you specifically filter for is_company or check for parent_id.


That’s why processing contact data from Odoo can get messy, especially if your system needs a clear separation between companies and people, like most ERP or CRM systems do. The way to achieve that with Odoo is by using the is_company flag and the parent_id relationship.


We’ll explain in detail how to apply this logic in section IV.


Why  res.partner Can Break Your Data?


Without the right logic in place, syncing contact data from Odoo can easily go wrong:

  • People may be classified as companies in your system

  • Companies might appear without their associated contacts

  • The relationship between people and companies gets lost, meaning your system cannot represent who works where


This does not just create messy data, it directly impacts data quality:

  • Attribute mismatches: company-specific fields might accidentally end up on contact records, and vice versa

  • Incomplete records: some information could get lost entirely if it does not fit the assumed structure of your system. For example, a personal LinkedIn profile might mistakenly be attached to a company or skipped entirely if the person-to-company link wasn’t mapped.


Example:

If you treat every contact in Odoo as a standalone entity:

  • A contact person with a parent_id pointing to a company would still be synced as an independent company

  • This could lead to the same company being duplicated multiple times, once for each associated person


The result is a broken data foundation that is hard to trust or work with across CRM, marketing, or analytics systems.


How to Handle Odoo’s Contact Logic?

To sync Odoo contact data reliably, here’s the logic you need to implement:


  1. Check is_company

    1. Use this flag to determine if the record should be treated as a company or a person

  2. Use parent_id to map relationships

    1. If parent_id is present, the contact is linked to a company

    2. If it is missing, the record is either an independent contact or a company (based on is_company)

  3. Implement conditional sync logic

    1. For reads:

      1. Apply logic to distinguish persons and companies

      2. Create clear links between persons and their parent company

    2. For writes:

      1. Respect these relationships when creating or updating records to avoid data conflicts or duplication

  4. Be mindful when querying

    1. List queries will always return a flat mix of persons and companies

    2. Always post-process the data to structure it meaningfully before syncing or storing



This approach is based on the real-world experience of our dev team.


The Easy Way to Handle Odoo Contact Sync Issues


We built a unified logic layer in our Maesn Odoo integration that handles all of this complexity for you:

  • Automatically separates companies from persons

  • Links persons to their companies using parent_id

  • Prevents duplicates and ensures proper classification of entities

As a result, when you sync contact data from Odoo via Maesn, you get a structured and usable format, without needing to decode the res.partner logic yourself.


It also means handling Odoo data is just as easy and consistent as with any other API we support. You can integrate and maintain Odoo contact data alongside your other systems, without custom workarounds or constant adjustments.


If you don’t have the time or patience to build this logic yourself, we’ve already done the work.


Summary / TL;DR


  • Odoo’s res.partner model stores both companies and people without clear separation

  • To sync correctly:

  • Use is_company to classify entity type

  • Use parent_id to link persons to companies

  • Without this logic, your sync will create messy data, duplicates, or attribute mismatches

  • Or, if you want to skip the hassle, you can rely on Maesn’s Odoo integration — structured, production-ready, and unified like any modern API




 
 

Browse more

DATEV API visual
Your SaaS
Maesn's magic
Your integrations

Start your API integration

Grow faster with Maesn by integrating your SaaS to DATEV and more with one unified API.

paywise.png
yokoy.png
hibob.png
Trusted by winning dev teams
bottom of page