What breaks between your ERP and your storefront on Black Friday

Home / Blog / What breaks between your ERP and your storefront on Black Friday


Black Friday 2026 is November 27. Cyber Monday is November 30. From the end of August that is a little under thirteen weeks.

That is not your deadline, though.

Adobe defines peak season for its cloud merchants as roughly mid-November through mid-January. It also asks that surge capacity requests for the Black Friday window go in as far ahead as possible, because capacity there is limited (Adobe Experience League).

Stripe's peak season data says the same thing from the buyer side. Last year spending sat near its Q4 baseline through the first half of November. Then it "turned sharply upward around November 17, 10 days before Black Friday," and fraud activity had already started climbing on November 8 (Stripe).

So the date that actually grades you is the second week of November. That is ten weeks out. Take out a real regression pass, and two quiet weeks where a change is live and you can still watch it, and you have roughly seven weeks of building left.

Seven weeks is plenty. It is not enough to start over.

Why does peak load break the ERP seam and not the storefront?

Because the storefront is the part that was built to absorb a spike, and the ERP is not.

Full page cache, a CDN, more web nodes, more PHP workers. An ecommerce platform has a whole toolkit for "more people arrived." Your ERP has none of it.

Epicor Prophet 21, Microsoft Dynamics, NetSuite, Infor and Salesforce were all sized for the back office. They are sized for the number of people who work there, not for the number of people who might open a product page on a Friday morning in November.

Between the two sits a set of jobs. An inventory feed. An order export. A price sync. A customer sync. Every one of those is a queue with a fixed drain rate, and Q4 does not raise the drain rate. It raises the inflow.

So the failure is almost never "the site went down." It is quieter than that. The two systems stop agreeing, and they keep taking orders while they disagree.

The mechanics below apply the same way on Magento Open Source, Adobe Commerce and a Mage-OS build. What changes between them is the support path, not the seam.

What happens when the inventory feed and reservations disagree?

You oversell, or you hide stock you actually have. Both cost you, and the second one is harder to notice.

Here is the piece people miss. On Magento 2.3 and later, the number a shopper sees is not the number in your quantity field. Adobe's Inventory Management keeps a separate ledger of reservations: when an order is placed, a reservation goes in, and salable quantity becomes the source quantity minus the reservations still outstanding. The reservation is cleared and the real quantity deducted when the shipment is created (Adobe Experience League).

Now bring in an ERP feed that writes absolute quantities. The ERP does not know what a reservation is. It sends the number sitting in the warehouse and the import writes it. Every order placed since the last file, real orders that are not yet shipped, is silently uncounted.

The number on the page looks right. It is wrong by exactly the volume of your best week.

We watched a version of this play out on a merchant's store during a December order wave. Bundles were showing out of stock while the warehouse had stock. The clock was running, a large institutional order was pending, and the emergency fix was to hard-code a big quantity onto every component and bypass the feed entirely. It worked. It is also, said plainly, a decision to oversell on purpose, and it stayed in place longer than anyone wanted.

What to do in the next three weeks:

bin/magento inventory:reservation:list-inconsistencies

Run it today. Run it against a normal week's data, not a quiet one. If it prints anything, you already have drift and Q4 will multiply it. Adobe ships the repair side too:

bin/magento inventory:reservation:list-inconsistencies -r \
  | bin/magento inventory:reservation:create-compensations

Then decide the harder question, which is not a command: does your ERP feed set quantity, or adjust it? A feed that sets an absolute number needs to account for open orders before it writes, or it needs to write to a source your salable calculation treats correctly. That decision is a week of work in September and a very bad week in November.

What if an order never reaches the ERP?

Then the customer thinks they bought something, and nobody in your warehouse knows about it.

This is the failure mode we see most often and it is nearly always the same shape. The order export does not pull every order. It pulls orders in certain states. Somebody adds a payment method, or a fraud hold, or a new status, and orders that land in that state simply never get picked up. No error is thrown. Nothing is red. The export ran fine; there was just nothing in it that matched.

On one B2B store, an order confirmation went out to the buyer and the ERP never received the order. It was caught because a person noticed that the order numbers in a report jumped by one. That is the real detection mechanism at a lot of distributors: a sharp human, reading a list.

A sharp human is not a control. During peak week they are also doing five other things.

What to do: a daily reconciliation that counts orders on the storefront for a window, counts orders in the ERP for the same window, and shouts when the two numbers differ. It does not need to be clever. It needs to exist, and it needs to page somebody. Then go read your export profile and write down every order status it selects, and every status it does not, and ask which of the second list can happen.

Why does contract pricing go wrong exactly when it matters most?

Because customer-specific pricing is the one number on the page that is expensive to compute, and every performance decision you make in Q4 pushes you toward caching it.

For a B2B distributor this is the whole ballgame. The price a customer sees is not the list price. It is their contract price, their tier, their negotiated discount, and it lives in the ERP. That leaves you three bad options and one good one. Call the ERP on every product view and inherit its response time. Cache the price and risk serving a stale one. Copy the prices into the storefront and let them go out of date.

Or split the difference on purpose. Cache for browsing, and go to the source of truth at the moments that have to be exact: the cart, the quote, and the order.

Two failures worth checking specifically before November.

The first is a price list that updates in the ERP and never lands on the storefront. Someone runs the annual pricing update, the ERP is correct, and the site quietly sells at last year's numbers into your highest volume week.

The second is stranger and we have hit it for real: a custom order form returned a price of zero for products whose discount was set as a percentage-based tier price rather than a fixed one. The code asked for a final price, did not get a number back in the shape it expected, and defaulted to nothing. It only affected one pricing configuration, which is exactly why it survived testing.

