Naar hoofdinhoud
Automatisering · n8n en Odoo

n8n en Odoo: wat automatiseer je met een flow en wat vraagt een module

n8n is geschikt voor wat er rond Odoo gebeurt; wat de bedrijfsstatus binnen Odoo wijzigt, vraagt een module. De grens, met JSON-RPC voorop en echte antwoorden uit een lab met Odoo 19 en n8n 2.30.6.

Odoo-dashboard: waar de records van een n8n-flow terechtkomen en waar je controleert of ze goed zijn aangekomen

n8n is geschikt voor wat er rond Odoo gebeurt: een extern formulier ophalen, een chat op de hoogte brengen, een dagelijks rapport opstellen. Wat de bedrijfsstatus binnen Odoo wijzigt (prijzen, voorraadreserveringen, validaties van leveringen, afletteren van betalingen) vraagt een module. De grens zie je pas als je beide uitvoert tegen een echte Odoo: dit artikel komt uit een eigen lab met Odoo 19.0-20260630 en n8n 2.30.6.

Kerngedachte: een flow die de Odoo-API aanroept, voert de interface niet uit. Hij kan een 200 met een wizard erin ontvangen en denken dat hij een levering heeft gevalideerd die nog open staat.

Hoe n8n met Odoo praat: vier wegen, niet één

  • XML-RPC: /xmlrpc/2/common om te authenticeren en /xmlrpc/2/object voor execute_kw. Die uit de documentatie.
  • JSON-RPC: een POST /jsonrpc met service, method en args. Dezelfde service in JSON.
  • Websessie: /web/session/authenticate en /web/dataset/call_kw met de cookie. Wat je browser doet.
  • De JSON-2-API, alleen in Odoo 19: POST /json/2/<modelo>/<método> met Authorization: bearer <clave API> en X-Odoo-Database. Zonder sessie: de argumenten gaan als benoemde velden mee, context inbegrepen.

De eerste drie werken nog in 19, maar de server waarschuwt in de log: "The /xmlrpc, /xmlrpc/2 and /jsonrpc endpoints are deprecated in Odoo 19 and scheduled for removal in Odoo 22". Een nieuwe flow tegen een 19 zou via /json/2 moeten lopen; als hij ook 17 en 18 bedient, via de sessie.

# Sesion + call_kw: funciona igual en 17, 18 y 19.
POST /web/session/authenticate
 {"params":{"db":"lab","login":"n8n_bot2","password":"..."}}
-> 200 {"result":{"uid":6,"server_version":"19.0-20260630"}}   # + cookie

POST /web/dataset/call_kw          # con esa cookie
 {"params":{"model":"crm.lead","method":"create",
            "args":[{"name":"Lead web","type":"lead"}],
            "kwargs":{"context":{"lang":"es_ES"}}}}
-> 200 {"result": 10}

# Clave API en la cabecera, sin sesion: solo Odoo 19.
POST /json/2/crm.lead/create
Authorization: bearer <clave>     X-Odoo-Database: lab
 {"vals_list":[{"name":"Lead via /json/2 (API key)"}]}
-> 200 [9]

# Sin cabecera -> 401 "User not authenticated, use an API Key with a
#                 Bearer Authorization header."
# Metodo privado -> 403 "Private methods (such as
#                 'crm.lead._compute_display_name') cannot be called remotely." 

De Odoo-node van n8n 2.30.6 kiest voor je op basis van de credential: die met API-sleutel gaat via /json/2; de klassieke gaat via /jsonrpc met execute, positioneel, die kwargs niet accepteert en geen context kan meegeven. De credential met API-sleutel waarschuwt bovendien dat hij "Odoo 19+ and a Custom pricing plan" vereist.

De HTTP Request-node, zoals hij werd opgeleverd

Let op waar de sleutel niet staat: de body bevat alleen gegevens en de header Authorization wordt gezet door een n8n-credential, die apart wordt versleuteld en geroteerd.

// Lineas del nodo real, copiadas de `n8n export:workflow`.
"type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2,
"url": "http://odoo:8069/json/2/crm.lead/create",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": { "parameters": [
    { "name": "X-Odoo-Database", "value": "lab" } ] },
"jsonBody": "={{ JSON.stringify({ vals_list: [{ name: 'Web: ' + $json.body.empresa, contact_name: $json.body.nombre, email_from: $json.body.email, description: $json.body.mensaje, type: 'lead' }] }) }}",
"credentials": { "httpHeaderAuth": { "name": "Odoo lab - API key (header)" } }
// La clave no esta aqui: la pone esa credencial.

