Плагин Allegro для Medusa v2 от Koda Plus. Предложения связываются с товарами по сигнатуре, заказы импортируются ровно один раз. Количества, посылки, счета-фактуры, цены и черновики предложений отправляются обратно в Allegro операциями записи, которые вы разрешаете и включаете. Есть авторизация через device login, зашифрованные токены, песочница и демо-режим.
Connect an Allegro seller account to Medusa: link every offer to its product variant by signature, see where Allegro and Medusa disagree on stock before buyers do, import Allegro orders into Medusa exactly once, and send quantities, parcels, invoices, prices and draft offers back to Allegro.
Read only until you decide otherwise. Every writer (the order import included) is off until it is allowed in the plugin options AND armed by a person in the admin, and the HTTP client lets through only the exact requests of the writers that are armed.
Live demo: Medusa admin medusa.koda.plus/app/allegro, signed in to a public demo account by the link itself. The demo runs the plugin in demo mode (): a simulated Allegro account built from the store's catalog, so every screen has data and every writer can be armed without touching Allegro.
What it syncs
Seller account (OAuth 2.0 device flow): the seller types a short code at allegro.pl. No redirect URI, no public callback route.
Offers (id, name, status, price, quantity, signature): Allegro to Medusa, every hour at minute 45 and on Sync now.
Offer to variant links, one primary offer per variant, and the stock check: inside Medusa, on every offer sync.
Order journal (status, fulfillment status, lines, total; no buyer data): Allegro to Medusa, every ten minutes.
Orders (writer ): Allegro to Medusa, every two minutes from the Allegro order event journal, exactly once per checkout form.
Quantities (writer ): Medusa to Allegro, every 15 minutes, plan first.
Parcel numbers and seller status (writer ): Medusa to Allegro, on every fulfillment and shipment and every five minutes.
Invoice PDFs (writer ): Medusa to Allegro, when the Fakturownia plugin (or any invoicing tool) announces a document, and every five minutes.
Prices (writer ): Medusa to Allegro, every hour at minute 52, plan first, inside bounds from metadata.
Draft offers by EAN (writer ): Medusa to Allegro, every hour at minute 57, plan first, drafts only.
Customer returns, disputes, claims and unread messages: Allegro to Medusa, read only, at minutes 20 and 50.
Live offer links for an "Also on Allegro" button: Medusa to your storefront through .
Features
Allegro page in the admin sidebar, not hidden under Settings, with a Panel and a Setup guide view ( opens the guide directly). The panel has counters, the account, the writers, the imported orders, the stock and price plans, the offers, the order journal, the parcels and invoices outbox, customer issues, draft offers and the history. Lists open on deep links (, ).
Cards on the product and the order page: the Allegro offers of a product, and for an imported order what Allegro knows about it (payment, buyer login, delivery and pickup point, totals on both sides, parcels and invoices sent, returns and disputes), with "Mark as handled" and "Retry".
Two switches per writer: in the options (a hard switch: cannot be overridden from the admin) and a toggle a person flips in the admin. The admin shows who armed it and when.
Plan first: the stock, price and draft writers compute a plan (what would change, from what to what, and why the rest is left alone), the admin shows it, and only an armed writer applies it, with a per run cap and a quarantine for items that keep failing. An incomplete read plans nothing; offers missing from a read are never touched.
Circuit breaker: a writer that fails times in a row (default 5) disarms itself and says why. Failures of one item do not count.
Exactly once orders: one row per checkout form before anything happens, an atomic claim with a lease, a lookup of before every create, repeated inside the lock that the BaseLinker plugin takes too. Which orders are the plugin's own is decided by its import table, never by order metadata.
Orders that look like any order: created as a draft and placed by Medusa's own (stock reserved, emitted), with Allegro prices as tax inclusive lines, tax lines from the region, the delivery method and pickup point, a payment collection marked paid when Allegro holds the money, and no customer account.
Stock writer that cannot hurt: decreases by default, ends sold out offers (Allegro cannot hold zero) and never activates an ended offer, re-reads every planned offer right before the command, and refuses a whole plan that looks like a broken read (most variants at zero, or a large share of live offers to end).
Parcels and statuses once each, with the carrier from Allegro's own carrier list (or your map), and a seller status that never moves backwards.
Invoices once each, from the Fakturownia plugin of Koda Plus (VAT invoices and corrections) or from any tool through an event, with the 3 MB and real PDF checks before anything is sent, in their own outbox and sweep.
Customer issues at a glance: open returns, disputes and claims, the ones waiting for your answer, due dates and unread message threads, with links to the right place in the seller panel. The plugin never answers for you.
Signature matching: the offer (the "sygnatura" sellers, feeds and BaseLinker fill with the SKU) against the variant SKU, case insensitive, never by offer name.
Production and sandbox: talks to allegro.pl.allegrosandbox.pl. Tokens of one environment are never used against the other.
Demo mode (only with ): a simulated Allegro account built from your catalog runs through the same parsers, planners and workflows as a real one. Evaluate everything without an Allegro developer account.
Events for your own alerts: , and .
Works with Koda Plus hosts through the shared contract : one line per imported order, product or variant, board counters and cards a host can embed.
References: the stores running the integration, passed in the options, shown under the counters and at the end of the guide.
Admin in English and Polish through the Medusa admin translations.
Zero dependencies beyond Medusa itself.
Requirements
Medusa 2.12 to 2.21 and Node.js 20+ (see Compatibility).
For a real account: an app registered at apps.developer.allegro.pl (or the sandbox portal) as an app without access to a browser, which is the device flow.
For the order import: a region in PLN and a sales channel linked to the stock location that ships Allegro orders.
For the price and draft writers: PLN prices that include tax (a tax inclusive price preference for PLN in Medusa, or ).
Installation
Yarn and pnpm work the same way: or .
Configuration
Add the plugin to :
Set the credentials in . Generate the encryption key with :
Run the migrations, then open Allegro in the admin sidebar:
npx medusa db:migrate
Missing options never break the boot: the module registers, the admin lists what is missing and the scheduled jobs wait. Missing keys never switch on demo mode: it runs only when is , so a production store without keys simply waits for its configuration.
Options
Connection:
, : the Allegro app credentials.
: 32 random bytes in base64. Encrypts the tokens and the device code at rest with AES-256-GCM. A wrong key never deletes the stored tokens: the account reads as not connected and the status says why, until the right key is back.
(default ): keys used before , for a key rotation. Stored tokens are read with them and saved again under the current key on the next use; remove them once the account has refreshed its token.
(default ): or .
(default ): the simulated account, only when this is ( in the configuration above). Nothing is sent to Allegro. Do not switch it on in a production store: with the order import armed, demo orders are created in that store (see Demo mode).
(default none): the name of your app at Allegro. Allegro asks for as the User-Agent with the name of the registered app.
(default ): the https address in the User-Agent.
(default built from and ): the whole User-Agent, when you need to set it yourself.
(default ): a self-imposed limit. Allegro allows 9 000 requests per minute per client id and blocks the client id for a minute above it.
(default ): the timeout of one request.
Reading:
(default ): the hourly offer sync.
(default ): the order journal.
(default: all locations): the stock locations whose quantities count in the stock check and the stock writer.
Writers (each one also needs a person to arm it in the admin):
, , , , , (default each; in demo mode a writer you do not mention is allowed, except , which creates orders in your store and needs in demo mode too; an explicit always wins). The consent asks Allegro only for the scopes of the writers allowed here: for stock, prices and drafts, for parcels and invoices. After changing , connect the account again; the admin says which scopes are missing.
(default ): consecutive failures after which a writer disarms itself.
Stock writer:
(default ): only lowers Allegro quantities to what Medusa has; also raises them, and only while the order import is armed, has run successfully in the last 15 minutes and holds nothing.
(default ): offers one run may change.
(default ): end the offer of a variant that sold out in Medusa (Allegro cannot set a quantity to zero). only reports it.
Order import:
(default: a sales channel named "Allegro", otherwise the store default with a warning; in demo mode an "Allegro (demo)" channel is created and linked to the default channel's stock locations, so the stock check sees your stock; nothing is reserved for demo orders).
(default: the first region in PLN).
(default none): a shipping option put on every imported order, so it can be fulfilled without picking one.
(default ): per Allegro delivery method id or name, the Medusa shipping option to use.
(default ): orders one run creates at most.
Parcels:
(default ): Medusa fulfillment provider id (or its prefix) to an Allegro carrier id, for example . Without a match the carrier is looked up in Allegro's carrier list by name, then sent as with the provider name.
Invoices:
(default ): the Fakturownia document kinds attached to Allegro orders (, , , ).
Prices:
(default: the variant's default price): read the Medusa price from this price list.
(default ) and (default ): variant (or product) metadata keys with the lowest and highest allowed Allegro price.
(default ): never change a price without a floor.
(default ): a bigger change is refused, never clamped.
(default ): offers one run may change.
(default: read from Medusa): Allegro takes gross prices. Unset, the plugin reads the PLN price preference of Medusa, and while it says the prices exclude tax (Medusa's default) the price and draft plans are refused with and nothing is sent. : your PLN prices include tax. : they do not, and the plans stay refused.
Draft offers by EAN:
(required to publish): the id or name of a shipping rates set from the seller panel.
(required to publish): ; for Poland is required (for example ) and is .
(default ): , , or .
(default ): drafts one run may create.
Customer issues:
(default ): customer returns, with the orders scope.
(default , in demo mode): disputes and claims. Needs , which has no read-only variant.
(default , in demo mode): unread message threads. Needs , which has no read-only variant.
References:
(default ): stores running the integration, where texts can be . marks a store that starts on Medusa soon: it is shown with a "Soon" badge and no link, and its is optional. Entries without a name, or live entries without an https address, are dropped, never thrown.
Setup in brief
The admin has the full guide (Allegro, then Setup guide), with each step ticked from the live state of your store.
Register an app at apps.developer.allegro.pl as an app without access to a browser, name it without spaces and copy the client id and secret.
Optionally do it all first in the sandbox (apps.developer.allegro.pl.allegrosandbox.pl, ).
Generate the encryption key () and keep it in the environment.
Add the plugin with , , , and , run and restart.
Click Connect Allegro account; the seller types the code at allegro.pl/skojarz-aplikacje.
Run the first offer sync and check that History shows it as OK.
Review the offers without a product and without a signature; fix signatures or SKUs.
Read the stock check and run a dry run of the stock plan.
Allow only the writers you will use in , then Connect again so the seller grants the wider scopes.
Arm the order import first, after a dry run in Imported orders; bring older orders in with the catch-up import.
Arm the stock writer and watch its plan for a day.
Arm parcels and status; set or when needed.
Arm invoices (with the Fakturownia plugin or your own event).
Turn on customer issues if you want disputes and messages counted.
Optionally arm prices, after putting floors in metadata.
Optionally plan drafts by EAN, after setting and .
Arm one writer at a time, each after its dry run, and go live when the checklist at the end of the guide is all ticked.
How the order import works
The import reads the Allegro order event journal () from its cursor and writes one row per checkout form in . Event ids are opaque: they are never compared, the events are taken in the order Allegro returns them, and the cursor moves to the last event of a page only after the page's rows are written. A fresh install starts at the newest event, so history comes in only through the catch-up import (orders bought between two dates, up to 62 days at once, queued once each). Allegro keeps events for 60 days; a longer pause restarts at the newest event and says so.
Every due row is claimed atomically and looked up in Medusa by . An order counts as the plugin's own only when its import row names it (or it is still a draft no cart placed): such an order from an earlier attempt is adopted and finished, never created again. An order another integration imported (the BaseLinker plugin of Koda Plus writes the same key) makes this plugin step back and say so; a shopper's cart metadata can never make an order look like an Allegro one.
The checkout form is read fresh and mapped: every line by its offer link first, then by its signature. A line that matches no variant holds the whole order with the reason; no product is ever invented. So do a missing address, a currency the region does not use and stock Medusa cannot cover.
Holding the lock in the Medusa Locking module, the reference is looked up again and the order is created as a draft with ; its id is written on the row at once. The buyer e-mail goes on the draft (no customer is created), tax lines are computed where the region left none, and the draft is placed with , which reserves the stock and emits . A payment collection for the total follows, marked paid (captured) when Allegro holds the money and left not paid for cash on delivery. Demo orders skip the placing and the payment (see Demo mode).
A cancellation on Allegro cancels the Medusa order only when nothing was fulfilled; otherwise the row asks a person to handle the return. Medusa's refunds a captured payment and emits , so plugins that react to refunds (an invoice correction, for example) see it.
When the buyer changes the delivery address, the pickup point or the invoice data on Allegro after the import, the row asks a person to compare (the Medusa order is never changed by itself). Mark as handled on the order card or in Imported orders clears it.
A held import emits ; a person retries it with Retry. When Allegro or the network is away for a moment (no answer, 5xx, 429), the next run tries again and the circuit breaker does not count it, so an outage never disarms the import.
is emitted on purpose, like the BaseLinker plugin does: invoicing (the Fakturownia plugin issues the invoice the invoices writer then attaches), the ERP (the Subiekt nexo plugin creates its document) and your own stock follow-ups see Allegro orders like any other. Imported orders carry and . Allegro writes to its buyer itself, so make the subscriber that sends your order confirmation skip them:
What each imported order carries in its metadata: , , , , , , , and when the buyer asked for an invoice; demo orders also and . These keys are for people and other tools; the plugin itself decides from its import table. Every line keeps , and .
The other writers
Stock: for every primary offer linked to a variant, the Allegro quantity against what Medusa has available (stocked minus reserved in the chosen locations; a kit counts its scarcest part). The plan says decrease, end, increase (mirror only) or why nothing happens, and the run sends one per target value (or an publication command) for at most offers, after reading every planned offer again.
Parcels and status: when an imported order gets a fulfillment with tracking numbers in Medusa, each number goes to the Allegro order once (), the seller status becomes , and when everything shipped. Every send is looked up on Allegro first; an unclear answer is checked on Allegro before anything is sent again.
Invoices: the Fakturownia plugin of Koda Plus announces and with ; the PDF is read through the Fakturownia module (resolved at run time, never imported) and uploaded once with , after looking at the invoices already on the order. Any other tool can emit with (an https address).
Prices: the Medusa price (or a price list) against the price of every live linked offer, inside the floor and ceiling from metadata; a price outside them, or a change bigger than , is refused and never clamped. Only gross prices go out (see ). Right before the command the offer is read again, and the price goes only while Allegro still shows the price the plan started from: a price somebody changed in the seller panel waits for the next plan.
Draft offers: variants with a valid EAN and no offer are matched to exactly one Allegro catalog product (several matches are never guessed) and created as drafts with the SKU as signature, at the gross Medusa price. You review and activate them on Allegro.
Parcels and invoices of orders fulfilled or invoiced before or was allowed are not sent later: those writers start from the events they see.
Demo mode
, and only that, runs a simulated Allegro account built from your catalog through the same parsers, planners and workflows as a real account, with every row flagged :
offers for your variants, with a few deliberate mismatches (an offer without a product, one without a signature, an ended offer still in stock);
three to five checkout forms a day at fixed times, deterministic, with buyers at only: online payments, cash on delivery, a company invoice with a NIP, parcel lockers, a cancellation every other day and, every third day, an order whose line has no product;
armed writers change the simulation: quantities, ended offers, prices, drafts, parcels (a simulated courier ships imported demo orders two hours after import) and invoices (the Fakturownia demo PDF when that plugin is present, a simulated one page PDF otherwise);
customer returns, disputes, a claim and unread threads.
The sample data is built by the job (every minute, demo mode only, until every kind exists) or at once with Prepare now on the page (). Opening the page never builds anything.
The order import is the one writer that touches your store, so in demo mode too it needs , and the arming dialog says so. A demo order is created in this Medusa store, in the "Allegro (demo)" sales channel, with , and moved from draft to in the order module itself: it is never placed or paid, so no stock is reserved, no or reaches invoicing, the ERP or e-mails, and a cancellation on the simulated account cancels it quietly (no , no refund). Other plugins can skip such orders by ; the proof is .
Nothing is ever sent to Allegro in demo mode.
Events
The plugin emits Medusa events with ids, codes and the mode, never buyer data, so you can wire a Discord ping or an e-mail without polling the admin:
: the circuit breaker disarmed a writer.
: an Allegro order is waiting for a person.
: a parcel, status or invoice could not be sent.
API routes
All admin routes need an admin session or token.
: status, counters, writers, plans, imports, outbox, issues, references, the last runs and, in demo mode, (the sample data not built yet). Reads only.
: demo mode, build the missing sample data now (202).
and : the device login. : forget the tokens.
with : a sync in the background (202).
: the snapshot, with (all, linked, unmatched, stock, ended_in_stock, ended, drafts, nokey), , , .
: the journal, with (all, open, sent, cancelled, unmatched, imported, held), , , ; every row carries its import and Medusa order.
with : arm or disarm , , , , or (409 with the reason when it cannot be armed).
: a plan, with , , , . with : a dry run now, or plan and apply in the background (409 when the writer is not armed). : take an item out of quarantine.
: the imported orders, with (all, imported, held, pending, attention, skipped, cancelled), , , . with : a preview of the next run, or a run now (409 when the writer is not armed). with : the catch-up import, queue the forms bought between two dates. : retry a held or skipped form. : a person checked an order that needed attention.
: what Allegro knows about one Medusa order (its import, parcels and invoices sent, returns and disputes), for the order card; for an order the plugin did not import.
: parcels, statuses and invoices. with : send what is due now. : retry a failed row.
: returns, disputes and claims, with (open, needs_reply, returns, disputes, claims, all). : refresh now.
Writes need a JSON body () or the header. A server error answers a plain message; the details go to the server log, masked. No route uses DELETE.
Works with Koda Plus hosts
An app that shows every Koda Plus plugin in one place (like medusa.koda.plus) reads Allegro through the shared contract and never needs to know its tables:
: the manifest (mode, configuration, writers armed, widgets, problems).
(or , up to 50; also and ): one line per record. An order has a line only when the plugin imported it, by its import row, never by order metadata: a changed or cancelled order after the import or a total that differs is red, a held import orange, an import under way blue, an imported order green. Its facts: (, code , the buyer login, priority 80), (code for cash on delivery or when paid on Allegro, priority 70), (the Allegro delivery method and pickup point, priority 60; InPost's own parcel fact at 80 wins in a host) and (the login, priority 60). A product or variant speaks through its linked offers: a stock problem (Allegro sells more than Medusa has, or a sold out variant still live) is orange, a live offer green, drafts and ended offers grey, with a fact that links the offer on allegro.pl (the sandbox host in sandbox mode, the plugin page for demo offers).
: counters (red), , and (orange), each with a link to its list (, , , ).
The cards register as for the zone (hidden for orders without a line) and for the zone ; a host that claims the zone shows them as a tab () and Medusa's own spot stays empty. Without a host nothing changes.
The page opens on deep links: (offers: , , , , , , , ; imports: , , , , , ; orders: , ; issues: , , , , ), (a search in that list) and when a filter alone is ambiguous, for example .
Public API
What other code may import: (the workflows and the functions below), (the module and its options) and . Type declarations ship with the package. Every other path is internal and may change in any release.
Workflows and functions
From : , , , , , , , , , and the functions behind them (, , , , , , , , , , , , ), plus (the contract routes as functions).
Security
Write allowlist: every request to the Allegro REST API goes through a check that lets GET and HEAD through and, for anything else, only the exact method and path of a writer that is armed right now: and with only (stock), (prices), and (parcels), (invoices), with an publication only (drafts). The bodies are checked too: a quantity must be a positive whole number, an offer is never activated. The only other POSTs go to the OAuth server.
Narrow scopes: read scopes, plus the write scopes of the writers allowed in , plus disputes and messaging only when switched on.
Encrypted tokens: AES-256-GCM with a random IV per write; the key lives in your environment, not in the database. A configuration mistake never costs the seller a new consent: a wrong key or a wrong client secret leaves the tokens in place, and only Allegro's (the consent itself is gone) disconnects the account. rotates the key.
Admin writes from the admin only: every write to needs a JSON body or the header, which a form on another site cannot send, so a cross-site request cannot arm a writer or disconnect the account.
Reserved metadata: the store routes (carts, line items, the customer) refuse , and in shopper metadata (400 ). The plugin never trusts those keys anyway: its own tables are the record.
One refresh across processes: a lease in the database serializes token refreshes between a server and a worker, because each refresh hands out a new refresh token and the previous one stops working about a minute later.
Leases and locks: one stock, price or draft run at a time across processes; one importer per marketplace order through the shared lock.
Secrets stay on the server: the client secret, the keys and the tokens never reach the admin or an answer. They and any long token-like string are masked in logs, stored errors and the admin; a server error answers a plain message without the exception text.
Rate limited, with retries only for transient errors: network, 5xx and 429. A write that got no clear answer is never repeated blindly: it is looked up on Allegro first.
Personal data
The plugin's own tables store ids, statuses, amounts, dates, reason codes and reasons, never a buyer's name, address, e-mail or phone, and never the text of a dispute or message. The import row of an order keeps the buyer's Allegro login, the delivery method and the pickup point (for the order card) and a short hash of the delivery and invoice data (to notice a change after the import), not the data itself. The order import needs the buyer's data to ship the order, so it puts it where any store order keeps it: in the Medusa order (the delivery and invoice addresses, the phone, Allegro's masked buyer e-mail, the buyer login and the NIP when an invoice was asked for). No customer account is created. In demo mode every buyer is fictional, at .
Out of scope
Writing offers from scratch (descriptions, photos, parameters): drafts by EAN reuse a product from the Allegro catalog, and a person activates them on Allegro.
Offer content, renewals and reactivation of ended offers; promotions, price automation rules on Allegro, fees and campaigns.
Talking to buyers: messages, disputes, claims, accepting returns and refunds stay in the seller panel, which the plugin links to.
Instant stock pushes: the stock writer runs on its 15 minute schedule.
Labels and courier orders (Allegro Delivery, Wysyłam z Allegro): the plugin sends the tracking numbers your fulfillment already has.
Issuing invoices: the Fakturownia plugin or your own tool does it, the plugin attaches the PDF.
More than one seller account per store, or an Allegro marketplace other than allegro.pl for the import.
A run against a real Allegro account: the writers are tested against fakes and in demo mode on Medusa 2.15.3, and every call follows the official documentation (). Start in the sandbox.
Uninstall
Disarm every writer in Settings, then Disconnect the account. The consent stays on the Allegro side until the seller removes it in the account settings (Allegro, Moje Allegro, connected apps).
Remove the plugin from and the package from .
The tables stay with your data; drop them by hand when you no longer need the history. Imported orders stay in Medusa with their metadata, as any order would.
After a demo: the demo orders (, channel "Allegro (demo)") reserved nothing; cancel or archive them, then delete the "Allegro (demo)" sales channel.
Compatibility
Medusa 2.12 to 2.21 (peer range ) and Node.js 20+. The release of each version runs the smoke test on a fresh Medusa 2.12.6 and 2.21.2 app: migrations, build, start and the admin pages. Developing the plugin needs Node.js 22.6+ (the tests run the TypeScript sources directly).
Development
covers the parsers, the matching, the stock check and both planners, the event journal with opaque ids (pages, restarts, repeats), the order import state machine (exactly once, the shared lock, drafts finished after a crash, ownership by the import row), demo orders that are never placed or paid, the outbox, carriers, invoices, issues, drafts, gross prices only, the write allowlist, the writers, the circuit breaker and its event, tokens kept on key and secret mistakes, the route guards, the store SQL, the encryption, the demo simulation and the contract. To try the plugin in a Medusa app, run here, then in the app.
Commercial support
Built and maintained by Koda Plus, a Medusa agency from Poland. The device login, the offer read and the matching come from the Allegro integration we maintain for a tyre and wheel retailer with about 4 000 live offers, next to our OLX, BaseLinker, Subiekt nexo and Fakturownia integrations. Need a custom Allegro flow, an integration or a Medusa store? Write to kontakt@koda.plus.
Trademarks
Allegro and the Allegro logo are trademarks of their owner, used here only to identify the marketplace this plugin connects to. This is an independent integration built on the public Allegro REST API, not affiliated with or endorsed by Allegro.
Opaque event ids in the order import; demo mode only with and demo orders that are never placed or paid; gross prices only for prices and drafts; tokens kept on configuration mistakes; reads that never write; writes only from the admin or a server; the contract with embeddable product and order cards and deep links; events for your alerts; type declarations. Full list in CHANGELOG.md.