What to do: take your ten largest accounts, take five SKUs each, and compare what the ERP says to what the storefront charges those accounts at cart. Fifty rows in a spreadsheet. Do it in September, and again the week before the freeze.

What happens when the sync job quietly falls behind?

Everything keeps working, gets slower, and then stops being true.

Three things drift under load, and all three are worth checking now.

Indexer mode. Adobe's own wording is the thing to notice. Update on Save refreshes indexed data as the change is made. Update by Schedule indexes "according to the schedule set by your cron job" (Adobe Experience League).

So if an ERP feed writes thousands of price and stock rows, Update on Save drags thousands of reindexes along with it. We have seen a store move its indexers onto a schedule and roughly halve the time a feed run takes.

Batch size. Large indexer batches time out on a busy box. Small ones take longer but finish. Peak season is a good time to prefer finishing.

Consumers. If your integration writes to a queue, a consumer that dies stays dead. Nothing about the site changes. The queue just grows. If you have not read how a queue actually works on Adobe Commerce and Magento, that is a good half hour before Q4.

And the one that should scare you most: a job can stop running and take a very long time to be noticed. On one store we found a custom inventory job that had not run automatically since a platform upgrade more than a year earlier. Nothing alerted. The upgrade had quietly unscheduled it, and it surfaced only when a large wholesale order failed to process and somebody went looking.

What to do: alert on the absence of success, not on errors. "This job has not completed in ninety minutes" catches a dead cron. "This job threw an exception" does not, because a job that never starts never throws. Add queue depth and last-successful-run time to whatever dashboard you already look at.

What does a failed checkout look like to a B2B buyer?

Usually, like your website is broken. Which is a shame, because it usually is not.

The last few feet matter here because a B2B order is worth more and the buyer is at work. We looked into a lost order on a distributor's store recently. The card was declined for one reason and one reason only: the security code did not match. The site had that answer in the gateway response the whole time. What it showed the buyer instead was raw gateway text saying a duplicate transaction had been submitted.

So he did the reasonable thing. He guessed. He changed his billing address, which had been correct, and tried again. Each retry inside the gateway's duplicate window was rejected before it ever reached the bank, and each of those rejections was counted as a checkout failure. The payment module's default is five failures in twenty-four hours, so a legitimate buyer with a good address and one mistyped code was locked out of checkout for a day.

Peak season does not create that bug. It multiplies it, because more attempts means more declines means more of these.

What to do: map gateway responses to human sentences. A card code mismatch should say the security code does not match, and that a reissued card keeps the number but changes the code. A duplicate-window rejection should say "we are still processing your last attempt, give it a minute" and should not count as a strike, because it never reached the issuer. That work is small, it is testable, and it is worth more in November than any new feature on your roadmap.

What can you still ship before the freeze, and what should you not start?

Ship the things that make failure visible. Postpone the things that change how data moves.

Yes, start now:

  • Reconciliation between storefront and ERP order counts, with an alert.
  • Queue depth and last-successful-run alerting on every sync job.
  • Reservation inconsistency check, and the compensation run if it finds any.
  • Checkout error copy that maps to real gateway reasons.
  • A pricing spot check across your largest accounts.
  • A written runbook: who to call at the ERP vendor, how to place an order by hand, how to turn the feed off.

Only if it is already scoped:

  • Changing how the inventory feed writes quantity.
  • Moving pricing to a cache-plus-live-lookup pattern.
  • Indexer and batch tuning, which is low risk but wants a load test.

No, not this year:

  • A new ERP connector.
  • A replatform.
  • Anything that changes the direction a field syncs.

The projects that die in Q4 are not the ambitious ones. Everybody knows to say no to those. The ones that die are ordinary changes approved in October with a November lead time.

How do you prove it before November?

Load test the seam, not the site.

Almost every peak season test we see hammers the storefront with page views. That is the half that scales. The half that will not is the ERP.

So test that half instead. Replay a real peak day's order volume, at real peak-day concurrency, through the actual integration and into a sandbox ERP. Then watch the queue, not the response time.

You are looking for one number. How far behind does the sync get, and does it catch up?

A queue that runs eight minutes behind and drains overnight is fine. A queue that is eight minutes behind at 10am and forty minutes behind at 2pm is a different animal. That one will be hours behind on Black Friday. Hours behind means stale stock, stale prices, and orders your warehouse has not seen.

Do that before the freeze, while you can still change something. Pick your freeze date now and tell everyone, including the people who will want an exception. Adobe's peak window opens in mid-November, so the second week of November is the honest place to put it.

Where to start if you only do one thing

Run the reservation check and the order count reconciliation this week. Together they are maybe two days of work, and between them they cover the two failures that cost the most and announce themselves the least.

Then read the ERP and integration readiness checklist, which is the longer version of the source-of-truth argument underneath all of this, and if you are on Prophet 21 specifically, what a P21 integration actually involves. We have been connecting P21 to storefronts since 2018, and the ERPs we have worked inside are Microsoft Dynamics, Epicor Prophet 21, NetSuite, Infor and Salesforce. Every single one of those projects spent more time on "which system owns this field" than on the API.

If your storefront and your ERP are already arguing and November is the wrong month to find out how badly, that is the seam we work on. Happy to look at your sync jobs with you and tell you which of the list above you can safely skip.

Related reading: the Adobe Commerce integration guide for how the APIs fit together, and B2B order approval workflows if the orders that reach your ERP need a human yes first.


Written by X2Y.DEV
ERP Integration Adobe Commerce B2B Ecommerce Magento Mage-OS Peak Season
Back to Blog

0%