Systemen
Odoo koppeling met je webshop: orders in Odoo, voorraad per magazijn terug
Een Odoo koppeling zet webshoporders en klanten als verkooporder in Odoo en haalt artikelen, voorraad, prijzen en trackingnummers terug naar je webshop. Sinds Odoo 19 loopt dat over de JSON-2 API met een API-sleutel; XML-RPC verdwijnt in Odoo 22. Het werk zit in varianten, voorraadvelden, adressen en de veldnamen die per versie veranderen.
Wat is Odoo en wie gebruikt het?
Odoo is een ERP-pakket uit België dat uit losse apps bestaat: verkoop, inkoop, voorraad, boekhouding, productie, CRM en een eigen webshop. Er is een open source-editie, Odoo Community, en een betaalde editie met een abonnement.
Voor een koppeling tellen twee dingen: waar Odoo draait en welke versie het is. Er zijn drie manieren van hosten:
| Hosting | Eigen modules | Versies |
|---|---|---|
| Odoo Online | nee, ook geen modules uit de Apps Store | major versies plus SaaS-versies elke 2 tot 3 maanden |
| Odoo.sh | ja | major versies |
| Eigen server | ja | major versies, ook met verlengde support |
Odoo brengt elk najaar een major versie uit en geeft daar 3 jaar standaardsupport op. Odoo 20.0 kwam in september 2026, Odoo 19.0 in september 2025, Odoo 18.0 in oktober 2024. De support van Odoo 17.0 liep in september 2026 af. Een koppeling die vandaag gebouwd wordt, draait dus vaak op 18 of 19 en gaat binnen een jaar of twee door een upgrade.
Wat je met Odoo koppelt
Odoo is in de meeste koppelingen leidend voor artikelen, voorraad, prijzen en facturen. De webshop levert de order en de nieuwe klant.
| Stroom | Richting | Model in Odoo |
|---|---|---|
| Orders | webshop naar Odoo | sale.order met order_line |
| Klanten en adressen | webshop naar Odoo | res.partner |
| Artikelen en varianten | Odoo naar webshop | product.template, product.product |
| Voorraad | Odoo naar webshop | qty_available, free_qty op product.product; stock.quant |
| Prijslijsten | Odoo naar webshop | product.pricelist, product.pricelist.item |
| Verzending en tracking | Odoo naar webshop | stock.picking, veld carrier_tracking_ref |
| Facturen | Odoo naar webshop | account.move |
Een order gaat met de regels erin in één aanroep naar binnen. Klant en artikel gaan mee als id, dus die zoekt de koppeling eerst op. Dit is order 10482 van Bakker Installatie B.V. op Odoo 19:
POST /json/2/sale.order/create HTTP/1.1
Host: bakker.odoo.com
Authorization: bearer 3f9c...e1a7
Content-Type: application/json; charset=utf-8
{
"vals_list": [{
"partner_id": 4711,
"partner_shipping_id": 4712,
"client_order_ref": "WEB-10482",
"order_line": [[0, 0, {
"product_id": 881, "product_uom_qty": 12,
"price_unit": 17.08, "tax_ids": [[6, 0, [17]]]
}]]
}]
}
De lijsten met drie elementen zijn de schrijfopdrachten van Odoo voor gekoppelde records: 0 maakt een regel aan, 6 zet de btw-codes. Via de API moeten ze letterlijk zo, als getallen. Het webshopordernummer gaat in client_order_ref, het veld Customer Reference. Daarop zoekt de koppeling bij elke nieuwe poging eerst of de order er al staat. Welke velden per stroom meegaan staat op orders, klanten en verzending.
Hoe Odoo data vrijgeeft
JSON-2 vanaf Odoo 19, XML-RPC daarvoor
| Versie | Externe API | Inloggen |
|---|---|---|
| Odoo 17 en 18 | XML-RPC en JSON-RPC op /xmlrpc/2 en /jsonrpc |
database, login en wachtwoord of API-sleutel |
| Odoo 19 | JSON-2 op /json/2/<model>/<methode>; RPC verouderd |
API-sleutel als bearer-token |
| Odoo 20 | JSON-2; database-service van RPC verwijderd | API-sleutel als bearer-token |
| Odoo 22 (najaar 2028) | alleen JSON-2; RPC verwijderd | API-sleutel als bearer-token |
In beide gevallen praat de koppeling met dezelfde modellen en methodes die Odoo intern gebruikt: search_read, create, write en de knoppen van het scherm, zoals action_confirm op een verkooporder. Welke modellen en velden jouw database heeft, hangt af van de geïnstalleerde apps. Methodes waarvan de naam met een underscore begint, zijn via de API niet aan te roepen.
Op een server met meerdere databases gaat de databasenaam mee in de header X-Odoo-Database. Bij XML-RPC is het de eerste parameter van elke aanroep; dat is de "databasenaam" die je bij oudere koppelingen moest invullen.
API-sleutels van maximaal 90 dagen
Een API-sleutel maak je per gebruiker aan onder Voorkeuren, Accountbeveiliging. Odoo toont de sleutel één keer. In Odoo 19 krijgt elke sleutel een verloopdatum. Voor een gewone interne gebruiker is de maximale looptijd 90 dagen; alleen een beheerder kan een sleutel zonder einddatum maken. Odoo raadt voor een koppeling een aparte botgebruiker aan met alleen de rechten die de koppeling nodig heeft en zonder wachtwoord. Die botgebruiker komt dan ook in de wijzigingslog te staan in plaats van een medewerker.
Een sleutel van 90 dagen betekent dat de koppeling na drie maanden stopt als niemand hem vervangt. Odoo heeft daarvoor res.users.apikeys/generate: met de lopende sleutel maakt de koppeling een nieuwe aan en trekt de oude in. Standaard mag alleen een gebruiker met beheerrechten dat; een systeemparameter zet het voor andere gebruikers aan. Per gebruiker zijn standaard 10 zo gemaakte sleutels toegestaan, daarboven volgt HTTP 422.
Alleen op het Custom-plan
Odoo schrijft dat de externe API alleen beschikbaar is op het Custom-plan, niet op One App Free of Standard. Een koppeling met een webshop is externe API. Verzoeken die Odoo zelf naar buiten doet, zoals naar een betaalprovider of vervoerder, vallen er niet onder. De documentatie van de JSON-2 API noemt het plan, de authenticatie en de foutcodes.
Elke aanroep is een eigen transactie
De documentatie van Odoo noemt geen limiet in verzoeken per minuut. Wat er wel staat: elke JSON-2-aanroep is een eigen databasetransactie, en meerdere aanroepen samen in één transactie kan niet. Voor een order betekent dat twee transacties: create maakt een offerte, action_confirm maakt er een bevestigde verkooporder van. Faalt de tweede, dan staat er een onbevestigde offerte met het webshopnummer erop. Zonder de controle op client_order_ref maakt de volgende poging een tweede offerte.
De rekensom voor 600 orders op een drukke dag: per order één zoekvraag naar de klant, één naar de artikelen van alle regels samen, één create en één action_confirm. Dat zijn 4 aanroepen per order, 2.400 per dag. Lezen gaat in pagina's: 15.000 varianten met search_read en een limit van 1.000 zijn 15 aanroepen. Hoe snel Odoo antwoordt, hangt af van je hosting en de geïnstalleerde apps, dus die meten we op jouw database voor de livegang.
Waar het bij Odoo op vastloopt
| Wat de webshop nodig heeft | In Odoo | Gevolg zonder regel |
|---|---|---|
| Eén unieke SKU per variant | default_code op product.product, niet uniek afgedwongen |
twee varianten met dezelfde code, order op de verkeerde |
| Voorraad die verkoopbaar is | qty_available, free_qty en virtual_available |
te hoge voorraad in de shop |
| Voorraad die gewijzigd is | berekende velden, geen write_date op het artikel |
wijzigingen worden niet gezien |
| Huisnummer en toevoeging | street en street2, splitsing alleen met een extra module |
lege huisnummers |
| Klantprijs | regels in product.pricelist.item, geen publieke rekenmethode |
verkeerde prijs in een B2B-shop |
Template, variant en een code die niet uniek is
Een artikel in Odoo is een product.template; elke variant daarvan is een product.product. De webshop-SKU hoort op de variant, in default_code (Internal Reference). Odoo dwingt die code niet uniek af: het scherm waarschuwt bij een dubbele code, de API niet. De streepjescode in barcode is wel uniek binnen een bedrijf. De koppeling controleert daarom voor elke run of een SKU precies één variant oplevert en zet een dubbele code op de controlelijst. Zie varianten.
Drie voorraadgetallen en geen wijzigingsdatum
Op een variant staan drie getallen. qty_available is wat er fysiek ligt. free_qty is dat min wat al gereserveerd is voor bevestigde orders. virtual_available telt ook geplande in- en uitgaande leveringen mee. Voor de webshop is free_qty meestal het juiste getal. Met warehouse_id of location in de context van de aanroep geeft Odoo het getal voor één magazijn of locatie; zonder context telt het alle interne locaties op. Zie meerdere magazijnen.
Alle drie zijn berekende velden. Een voorraadmutatie verandert de write_date van het artikel dus niet, en een koppeling die artikelen filtert op write_date mist elke voorraadwijziging. De koppeling leest wijzigingen daarom uit stock.quant. Odoo slaat datums op in UTC zonder tijdzone; een filter op 00:30 Nederlandse tijd op 1 oktober is 2026-09-30 22:30:00. Zie welke voorraad toon je in je webshop.
Adressen: één regel of een splitsing die niet klopt
Een adres in Odoo heeft street en street2. De module base_address_extended voegt street_name, street_number en street_number2 toe en splitst street automatisch. Die splitsing herkent een Nederlandse toevoeging met spatie niet: Dorpsstraat 12 A komt in zijn geheel in street_name en het huisnummer blijft leeg, terwijl Dorpsstraat 12A wel als straat plus huisnummer 12A uitkomt. De Nederlandse boekhoudmodule l10n_nl installeert base_address_extended niet mee. Schrijft de koppeling zelf naar de losse velden, dan bouwt Odoo street daaruit op als Dorpsstraat 12 - A, met een streepje voor de toevoeging. Zie adresvelden mappen.
Klantprijzen en veldnamen die per versie wijzigen
De prijs van een artikel voor een klant komt uit de prijslijst van die klant: regels met een vaste prijs, een korting of een formule, een min_quantity en een date_start. De methodes die daar een prijs van maken beginnen met een underscore en zijn via de API niet aan te roepen. De koppeling leest de regels en rekent de prijs zelf uit, of op Odoo.sh en een eigen server doet een kleine module dat. Zie klantspecifieke prijzen.
Veldnamen veranderen bij een upgrade. Het btw-veld op een orderregel heette tot en met Odoo 18 tax_id en heet in Odoo 19 tax_ids. Een koppeling die het oude veld blijft sturen, krijgt na de upgrade een fout op elke order. Bij een upgrade draait de koppeling daarom eerst als dry run tegen een kopie van je database. Op Odoo Online kan dat met een duplicaat: maximaal 5 per database, 15 dagen geldig, en met de optie For testing purposes staan e-mails, betalingen en leveringen erin uit.
Platformen die we aan Odoo koppelen
De koppeling wordt gebouwd op jouw Odoo, met jouw apps, prijslijsten en magazijnen. Voor WooCommerce staat de combinatie op WooCommerce Odoo koppeling. De platformen zelf staan op WooCommerce koppeling, Shopify koppeling en Magento koppeling. Andere ERP-systemen: Business Central koppeling en Exact Online koppeling. De ERP-kant in het algemeen staat op ERP koppeling met je webshop, alle stromen op koppelingen.
Wij bouwen de koppeling voor een vaste prijs, en hosten, draaien en bewaken hem daarna voor een vast bedrag per maand. Voor de livegang draait hij als dry run: je ziet per order welke klant, varianten en btw-codes in Odoo zouden ontstaan, zonder dat er iets wordt aangemaakt. Vertel welke Odoo-versie en welk plan je hebt, dan hoor je welke stromen via de API kunnen en waar een module nodig is.
Veelgestelde vragen
Werkt een koppeling met Odoo Online, Odoo.sh en een eigen server?
Ja, alle drie hebben dezelfde externe API. Het verschil zit in wat er naast de API kan. Odoo Online draait geen eigen modules en geen modules uit de Odoo Apps Store, dus alles moet via de standaardmodellen en publieke methodes. Op Odoo.sh en op een eigen server kan een kleine module erbij, bijvoorbeeld voor een klantprijs of een order die in één transactie wordt aangemaakt en bevestigd.
Heb ik het Custom-plan van Odoo nodig?
Volgens de documentatie van Odoo is de externe API alleen beschikbaar op het Custom-plan, niet op One App Free en niet op Standard. Een koppeling die van buitenaf gegevens in Odoo leest of schrijft valt daaronder. Gaat het verzoek vanuit Odoo naar een andere dienst, zoals een betaalprovider of vervoerder, dan telt Odoo dat niet als externe API. Controleer dus eerst welk plan je hebt.
Welke Odoo-versie heb ik nodig?
Een koppeling werkt op elke versie met standaardsupport. Odoo 19 en 20 hebben de JSON-2 API, Odoo 17 en 18 alleen XML-RPC en JSON-RPC. Standaardsupport voor Odoo 17 liep in september 2026 af, voor Odoo 18 loopt hij tot september 2027. Wie nu nog op 17 of 18 zit, upgradet binnen afzienbare tijd, en dan verandert de API en een deel van de veldnamen.
Wat gebeurt er met mijn koppeling als XML-RPC verdwijnt?
De database-service van XML-RPC en JSON-RPC is in Odoo 20 al verwijderd. De services common en object, waar koppelingen over lopen, volgen in Odoo 22, gepland voor najaar 2028, en op Odoo Online in versie 21.1, winter 2027. Een koppeling die nog op /xmlrpc/2/object draait moet voor die tijd naar /json/2. Inloggen verandert mee: geen gebruikers-id en wachtwoord meer, maar een API-sleutel in de header.
Kan Odoo een webhook sturen als er iets wijzigt?
Ja, via een automatiseringsregel met de actie Send Webhook Notification. Die stuurt een POST met de velden die je kiest naar een adres. De documentatie beschrijft geen herhaalpogingen als de ontvanger even onbereikbaar is. Wij gebruiken zo'n webhook als signaal en draaien daarnaast een controleronde op write_date, zodat een gemiste melding geen gemiste order of voorraadwijziging wordt. Zie wat is een webhook.
Odoo heeft zelf een webshop. Waarom een koppeling?
Met de eCommerce-app van Odoo heb je geen koppeling nodig: shop en ERP zijn dan dezelfde database. Deze pagina gaat over een webshop op een ander platform, zoals WooCommerce, Shopify of Magento, met Odoo als ERP erachter. Dan zijn het twee systemen met elk een eigen artikelnummer, klant en order, en daar zit de mapping.
Vertel wat je nodig hebt
Vertel welke systemen je gebruikt en wat je wilt verbeteren. Je krijgt binnen één werkdag een persoonlijk antwoord. We helpen je de werkzaamheden helder te krijgen en spreken de prijs en planning af voordat je iets toezegt.
- Je weet de prijs en de doorlooptijd voordat je iets toezegt
- Wij zoeken uit welke koppeling het werk uit handen neemt
- Wij verzorgen de bouw, hosting, bewaking en het onderhoud
- Je team krijgt minder overtypwerk en minder uitzoekwerk