De flow komt ook niet binnen als beheerder, maar als technische gebruiker met precies de juiste groepen en de limiet die Odoo 19 aan zijn sleutel oplegt:

# Usuario tecnico nuevo (solo grupo de usuario interno):
POST /json/2/crm.lead/create
-> 403 "No puede crear informes 'Lead' (crm.lead) ...
            - Sales/Administrator
            - Sales/User: Own Documents Only"
# Tras anadirle sales_team.group_sale_salesman:  -> 200

# Su clave API tampoco dura lo que uno quiera:
_generate(..., +200 dias) -> "No puede exceder 90.0 dias."
_generate(..., sin fecha) -> "La clave API debe tener una
                              fecha de vencimiento"

Die limiet van 90 dagen is de datum waarop je flow ophoudt te werken zonder dat iemand iets aanraakt. Noteer hem op de dag dat je de sleutel aanmaakt.

Vijf automatiseringen die wel in een flow passen

Ze hebben allemaal hetzelfde gemeen: het feit heeft zich al voorgedaan en de flow verplaatst het alleen.

GevalTriggerAanroep naar Odoo
Lead via een extern formuliern8n-webhookcrm.lead / create
Chatmelding bij het valideren van een leveringOdoo-automatisering met webhook-actieGeen: Odoo pusht
Contacten naar een marketingtoolGepland, elke nachtres.partner / search_read op write_date
Waarschuwing bij lage voorraadGepland, elke ochtendproduct.product / search_read van qty_available
Dagelijks rapport voor de directieGeplandread_group op sale.order

Het tweede geval heeft een addertje. De webhook-actie verstuurt _model, _id en de naam van de actie, en is "fire and forget": een POST van een seconde, zonder herpoging. In 19 gaat hij na de commit; in 17 en 18 zit hij binnen de transactie, dus een trage n8n houdt de gebruiker op.

# Accion de servidor state='webhook' al crear un lead.
INFO    Webhook call to http://n8n:5678/webhook/odoo-lead
INFO    Webhook call to http://n8n:5678/webhook/odoo-lead - succeeded

# Apuntando a un flujo borrado (el lead se crea igual):
WARNING Webhook call failed: 404 Client Error: Not Found for url:
        http://n8n:5678/webhook/flujo-borrado
WARNING Webhook call timed out after 1s - it may or may not have failed.

Vijf die niet kunnen, en de precieze reden

  1. Prijzen of kortingen berekenen. Odoo berekent ze vanuit de prijslijst; berekent de flow ze extern, dan heb je bij een gewijzigde prijslijst twee waarheden.
  2. Voorraad reserveren voor meerdere kanalen. Odoo lost de race binnen één transactie op; een flow die apart leest, beslist en schrijft, verkoopt te veel.
  3. Betalingen afletteren. Koppelen en boeken horen bij elkaar: gebeurt het ene buiten en het andere binnen Odoo, dan laat een netwerkonderbreking een halve afletterbewerking achter.
  4. Alles wat iemand gaat controleren. De geschiedenis van n8n is niet de chatter: "wie heeft dit gewijzigd en waarom?" beantwoord je in het document.
  5. Alles wat afhangt van een veld dat tussen versies verandert. We hebben het gecontroleerd door in Odoo 19 te schrijven wat in 18 werkte.

Het geval dat het best samenvat: een levering valideren vanuit een flow. We bereidden er een voor van 10 stuks met 4 gereserveerd en riepen button_validate aan, hetzelfde als de knop.

# WH/OUT/00003: 10 pedidas, 4 reservadas.
POST /web/dataset/call_kw
 {"model":"stock.picking","method":"button_validate","args":[[2]]}
-> 200 {"result": {"name": "¿Crear entrega parcial?",
                   "type": "ir.actions.act_window",
                   "res_model": "stock.backorder.confirmation", ...}}

read -> [{"name":"WH/OUT/00003","state":"assigned"}]   # sigue abierto

HTTP 200, geen fout, en een levering in assigned. Voor n8n was de stap groen; voor het magazijn is de bestelling niet vertrokken. Een module herkent de wizard en legt het vast in het document: dezelfde grens als in Odoo 19 versus middleware-connectoren.

En de velden die tussen versies van naam veranderen, wat een stabiele flow na een migratie breekt:

# Odoo 19, escribiendo lo que funcionaba en 17 y 18:
res.users write {"groups_id": [[4, 1]]}
-> "Invalid field 'groups_id' in 'res.users'"     # en 19 se llama group_ids

stock.move create {"name": "Latiguillo", "product_id": 1, ...}
-> "Invalid field 'name' in 'stock.move'"         # en 17 y 18 era obligatorio

