Mirakl is geen marketplace waar je op verkoopt. Het is de software waarmee een retailer zijn eigen marketplace bouwt: Leroy Merlin, Carrefour, Kingfisher, Macy's en Best Buy staan vandaag als klant op de website van Mirakl. Als een operator je uitnodigt, verkoop je bij de operator (zijn categorieën, zijn commissie, zijn contract), maar je Odoo praat met de Mirakl-API, die bij allemaal dezelfde is. Een goede Mirakl-connector is niet "de connector van Leroy Merlin": het zijn N marketplaces met één API en verschillende inloggegevens. En het lastige is niet de API: het is de voorraad verdelen over de kanalen die naar hetzelfde magazijn kijken.
Een correctie op onze eigen website: maandenlang behandelden we Leroy Merlin en GACD als losse integraties. Het zijn twee accounts van dezelfde connector: dezelfde code met een andere host, sleutel en catalogus.
Wat alle Mirakl-operators gemeen hebben en wat niet
De verkoper-API van Mirakl heeft voor elke functie een operatiecode, dezelfde welke operator het ook is: OR11 toont orders, OR23 en OR24 sturen de tracking door en markeren de verzending, OR28 doet een terugbetaling, OF01 uploadt aanbiedingen via een bestand, IV01 geeft de afrekeningsdocumenten terug, M11 is de berichtenservice met de koper en SH21 toont de vervoerders. Een operator kan onderdelen uitgeschakeld hebben (sommige hebben geen berichten of vervoerders, en de connector markeert het endpoint als niet beschikbaar bij een 404 of 410), maar als het beschikbaar is, is het dezelfde aanroep.
Wat verschilt is alles wat geen API is: de host (adeo-marketplace.mirakl.net bij Leroy Merlin), de sleutel en de winkel, de categorieboom en de verplichte attributen (4.844 categorieën en 35.364 attributen in ons Leroy Merlin-account), de toegestane vervoerders (165 codes), de redenen voor terugbetaling, de valuta en vooral de btw-modus: sommigen sturen prijzen inclusief btw (TAX_INCLUDED) en anderen exclusief (TAX_EXCLUDED). Dat punt kostte ons een echte fout: de connector nam de prijs incl. btw als basis, Odoo telde de btw er nogmaals bij op en € 48,86 kwam binnen als € 59,12. Gecontroleerd op de 20 echte orders van het account.
Hoe je het in Odoo modelleert: één account per operator
In onze Mirakl-connector is elke operator een instantie: een record met zijn basis-URL, API-URL, sleutel, winkel, bedrijf, magazijn en verkoopteam. Bij het testen van de verbinding leest de connector /platform/configuration, /account en /channels uit en noteert hij welk platform antwoordt, welke winkel het is en welke functies beschikbaar zijn. In de schermafbeelding is het gedetecteerde platform "Marketplace Adeo" en de gedetecteerde provider leroy_merlin.

Alles van de operator hangt onder de instantie: het woordenboek met categorieën, attributen en waarden (uniek per instantie en code, dus twee operators komen elkaar nooit in de weg), de koppeling van categorieën en vervoerders, en de prijs- en voorraadregels. Een Odoo-product heeft één binding per instantie: hetzelfde product, een andere aanbieding bij elke operator, met eigen SKU, prijs en hoeveelheid. Een tweede operator toevoegen (GACD, waarvan de verkoper-API antwoordt op tdmp.mirakl.net, of een andere) is gewoon één instantie meer. De profielen in de catalogus vullen alleen standaardwaarden in; de code die met Mirakl praat is één en dezelfde.
Het echte probleem: de voorraad verdelen
Twee Mirakl-operators, ManoMano, Amazon, Temu of je eigen webshop kunnen naar hetzelfde magazijn kijken. Alleen de eerste twee zijn Mirakl: de andere hebben hun eigen verkoper-API (Amazon, de SP-API) en zijn aparte connectoren. Maar ze verkopen allemaal uit dezelfde voorraad en geen enkele weet van de andere: elk krijgt de hoeveelheid die je exporteert en verkoopt daarvan tot de volgende export. Dat los je niet "in realtime" op, want noch de API noch de operator werkt zo; je lost het op met regels per kanaal. Elke instantie beslist vier dingen voordat ze een hoeveelheid publiceert:
- Naar welke hoeveelheid ze kijkt: aanwezig, voorspeld, vrij (min wat gereserveerd is) of aanwezig alleen in de magazijnen van die instantie.
- Hoeveel ze achterhoudt: een buffer per instantie die de verkopen van andere kanalen tussen twee exports dekt.
- Minimum om te publiceren: als er na de buffer minder dan N stuks overblijven, wordt nul gepubliceerd: het laatste stuk op drie plekken verkopen is de klassieke oververkoop.
- Maximum gepubliceerd: een plafond per instantie, om een operator geen voorraad te tonen die al aan een andere is beloofd.
De volgorde staat in de code: hoeveelheid volgens de strategie, min de buffer, nul als het minimum niet gehaald wordt, afgekapt op het maximum. Met 12 vrije stuks, buffer 2, minimum 3 en maximum 5 ziet elke operator 5. Als elk kanaal gewoon de aanwezige hoeveelheid krijgt, laat de eerste die het laatste stuk verkoopt de anderen lucht verkopen. Buffer en frequentie behandelen we in voorraad in realtime voor marketplaces, en hoe je alles vanuit één Odoo beheert in verkopen op meerdere marketplaces en in oplossingen.
Orders en statussen: van Mirakl naar Odoo en terug
Mirakl heeft meer orderstatussen dan Odoo nodig heeft en brengt ze terug tot zes: WAITING_ACCEPTANCE, WAITING_DEBIT, STAGING en INCIDENT_OPEN zijn "in afwachting"; SHIPPING, "in verzending" (de koper heeft betaald en de termijn om te verzenden loopt); SHIPPED, "verzonden"; RECEIVED en CLOSED, "gesloten"; CANCELED en REFUSED, "geannuleerd"; REFUNDED, "terugbetaald". De order in de schermafbeelding kwam binnen als SHIPPED, werd gekoppeld aan "Verzonden" en gelinkt aan verkooporder S00509, met valuta, totaal en btw uit de payload van de operator.

