Pricing Automation Across Currencies
Foreign currency prices that recalculate themselves every day from the Narodowy Bank Polski rate, and a purchase cost sitting next to every product, so margin is a number in the admin rather than something rebuilt in a spreadsheet at month end.
A price is only half a decision
Most stores can tell you what a product sells for in every currency they trade in. Far fewer can tell you, without opening a spreadsheet, whether last week's order was worth fulfilling.
The cost of goods usually lives somewhere else. In a supplier email, in an accounting system nobody in sales has access to, in a workbook maintained by the one person who knows which tab is current. Once a quarter that person reconstructs the margin, and everyone treats the result as fact because there is no competing version.
Putting the purchase cost next to the price, inside the same admin, changes what the team can answer on the spot. It also removes a dependency on a single colleague that nobody planned and nobody notices until they take a holiday.
What the daily conversion does
The store's PLN price is the source. Every day, a scheduled run reads the Narodowy Bank Polski table A mid rate and derives the foreign price: the PLN price divided by the rate, multiplied by a margin multiplier you configure, rounded half up to two decimal places.
The multiplier is where the commercial judgement lives, and there is deliberately no default for it. A run that finds no margin configured is refused in full rather than proceeding on a made-up number. Guessing here would be worse than doing nothing, because a wrong price that looks plausible ships.
You are not obliged to wait for the schedule. A recompute can be triggered from the admin, and each run reports per currency what it actually did, so the first question after a change has an answer in the interface rather than in the logs.
What it refuses to touch
An automation that overwrites human decisions gets switched off within a month, so this one is built to lose that argument on purpose.
Only the default price is ever read or written. Region overrides, customer group prices, quantity breaks, anything scoped by a rule or living in a price list: all of it is somebody's deliberate exception, and the plugin leaves it alone.
Manual edits are protected by the plugin's own record of the last price it wrote, used as an optimistic concurrency stamp. If the live price no longer matches, a person has been there and the run steps around it.
A currency missing from the store's supported currencies is skipped whole rather than variant by variant. A rate older than the staleness tolerance, five days by default, or one that cannot be fetched at all, skips that currency for the entire run. No stale price gets written because half the data happened to arrive.
And the whole thing seeds to off. Installing it changes nothing until you enable it.
Cost history that cannot be quietly rewritten
Net purchase cost is tracked per SKU, with an append-only history behind it. The SKU is the durable key, because SKUs outlive variant ids; the variant id is treated as a cache with a resync action in the admin when the catalogue moves underneath it.
Each record carries more than a number. It carries the currency, the source, meaning whether it was entered by hand, imported from a CSV or written over the API, the Medusa user who changed it, and a note. Six months later the question is rarely what the cost was. It is why it changed, and who agreed to it.
The history table's update, delete, soft delete and restore operations are deliberately overridden to throw. There is no supported path to editing the past, by design. A cost history that can be tidied up is not evidence of anything.
The figures that fall out of it
Once cost and price sit in the same place, the useful numbers are arithmetic rather than analysis.
Gross cost is the net purchase cost plus VAT.
Net income is the selling price minus commission minus gross cost.
Break-even price is the gross cost divided by one minus the commission rate, which is the number worth knowing before agreeing to a discount.
Margin is net income over selling price.
The commission rate defaults to zero, which is honest for a store selling only through its own checkout. VAT has no default at all, and neither does currency: an operation that needs one refuses and names the setting that is missing.
That refusal extends to the outputs. A missing input returns nothing rather than a zero, because a zero margin printed next to a product is a statement, and it would be a false one.
Where you actually see this
Two places, both inside the Medusa admin you already use.
A widget on the product detail page shows the cost, the history and the derived figures for the product in front of you. And a margin column appears in the shared Catalog table, the single extensible product list that our Medusa plugins contribute columns to, rather than each plugin adding a near-identical list of its own.
The practical effect is that margin becomes something you glance at while doing something else, instead of a report somebody has to be asked for. Full documentation for both plugins lives at medusa-fx-pricing and medusa-product-costs, and you can read exactly what they do before commissioning anything.
What you get
Daily USD and EUR prices derived from your PLN price
A scheduled run reads the NBP table A mid rate and writes the foreign price as PLN price divided by the rate and multiplied by your margin multiplier, rounded half up to two decimal places.
A margin multiplier you set on purpose
There is no default margin and no fallback. A run configured without one is refused whole rather than quietly guessing a number that would end up on your shelf edge.
Manual price edits left alone
The plugin records the price it wrote and treats that record as a concurrency stamp. A price a person edited by hand no longer matches, so the next run skips it instead of overwriting the decision.
Purchase cost per SKU with an append-only history
Every cost record carries the net unit cost, the currency, whether it was typed in, imported from CSV or written over the API, the Medusa user who changed it and a note explaining why.
Margin figures computed rather than estimated
Gross cost is net cost plus VAT. Net income is the selling price minus commission minus gross cost. The break-even price is gross cost divided by one minus the commission rate, and margin is net income over selling price.
Bulk cost import from CSV
The importer handles comma or semicolon delimiters, comma or dot decimals, thousands grouping, quoted fields and currency symbols left in the cell, and refuses to proceed when the delimiter is genuinely ambiguous.
How we work
- 01
Agree the base price and the multiplier
The store's PLN price is the single source the conversion reads. What we settle first is the margin multiplier per currency, because that number is the whole commercial decision and the plugin will not invent one for you.
- 02
Get a cost onto every SKU
Costs arrive by CSV import, by hand in the admin, or over the API from whatever system already knows them. The SKU is the durable key and the variant id is only a cache, with a resync action in the admin for when the catalogue changes underneath it.
- 03
Set VAT and commission explicitly
There is no default VAT rate and no default currency. An operation that needs one refuses and names the setting that is missing, which is a slower first day and a considerably better first month.
- 04
Run it by hand before it runs itself
Everything ships disabled, so nothing writes until you say so. You trigger a recompute from the admin, read the per-currency summary of what the run did, and only then let the daily schedule take over.
- 05
Watch the margin column, not the export
Margin appears as a column in the shared Catalog table in the Medusa admin, next to the other columns our plugins contribute, so checking whether a product is worth selling stops being a monthly reporting exercise.
Tools and technology
Where a solid open-source tool exists, we choose it over a closed one. No lock-in to a single vendor, and costs you can actually predict.
- Medusa v2
- TypeScript
- Node.js
- PostgreSQL
- Next.js
- NBP API
- @zanreal/medusa-fx-pricing
- @zanreal/medusa-product-costs
- @zanreal/medusa-admin-kit
- CSV
Frequently asked questions
More services in this category
Headless Commerce Builds on Medusa
An off-the-shelf commerce platform hands you its data model, its checkout rules and its release schedule. Medusa v2 is a framework you run yourself, so the parts of your business that do not fit a template get built rather than worked around.
Marketplace Integrations for Allegro
Selling on Allegro next to your own shop usually means one catalogue kept in two places and a spreadsheet holding them together. The offers, the stock and the orders can live in the same admin as everything else instead.
Invoicing and KSeF Compliance for Online Stores
Invoicing is the part of a shop where a plausible guess is worse than no answer at all. The pipeline issues what is clearly issuable, files what the law says must be filed, and hands everything else to a human with the reason attached.
Read testimonials from companies that trusted us
Delivered well ahead of the deadline.
ZanReal's individual approach is impressive.
Knowledge and business intuition make them a valuable partner.
Quick solutions that reduced costs by 99%.
Latest
Technical guides, security insights, and what we've learned building with AI.
Where does your margin actually live today?
Message usTell us which currencies you sell in and where the purchase cost is kept. We will show you what a daily conversion would do to your catalogue before anything writes a single price.
Can't keep up with changes in AI world?
Let us do the heavy lifting. Every week we distill the most important AI developments into a focused 5-minute briefing - so you stay ahead without the noise.
Find out more