We onderhouden dezelfde code in Odoo 19, 18 en 17 in 105 gepubliceerde modules: deze verschillen komen voor rekening van de module, niet van de klant. Het is ook de grens van Odoo Studio wanneer het proces geen veld meer is maar een regel wordt.

De vier fouten die we steeds zien

  1. De lus. Een automatisering meldt aan n8n dat een veld is gewijzigd, de flow schrijft naar Odoo en wat hij schrijft activeert haar opnieuw. Je doorbreekt dat met een voorwaarde in de trigger.
  2. De credential in platte tekst. Niet in de body van de node en niet in een codenode: in een n8n-credential, met een technische gebruiker met minimale groepen.
  3. Geen idempotentie. Een webhook die aan de andere kant opnieuw wordt verstuurd, maakt het record opnieuw aan: drie identieke POST naar onze flow leverden drie leads op.
  4. Geen echte herpoging. Een node probeert niet opnieuw tenzij je Retry On Fail activeert, en de engine beperkt de pogingen tot vijf en de wachttijd tot vijf seconden. Ruim genoeg voor een chat; niet voor een vervoerder: onze Correos Express-module probeert opnieuw na 5, 15, 30, 60, 120 en 240 minuten.

De oplossing zit niet in n8n maar in het ontwerp: bewaar de externe referentie in Odoo en controleer haar voordat je aanmaakt. In een module is dat een unieke constraint in de database; in een flow een voorafgaande leesactie met een raceregio.

Wanneer een flow een module wordt

De flow is een goedkope manier om te ontdekken of het proces het waard is om te bestaan. Het signaal dat hij tekortschiet is een van deze zes:

  • Hij schrijft een veld dat Odoo zelf berekent.
  • Twee schrijfacties moeten samen gebeuren of niet.
  • Iemand gaat binnen Odoo controleren wat er wanneer is gebeurd.
  • Het proces moet de volgende migratie overleven.
  • De aanroep moet herhaald kunnen worden zonder iets te dupliceren.
  • De gebruiker moet vanuit het document zelf opnieuw kunnen proberen.

Dan gooi je de flow niet weg: je brengt het deel dat de bedrijfsstatus raakt naar de module en n8n houdt de rand. Het gaat hetzelfde bij administratieve taken automatiseren en bij de integratie met Signaturit.

Samenvatting: als de flow uitvalt en er alleen gebeurt dat iemand een melding mist, volstaat n8n. Als hij uitvalt en het magazijn of het factuurboek in een toestand achterblijft die niemand kan lezen, was dat een module.

Veelgestelde vragen

Kan ik de taal of het bedrijf meegeven in de aanroep?

Via de drie moderne wegen wel: kwargs.context in call_kw en in execute_kw, en een veld context in /json/2 (een land komt als "Spain" met en_US en als "España" met es_ES). Met de klassieke credential kan het niet, die execute positioneel aanroept.

Waar bewaar ik de API-sleutel en hoe lang is hij geldig?

In een n8n-credential, nooit in de body van de node. In Odoo 19 heeft de sleutel van een gebruiker die geen beheerder is een vervaldatum nodig, en de limiet wordt bepaald door de groep: 90 dagen voor een interne gebruiker.

Breekt mijn flow bij de migratie van Odoo 18 naar 19?

Dat hangt af van de velden die hij raakt, en er komt geen waarschuwing: res.users.groups_id werd group_ids en stock.move.name, verplicht in 17 en 18, bestaat niet in 19. Test je flows tegen een kopie.

Nuttige links binnen FlexigoTech

Odoo-engineeringdienstenImplementatie en ontwikkeling op OdooMaatwerkontwikkelingWanneer een module nodig isEen Odoo-connector voor jouw softwareVoor technologiepartnersOplossingen per behoefteGeordend op probleem, niet op moduleOdoo 19 versus middleware-connectorenDezelfde grens, een niveau hogerWat is Odoo Studio en hoe werkt hetDe andere "no-code" en zijn grenzenAdministratieve taken automatiserenAutomatisering binnen de ERPElektronisch ondertekenen in Odoo met SignaturitNog een geval waar de flow tekortschiet

Wat wij hierin doen

Automatisering met OperariaWat het doet, schermafbeeldingen, versies en prijs.

Heb je n8n-flows tegen Odoo en weet je niet meer welke standhouden?

We beoordelen ze, vertellen je welke blijven zoals ze zijn en welke naar een module moeten, en bouwen de module als het nodig is. Schrijf naar comercial@flexigobe.com of bel +34 616 809 504.

Praat met een engineer