Skip to main content
Mirakl · Odoo 19, 18 and 17

Mirakl is not a marketplace: it is the platform behind many, and that changes how you integrate it with Odoo

Leroy Merlin, Carrefour or another operator has invited you and they keep saying Mirakl. What it is, what its marketplaces share and what they do not, how to model it in Odoo and why the real problem is stock allocation.

Instance form of the Mirakl connector in Odoo with the connection tested and 206 offers

Mirakl is not a marketplace you can sell on. It is the software a retailer uses to run its own: Leroy Merlin, Carrefour, Kingfisher, Macy's and Best Buy are listed today as customers on Mirakl's website. When one invites you, you sell on the operator — its categories, its commission, its contract — but your Odoo talks to the Mirakl API, the same across all of them. A well-made Mirakl connector is not "the Leroy Merlin connector": it is N marketplaces with one API and separate credentials. And the hard part is not the API: it is sharing stock among the channels that look at the same warehouse.

A correction to our own website: for months we treated Leroy Merlin and GACD as two separate integrations. They are two accounts of the same connector: the same code with a different host, key and catalogue.

What every Mirakl operator shares and what it does not

Mirakl's seller API has an operation code for everything, the same whatever the operator is called: OR11 lists orders, OR23 and OR24 send the tracking and mark the shipment, OR28 refunds, OF01 uploads offers by file, IV01 returns the settlement documents, M11 is buyer messaging and SH21 lists carriers. An operator can have families switched off — some expose neither messaging nor carriers, and the connector flags the endpoint as unavailable on a 404 or 410 — but when it is exposed it is the same call.

What changes is everything that is not API: the host (adeo-marketplace.mirakl.net for Leroy Merlin), the key and shop, the category tree and mandatory attributes (4,844 categories and 35,364 attributes on our Leroy Merlin account), the accepted carriers (165 codes), the refund reasons, the currency and, above all, the tax mode: some send prices with VAT included (TAX_INCLUDED) and others without it (TAX_EXCLUDED). That point cost us a real defect: the connector took the VAT-inclusive price as the base, Odoo added VAT again and 48.86 € came in as 59.12 €. Verified on the account's 20 real orders.

How to model it in Odoo: one account per operator

In our Mirakl connector each operator is an instance: a record with its base URL, its API URL, its key, its shop, its company, its warehouse and its sales team. On test connection it reads /platform/configuration, /account and /channels and writes on the form which platform answers, which shop it is and which features it exposes. In the screenshot, the detected platform is "Marketplace Adeo" and the detected provider, leroy_merlin.

Leroy Merlin instance of the Mirakl connector in Odoo: host adeo-marketplace.mirakl.net, shop 7401, detected platform Marketplace Adeo and the chatter with 4,844 categories, 35,364 attributes and 165 carriers synced
One instance = one operator. The chatter records what Mirakl returned on connection: platform, shop, 4,844 categories, 35,364 attributes and 165 carriers. Our own screenshot on Odoo 19.

Everything of the operator's hangs off the instance: the dictionary of categories, attributes and values (unique per instance and code, so two operators never collide), the category and carrier mapping, and the price and stock rules. An Odoo product has one binding per instance: the same product, a different offer on each operator, with its SKU, price and quantity. Adding a second operator — GACD, whose seller API answers on tdmp.mirakl.net, or any other — is one more instance. The profiles in the catalogue only fill in defaults; the code that talks to Mirakl is one.

The real problem: allocating stock

Two Mirakl operators, ManoMano, Amazon, Temu or your own site can look at the same warehouse. Only the first two are Mirakl: the rest have their own seller API — Amazon, the SP-API — and are separate connectors. But they all sell against the same stock and none knows about the others: each receives the quantity you export and sells against it until the next export. "Real time" does not solve that, because neither the API nor the operator works that way; rules per channel do. Each instance decides four things before publishing a quantity:

  • Which quantity it looks at: on hand, forecast, free (minus what is reserved) or on hand only in that instance's warehouses.
  • How much it keeps back: a buffer per instance covering the sales on other channels between two exports.
  • Minimum to publish: if fewer than N units remain after the buffer, zero is published: selling the last unit in three places is the classic oversell.
  • Maximum published: a cap per instance, so you do not show one operator stock already promised to another.

The order is in the code: quantity per the strategy, minus the buffer, zero if it does not reach the minimum, capped at the maximum. With 12 free units, buffer 2, minimum 3 and maximum 5, each operator sees 5. If every channel just gets the on-hand quantity, the first to sell the last unit leaves the others selling air. Buffer and cadence are covered in real-time stock for marketplaces, and how all of it is governed from a single Odoo, in selling on several marketplaces and in solutions.

Orders and states: from Mirakl to Odoo and back

