A demo is not an integration
A demo proves that two systems can exchange data once, with clean input, while someone is watching. Production is different. Input is messy. The network drops. A record is sent twice. Someone changes a field name. The person who built it goes on holiday.
| Working demo | Supportable production integration | |
|---|---|---|
| Input | Clean test records | Real data, including incomplete and unexpected values |
| Failure | Fix it by hand | Retried, logged and escalated automatically |
| Duplicates | Not considered | Prevented by design |
| Visibility | Someone watches it run | Monitoring and alerts |
| Ownership | The person who built it | A named process owner and a support agreement |
| Change | Edit it live | Versioned, tested and deployed deliberately |
Most of the cost of an integration is in the right-hand column. That is where the value is too, because an integration that fails silently creates work that is harder to find than the manual work it replaced.
What n8n is and how it connects to Odoo
n8n is a workflow automation platform. A workflow is a series of steps, called nodes, that runs when something triggers it.
n8n includes a built-in Odoo node. According to n8n's documentation, it supports four resources: contact, custom resource, note and opportunity. For each, it can create, delete, get, get all and update. The custom resource option is the important one for ERP work, because it lets a workflow read and write other Odoo models, such as projects, timesheets, purchase orders or products, using the model's technical name.
On the Odoo side, automation rules can send a webhook notification when a record changes, and can be triggered by an incoming webhook. That gives two directions of travel: Odoo telling n8n that something happened, and n8n writing to Odoo.
Where the logic should live
A common design question is whether a rule belongs in Odoo or in the workflow.
| Put it in Odoo when | Put it in n8n when |
|---|---|
| It is a business rule about Odoo records, such as an approval threshold | It concerns moving or transforming data between systems |
| It must apply no matter how the record is created | It depends on another system's data or timing |
| Finance or operations need to see and audit it | It is about retries, queuing or routing between tools |
Business rules that live only in an integration are easy to forget. When in doubt, keep the rule with the system of record and let the workflow carry data.
Decide ownership before you build anything
The first design document is a table, not a workflow. For every field that moves, record which system owns it.
| Field | Owner | Flows to | If the two disagree |
|---|---|---|---|
| Employee name and ID | Odoo | Field app | Odoo wins |
| Project and cost code | Odoo | Field app | Odoo wins |
| Clock-in and clock-out time | Field app | Odoo, after approval | Field app wins until approved, then Odoo |
| Approval status | Field app | Odoo | Only approved entries are sent |
| Hourly cost | Odoo | Not sent | Stays in Odoo |
This table is an illustration with synthetic field names. The principle is that every field has exactly one owner, and the losing side is never edited directly. When ownership is unclear, two systems slowly drift apart and nobody can say which is right.
How data should move: four patterns
| Pattern | How it works | Good for | Watch for |
|---|---|---|---|
| Webhook | The source system calls the integration when an event happens | Near real-time updates, low volume per event | A missed call is lost unless the sender retries |
| Scheduled sync | The integration runs on a timetable and processes a batch | Nightly or hourly consolidation, reports | Delay between event and update |
| Polling | The integration asks the source for changes since the last run | Sources that cannot send webhooks | Needs a reliable "changed since" marker |
| Queue | Events are stored in order and processed one at a time | Bursts of volume, ordering, safe retries | One more component to run and monitor |
Many production designs combine them. A webhook gives speed, a queue absorbs bursts and allows retries, and a scheduled reconciliation catches anything that was missed. The reconciliation matters. It is the step that tells you the two systems still agree.
Example: field time to Odoo, with synthetic data
In NGYN's construction ERP case study, field crews clock in through a workforce app and the hours reach payroll and job costing in Odoo through an integration built on n8n. The pattern below is an anonymized reconstruction. Names, numbers and identifiers are synthetic.
- Employee and project syncOn a schedule, the integration reads active employees, projects and cost codes from Odoo and updates the field app, so crews can only select valid ones.
- Clock-in and clock-outA crew member records time in the field app against a project and cost code.
- Supervisor approvalA supervisor approves the entry in the field app. Only approved entries are eligible to send.
- Event receivedThe field app notifies the integration. The event is placed on a queue with its unique entry ID.
- ValidationThe integration checks that the employee, project and cost code exist and are active in Odoo, the hours are within allowed limits, and the date is in an open period.
- Duplicate checkThe integration looks for an existing Odoo timesheet line with the same external entry ID. If one exists, it updates or skips, and does not create a second line.
- Write to OdooA timesheet line is created against the project and cost code, carrying the external entry ID.
- Log and confirmThe run is logged with the entry ID, result and time. Failures go to an exception queue.
- Daily reconciliationA scheduled job compares approved hours in the field app with hours in Odoo for the day and reports any difference.
An illustrative event, with synthetic values:
| Field | Example value |
|---|---|
| External entry ID | FT-000482 |
| Employee reference | EMP-0117 |
| Project reference | PRJ-2417 |
| Cost code | 03-CONCRETE |
| Date | 2026-09-14 |
| Hours | 8.5 |
| Status | Approved |
What makes this supportable is not the happy path. It is steps five, six, eight and nine: validation, duplicate prevention, logging and reconciliation.
The controls every production integration needs
Validation
Check data before it is written. Does the referenced record exist? Is it active? Is the value in range? Is a required field present? Reject and report anything that fails, with a message a person can act on. Never let the system of record absorb data it should have refused.
Mapping
Write down how each source field maps to each destination field, including units, time zones, rounding and status values. Keep the document with the workflow. Most integration disputes are mapping questions that were never written down.
Idempotency and deduplication
Idempotency means that processing the same event twice has the same effect as processing it once. It is the single most important property of an integration, because retries and resends will happen. The usual method is to carry a unique external ID from the source into Odoo and check for it before creating a record.
Retries
Temporary failures such as a timeout or a brief outage should be retried automatically, with a growing delay and a maximum number of attempts. Permanent failures, such as a missing project, should not be retried. They go to a person.
Exception queue and ownership
Every failed item needs a place to wait and a person responsible for it. The exception queue should show what failed, why, and what to do. Name the owner. A shared inbox is not an owner.
Audit logging
Log every run: what was received, what was written, the result, and when. Keep the logs long enough to answer a payroll or billing question months later. Do not log secrets or more personal data than you need.
Monitoring and alerts
Three alerts cover most problems: a run failed, the exception queue is growing, and nothing has run when something should have. The third one catches silent failures, which are the dangerous kind.
Temporary and permanent failures
Treating every failure the same way is a common fault. They need different handling.
| Failure | Example | Handling |
|---|---|---|
| Temporary | Timeout, brief outage, rate limit reached | Retry with increasing delay, up to a limit |
| Permanent, data | Project does not exist, date in a closed period, value out of range | Do not retry. Send to the exception queue with a clear reason |
| Permanent, configuration | Credential expired, field renamed after an upgrade | Stop, alert the technical owner, and hold new events in the queue |
| Partial | Three of five lines written before a failure | Design each write to be repeatable, then retry safely |
Volume and pace
Decide how much the integration will carry on its busiest day, not its average one. Large batches should be split into smaller ones. The integration should respect the limits of both systems. A queue lets you slow down without losing work.
Security and access
Keep this conceptual and strict.
- Dedicated integration user. The integration signs in to Odoo as its own user, not as a person. That user has only the access the integration needs.
- Secrets stay in the credential store. API keys and passwords are stored in n8n's credentials or a secrets manager. They are never written into workflow steps, documents, tickets or chat messages.
- Encrypted transport. All calls use HTTPS.
- Verified webhooks. Incoming calls are checked with a shared secret or signature so that only the expected sender is accepted.
- Rotation. Credentials are rotated on a schedule and when someone with access leaves.
- Least data. Send only the fields the destination needs.
This guide does not publish real endpoints, credentials or client configuration, and an integration document you share outside your team should not either.
How authentication works, in concept
The integration proves its identity to each system with a credential. For Odoo, that is a dedicated user and an API key or password held in the workflow platform's credential store. For the other system, it is usually an API key or a token issued by that system. Incoming webhooks are verified with a shared secret or a signature.
Three practices keep this safe. Give each integration its own credentials so one can be revoked without affecting others. Give the Odoo user access only to the models and companies it needs. And record who can view or change credentials, because that list is part of your access control.
Testing, deployment and versioning
- Test environment. Build and test against a copy of Odoo, not the live database.
- Test cases. Include the normal case, a duplicate, a missing reference, an out-of-range value, an outage in the middle of a run and a late correction.
- Acceptance. The process owner signs off on the results, not only the developer.
- Versioning. Keep workflow versions so a change can be reviewed and rolled back.
- Deployment. Changes go live deliberately, outside peak hours, with a way to pause.
- Upgrades. When Odoo or the other system is upgraded, the integration is retested. Field and model changes are the usual cause of post-upgrade failures.
Who supports it
Decide this before go-live.
- Who is the business owner of the process?
- Who receives alerts, and during which hours?
- Who can pause the integration?
- What is the expected response time for a failure?
- Where is the documentation, and who keeps it current?
NGYN's Service Level Agreement describes how requests are prioritized. An integration that blocks payroll or shipping is treated as urgent. If you are deciding whether to build an integration yourself or bring in help, when you need an Odoo consultant explains where the risk sits.
Production-readiness checklist
- Every field has a documented owner and direction.
- The field mapping is written down, including units, time zones and status values.
- Incoming data is validated before it is written to Odoo.
- Each record carries a unique external ID, and duplicates are prevented.
- Temporary failures are retried with a limit. Permanent failures go to an exception queue.
- The exception queue has a named owner.
- Every run is logged with enough detail to answer a question later.
- Alerts exist for failures, a growing queue and missed runs.
- A reconciliation compares the two systems on a schedule.
- The integration uses a dedicated Odoo user with minimum access.
- Secrets are stored in a credential store and are not in workflows or documents.
- Incoming webhooks are verified.
- There is a test environment and a written set of test cases.
- The process owner has signed off on test results.
- Workflow versions are kept and a rollback has been tried.
- Support hours, response times and the pause procedure are agreed.
If a proposal cannot answer most of these, it describes a demo.
The documentation a production integration should have
Ask for these before you sign off. They are what lets someone other than the builder support it.
- The ownership and mapping tables.
- A plain-language description of each workflow and what triggers it.
- The list of alerts and who receives them.
- The exception-handling procedure, with examples.
- The test cases and their results.
- The pause, rollback and recovery steps.
- A change log.
When not to integrate
Integration is not always the answer. Consider alternatives when:
- The second system is not worth keeping. Moving the process into Odoo removes the integration entirely.
- Volume is tiny. A weekly import of ten rows may not justify the build and support.
- The process is not stable. Fix it first. Our guide on how to choose an automation candidate helps decide.
- Ownership cannot be agreed. Without an owner for each field, an integration will make the disagreement worse.
For where integration sits among standard features, rules and AI, see the Odoo automation and practical AI hub.
Frequently asked questions
Can n8n work with any Odoo model?
The n8n Odoo node supports contacts, opportunities, notes and a custom resource option. The custom resource option lets a workflow work with other models by their technical name. Complex operations may need additional steps or Odoo-side logic.
Should we use webhooks or a scheduled sync?
Use webhooks when updates should arrive quickly and the sender can retry. Use a scheduled sync for batch consolidation. In either case, add a scheduled reconciliation so missed events are found.
What happens if Odoo is down when an event arrives?
In a design with a queue and retries, the event waits and is retried. If it still fails after the limit, it moves to the exception queue and the owner is alerted. Without those, the event is lost.
How do we stop the same record being created twice?
Carry a unique ID from the source system into Odoo and check for it before creating a record. This is idempotency, and it should be designed in from the start.
Who maintains the integration after go-live?
That should be agreed before go-live: a business owner for the process, a technical owner for the workflow, and a support arrangement with response times.
Does an integration need to be rebuilt when Odoo is upgraded?
Not usually rebuilt, but it must be retested. Field or model changes between versions are a common cause of failures after an upgrade.
Next step
If you have an integration in mind, or one that already worries you, bring it to a free 30-minute ERP fit call. We will go through ownership, failure handling and support, and tell you what we would change.
Sources and review
- n8n Odoo node documentation, n8n, for supported resources and operations.
- Odoo automation rules, Odoo 17 documentation, for webhook triggers and webhook notifications.
- NGYN's published construction ERP case study for the field-time integration pattern. The example in this guide is rebuilt with synthetic data. It contains no client records, credentials or endpoints.
- The architecture and checklist are NGYN's working practice, not a vendor standard.
Published October 2026. Last reviewed October 2026 by NGYN Solutions Inc.. Product capabilities change between Odoo versions, so confirm version-specific details against the linked documentation before relying on them.