Case notes

Case note: credit checks that stopped blocking order capture

TL;DRKeep credit limit checks off the order-submit path. Treat credit state as an event-driven projection updated by payment and invoice events, so the app reads it instantly. Over-limit buyers get an in-app soft-block with a clear next step; the only synchronous hard gate is at delivery release. SAP stays the source of truth.

We stopped asking the ERP for permission on every order. Credit state now lives as an event-sourced projection: a read model the order app updates from payment and invoice events on the bus and reads in single-digit milliseconds. Order capture never waits on a credit call. Buyers over their limit get a soft-block with a clear next step, and the only synchronous hard gate sits at delivery release, where a real financial commitment actually happens.

What breaks when the credit check lives in the order-submit path?

The classic route-to-market pattern makes order submit call an ERP credit check synchronously. It reads fine in a demo and fails under load. When the financial core is busy — month-end, a batch window, a slow join — that inline call stretches to seconds or times out, and a timeout on the single hottest path in the business either blocks the sale or silently drops it. In our own load tests the synchronous check added anywhere from 300 ms to several seconds to p99 submit latency under ERP contention, which is precisely the budget we defend when we take order capture from thirteen seconds to sub-second.

The subtler failure is where the block lands. A boolean at submit means genuine credit problems surface at the warehouse: the truck is loaded, a block fires at delivery, and what should have been a quiet conversation with the buyer becomes a returns-and-restock event. The check was in the wrong place and it answered the wrong question.

Why treat credit as a projection instead of a question for the ERP?

The ledger truth belongs in SAP and we leave it there; the financial core is not something you rip out to speed up a checkout. But what is this customer's available credit right now? is a read-heavy question asked on every single order, and answering it with a synchronous round-trip into a batch-oriented finance system is the wrong coupling. The events that move the answer — invoices posted, payments received, limits changed — already flow on the bus. We fold them into a per-customer credit projection (limit, open exposure, overdue buckets, available balance) and let the app read that.

This is not exotic at the frontier. Public materials describe how the world's largest brewer's B2B ordering platform moved credit decisioning off the slow path:

...reduced wait times for a loan from an average of two weeks to hours.

The same materials report over 500,000 users leveraging short-term credit across a network that, as of April 2023, ran 3.1 million monthly active users in twenty markets. You do not get to hours-not-weeks by making the credit call faster; you get there by making credit a live data product instead of a synchronous gate.

How do you fix it without touching the SAP core?

Seven moves, none of which require reopening the financial system:

  1. Publish the events you already have. Emit invoice-posted, payment-received, credit-limit-changed and order-reserved events onto the bus. SAP stays the ledger of record; it just also narrates what it does.
  2. Build the credit projection. A per-customer read model — limit, open exposure, overdue amount and age, and available = limit minus exposure minus open reservations. Make it idempotent and order-tolerant, because payment events will arrive out of sequence.
  3. Reserve on order; do not ask permission. On submit, decrement available optimistically with a reservation event. Never make an inline call into the finance system on the hot path.
  4. Define three states, not a boolean. Available, soft-block and hard-block, each enforced in a different place (see below).
  5. Move the hard gate to delivery release. The only synchronous, blocking check happens at pick-and-load, where a real financial commitment is made — and even there it reads the projection first, with SAP as the tiebreak.
  6. Reconcile continuously. A scheduled job compares the projection against SAP balances and emits a correction event on any drift, with a manual override for the credit desk.
  7. Show the state wherever a human sells. Surface it in the buyer app and in the telesales console that replaced printed call sheets, always with the next step attached to the block.

The three-state model is the part worth getting right:

StateWhat the buyer seesWhere it is enforced
AvailableNormal order capture, no interruptionNowhere — it is a read
Soft-blockOrder accepted, flagged: over limit, pay down or trim the basket to release for deliveryOrder app, non-blocking
Hard-blockDelivery will not release until the balance clearsDelivery release, synchronous

What did not go smoothly?

Reconciliation drift bit us early. One legacy posting route settled payments through a batch window our emitter did not cover, so for a few hours the projection still showed customers over their limit after they had actually paid. They sat in soft-block, and a rep had to clear them by hand. It was not data loss — it was a coverage gap: we had instrumented the real-time payment path and missed one back-office route into the same ledger. The fix was a reconciliation heartbeat every few minutes and an alert when the projection and SAP diverge beyond a threshold. An event projection is only as trustworthy as your least-instrumented posting path, which is the same lesson that shows up when these projections feed reporting and someone needs to answer the CFO's question the same afternoon. A wrong number in a dashboard and a wrong number in a credit block have the same root cause, and folding events into read models like this is the pattern behind everything on our shared event bus.

The interesting move is the next one: once available credit is a live projection rather than a locked door, meeting a buyer who has just hit their limit with a short-term top-up offer becomes a pricing and risk decision, not a plumbing problem. That is the road the fintech benchmarks are already on, and it only opens once credit stops being a synchronous gate on the order and starts being data you own and can act on in the moment.

Frequently asked questions

Doesn't moving credit off the ERP call path risk over-extending credit?

No. SAP stays the source of truth and the projection reconciles against it continuously. Orders reserve credit optimistically, but delivery release is a synchronous hard gate that reads the real balance, so nothing physically ships past the actual limit.

How fresh is the projected credit state?

It updates on each payment, invoice and limit-change event, usually within seconds. A scheduled reconciliation job compares the projection to SAP balances and emits a correction on any drift, so staleness is bounded by your reconciliation interval, not by batch posting windows.

What happens to a buyer who is genuinely over their limit?

They still place the order, but it enters a soft-block: the app flags it and shows a clear next step, such as paying down a balance or trimming the basket. Delivery will not release until the balance clears, so the credit limit is enforced without killing the sale.

Stuck with exactly this?

BrewOS builds the full route-to-market stack for global brewers — order capture, stock, loyalty, returnables, delivery and analytics on one event bus, run by a team of ~20 engineers. Bring us the feature that’s been stuck the longest and we’ll show you how we’d ship it in days.

Book a 30-minute walkthrough