Mirakl has more order states than Odoo needs and reduces them to six: WAITING_ACCEPTANCE, WAITING_DEBIT, STAGING and INCIDENT_OPEN are "pending"; SHIPPING, "shipping" (the buyer has paid and the dispatch deadline is running); SHIPPED, "shipped"; RECEIVED and CLOSED, "closed"; CANCELED and REFUSED, "cancelled"; REFUNDED, "refunded". The order in the screenshot came in as SHIPPED, was mapped to "Shipped" and linked to sale order S00509, with currency, total and tax from the operator's payload.

Mirakl order in Odoo: raw state SHIPPED, state Shipped, sale order S00509, 35.60 € with 4.27 € tax, and the Cancel on Mirakl and Refund on Mirakl buttons
The order keeps the operator's raw state and Odoo's reduced one side by side. Refund and cancel are buttons on the same record: that is why they must be idempotent.

The way back: the pending order is accepted with a PUT to /orders/{id}/accept, in batches with a cap per run; validating the delivery sends the tracking (OR23) and marks the shipment (OR24), stamped with request and response; the validated invoice goes up to the order (OR74) after deleting the previous one of the same type (OR72, OR76). And the incremental window is asked by update date, not creation date: an order that changes state weeks later would never come back in.

Where things get duplicated if the connector is not idempotent

Three places. The order: the database rejects two records with the same Mirakl id on the same instance (unique(instance_id, mirakl_order_id)); the import updates the existing one. The shipment: the connector re-reads the state first; if it is already SHIPPED it does not repeat it, and if the re-read fails it assumes nothing and calls, because taking "already shipped" for granted on a timeout left orders without tracking. And the refund, which is money: in the 16.15.1 audit we found the HTTP client retried any request on 5xx or timeout, including the OR28 one. A timeout does not say the request did not arrive: it says you do not know. Today only reads are retried, bar the 429, which guarantees nothing was processed; and the button refuses a second full refund if the order already reads as refunded.

Settlements: what the API returns and why it deserves its own reconciliation

Mirakl does not pay you order by order: the operator periodically transfers a net amount, and IV01 returns the document explaining it, with the transferred amount and four buckets: orders, commissions, refunds and returned commissions. The connector stores each document per instance — period, currency, payment state — and computes its own net from the buckets. What is missing to reach the transferred amount is "other fees", almost always the operator's subscription: a real settlement carried a 39.00 € gap until we folded that residual in, and that way it shows as one more line instead of hiding in a nameless difference.

When a Mirakl operator is not worth it

The API being the same does not mean every invitation deserves a yes. The cost of entering is in the catalogue, not the integration: mapping your categories against a tree of thousands of nodes and filling in the mandatory attributes of each family is people's work, and it repeats on every operator. Few relevant categories, a commission that eats the margin after the fee or an acceptance deadline your warehouse cannot meet: none is worth it however easy it is to connect. The signal comes out of the instance before publishing anything: sync the dictionary, map ten families and count how many mandatory attributes you are missing. If it is hundreds, it will cost you more than it sells.

The connector behind all of the above is in production with real orders and green — 163 of 163 tests — on Odoo 19, 18 and 17, after the 16.15.1 audit (121 candidate findings, 18 confirmed). If you inherit someone else's Mirakl connector, what to check is in auditing an inherited Odoo connector; if the platform that must talk to Odoo is yours, that is an Odoo connector for your software.

Frequently asked questions

So do I sell "on Mirakl"?

No. You sell on the operator that invited you: it sets categories, commission, deadlines and contract. Mirakl is the software that operator runs its marketplace with, and its API is what your Odoo integrates with.

Do I need one connector per Mirakl operator?

No. You need one instance per operator inside the same connector: host, key, shop, dictionary, carriers and stock rules of its own. The code that talks to the API is the same.

Why can't stock be "real time"?

Because each operator receives the quantity you export and sells against it until the next export, unaware of the other channels. What prevents overselling is the rule per channel: which quantity is looked at, buffer, minimum and maximum, plus a sensible cadence.

Useful links inside FlexigoTech

Mirakl Odoo ConnectorWhat it needs to solve when you really sell on a marketplaceSelling on GACD (Mirakl) from OdooThe second operator: same base, another instanceModule catalogueMirakl connector and operator profiles on 19, 18 and 17SolutionsMarketplaces, logistics and invoicing in one OdooAn Odoo connector for your softwareIf the platform that needs to talk to Odoo is yours

What we do about this

Mirakl connectorWhat it does, screenshots, versions and price.

Has a Mirakl operator invited you and you sell with Odoo?

Tell us which operator it is, how many channels already look at your warehouse and which Odoo version you are on. We will tell you what it takes to connect it as one more instance and which stock rules you would need to set before publishing. Email comercial@flexigobe.com or call +34 616 809 504.

Talk to an engineer