De terugweg: de order in afwachting wordt geaccepteerd met een PUT naar /orders/{id}/accept, in batches met een maximum per run; bij het valideren van de levering wordt de tracking verstuurd (OR23) en de verzending gemarkeerd (OR24), en de levering krijgt een stempel met verzoek en antwoord; de gevalideerde factuur wordt naar de order geüpload (OR74) nadat de vorige van hetzelfde type is verwijderd (OR72, OR76). En het incrementele venster wordt opgevraagd op wijzigingsdatum, niet op aanmaakdatum: een order die weken later van status verandert, zou anders nooit meer binnenkomen.
Waar het dubbel gaat als de connector niet idempotent is
Op drie plekken. De order: de database weigert twee records met dezelfde identificatie in dezelfde instantie (unique(instance_id, mirakl_order_id)); de import werkt de bestaande bij. De verzending: de connector leest eerst de status opnieuw uit; als die al SHIPPED is, herhaalt hij het niet, en als het opnieuw uitlezen mislukt, neemt hij niets aan en doet de aanroep, omdat "al verzonden" als gegeven aannemen bij een timeout orders zonder tracking achterliet. En de terugbetaling, dat is geld: in de audit van 16.15.1 zagen we dat de HTTP-client elk verzoek herhaalde bij 5xx of timeout, ook dat van OR28. Een timeout zegt niet dat het verzoek niet is aangekomen: het zegt dat je het niet weet. Nu worden alleen leesverzoeken herhaald, behalve bij 429, dat garandeert dat er niets is verwerkt; en de knop weigert een tweede volledige terugbetaling te sturen als de order al als terugbetaald geregistreerd staat.
Afrekeningen: wat de API teruggeeft en waarom ze een eigen afletting verdienen
Mirakl betaalt je niet order voor order: de operator maakt periodiek een nettobedrag over, en IV01 geeft het document terug dat dit toelicht, met het overgemaakte bedrag en vier emmers: orders, commissies, terugbetalingen en teruggestorte commissies. De connector bewaart elk document per instantie (periode, valuta, betaalstatus) en berekent een eigen netto uit de emmers. Wat ontbreekt om bij het overgemaakte bedrag uit te komen is "overige kosten", vrijwel altijd het abonnementsgeld van de operator: een echte afrekening sleepte € 39,00 verschil mee tot we dat restant opnamen, en zo is het zichtbaar als een gewone regel in plaats van verstopt te zitten in een verschil zonder naam.
Wanneer een Mirakl-operator niet loont
Dat de API dezelfde is, betekent niet dat elke uitnodiging een ja verdient. De kosten van instappen zitten in de catalogus, niet in de integratie: je categorieën koppelen aan een boom van duizenden knooppunten en de verplichte attributen van elke familie invullen is mensenwerk, en het herhaalt zich bij elke operator. Weinig passende categorieën, een commissie die na het abonnementsgeld de marge opeet of een acceptatietermijn die je magazijn niet haalt: niets daarvan loont, hoe makkelijk het ook te koppelen is. Het signaal komt uit de instantie voordat je iets publiceert: synchroniseer het woordenboek, koppel tien families en tel hoeveel verplichte attributen je nog mist. Als het er honderden zijn, kost het je meer dan het oplevert.
De connector waarmee we het bovenstaande hebben gedaan draait in productie met echte orders en staat op groen (163 van 163 tests) in Odoo 19, 18 en 17, na de audit van 16.15.1 (121 kandidaat-bevindingen, 18 bevestigd). Als je een Mirakl-connector van iemand anders erft, staat wat je moet nakijken in een geërfde Odoo-connector auditen; als het platform dat met Odoo moet praten van jou is, dan is dat een Odoo-connector voor jouw software.
Veelgestelde vragen
Verkoop ik dan "op Mirakl"?
Nee. Je verkoopt bij de operator die je heeft uitgenodigd: die bepaalt categorieën, commissie, termijnen en contract. Mirakl is de software waarmee die operator zijn marketplace beheert, en de API ervan is waar je Odoo mee koppelt.
Heb ik een connector per Mirakl-operator nodig?
Nee. Je hebt één instantie per operator binnen dezelfde connector nodig: eigen host, sleutel, winkel, woordenboek, vervoerders en voorraadregels. De code die met de API praat is dezelfde.
Waarom kan de voorraad niet "in realtime"?
Omdat elke operator de hoeveelheid krijgt die je exporteert en daarvan verkoopt tot de volgende export, zonder van de andere kanalen te weten. Wat oververkoop voorkomt is de regel per kanaal: naar welke hoeveelheid wordt gekeken, buffer, minimum en maximum, plus een redelijke frequentie.
Handige links binnen FlexigoTech
Wat wij hieraan doen
Heeft een Mirakl-operator je uitgenodigd en verkoop je met Odoo?
Vertel ons welke operator het is, hoeveel kanalen al naar je magazijn kijken en welke Odoo-versie je gebruikt. We zeggen je wat nodig is om hem als één instantie meer te koppelen en welke voorraadregels je moet instellen voordat je publiceert. Mail naar comercial@flexigobe.com of bel +34 616 809 504.

