· build vs buy

Build vs Buy: What Computing Per-Fill Margin Actually Takes

The weekend-project version is revenue minus cost. The seven problems underneath it are why it is never a weekend, and when building it yourself is still the right call.

If you have an analyst, a data warehouse, or a son-in-law who writes SQL, someone has already suggested it: we do not need a vendor, margin is revenue minus cost, we can build it.

They are not wrong about the formula. They are usually wrong about the seven things underneath it. A pharmacy that reads this and builds anyway has made a good decision with open eyes, which is a better outcome than a purchase resented in month three.

Problem 1: getting the events at all

Margin arithmetic is downstream of a data feed, and the feed is most of the work.

A nightly export will get you month-end analysis. It will not get you a flag before the wholesaler order goes out, which is the only version of this that changes a decision. Real-time means subscribing to events as adjudication happens, and that means a credential, an endpoint that is up when the pharmacy is open, and a plan for the hours it is not.

Then the parts nobody scopes:

  • Redelivery. Your endpoint is down for six hours and the source retries. Do you now hold one copy of each event, or three?
  • Idempotency. The answer is a stable key derived from the event plus a unique index that lets the database reject the duplicate. Checking first and inserting after races with itself under concurrent retries.
  • Backfill. After an outage the gap must be filled, and you need to know it was.

None of this is exotic. All of it is a week nobody planned.

Problem 2: whether you archive before you parse

This is the decision that separates a system you can trust from one you cannot, and it is invisible on day one.

The tempting design reads the payload, extracts the fields you care about, writes a tidy row, and discards the rest. It works until your first parsing mistake. Then the data needed to correct it is gone, and nobody can send it to you again.

The alternative is to store every payload exactly as received, before anything interprets it, and treat everything downstream as a projection you can recompute. A parsing bug becomes a replay instead of a permanent hole, and the same archive is what makes an audit request about claims from fourteen months ago answerable.

If you build, archive first. It costs storage, which is cheap, and it buys the ability to be wrong recoverably, which is not.

Problem 3: the arithmetic is a floating-point trap

Margin is a subtraction of two nearly equal numbers, which is exactly where binary floating point is proportionally worst: the error that was negligible against each input is not negligible against the difference.

The canonical example is that in most languages, taking 8.115, multiplying by 100 and rounding gives 811 cents rather than 812, because the stored value was never really 8.115. Across a month of fills your report is then wrong by an amount that is small, real, and impossible to explain to an accountant.

The fix is to hold every money value as an integer number of cents from ingestion to display and never let a float touch it. That is a discipline rather than a line of code, so write a test that fails the build when a money-named column is typed as a float.

Problem 4: cost is the hard half

Reimbursement arrives on the adjudication response. Cost does not.

To compute margin you need what you actually paid for that NDC in that package size. That means ingesting wholesaler invoices, matching them to dispensed products, and handling the mismatches:

  • NDC formats. The same product appears as a 10-digit code in one place and an 11-digit code in another, with the zero padded into a different segment depending on the labeler/product/package split. Matching without normalising is how a drug ends up appearing to have no cost.
  • Package versus dispensed quantity. Your invoice prices a bottle of 90 and the fill dispensed 30. Scaling is easy, but rounding on every line accumulates error across a month, so round once at the end.
  • The fallback. Without an invoice, NADAC is the usual substitute and carries its own caveats. It is a survey of retail community pharmacy invoice prices that excludes mail order and specialty, and it excludes rebates and off-invoice discounts received after the invoice is paid. Since the December 2024 updates, CMS has calculated monthly generic rates on a three-month moving average to damp volatility from fluctuating survey participation. It is a benchmark, not your cost, and a system that does not say which it used will be believed as though it were.

Problem 5: deciding what to show when you know nothing

The case that separates a careful build from a careless one is the fill with no cost on file at all.

The lazy implementation treats a missing cost as zero. Every such fill then reports as pure profit. That is wrong in the most expensive possible direction, because it hides losses rather than raising false alarms, and the report looks healthiest exactly where your data is worst.

The correct behaviour is to compute no margin, say so, and flag the fill as needing a cost. More code, a less satisfying dashboard, and the difference between a number you can act on and one that will eventually embarrass you.

Problem 6: the cases that are not a simple fill

  • Reversals, and partial fills later completed.
  • Secondary and coordination-of-benefit claims, where more than one payer contributes and revenue for one fill arrives in pieces.
  • 340B and other contract pricing, where the invoice cost is not the cost that applies.
  • Post-adjudication adjustments, which still exist in various forms depending on the line of business and arrive long after the fill.

Each is a rule. None is impossible. Together they are the difference between a prototype that works on the happy path and a system your controller will sign off on.

Problem 7: it has to keep running

This is the cost that never appears in the estimate. Your pharmacy system gets upgraded. A field changes name. A new payer starts populating a field that was always empty. The endpoint certificate expires on a Saturday. Someone has to own that, and if your build has one author who then leaves, you have a reporting outage and nobody who can read the code.

When building is genuinely right

Buying is not automatically correct, and here is where we would tell you to build.

  • You already have the warehouse and the people. If prescription data already lands somewhere you control and someone competent owns it, the marginal cost of margin logic is far lower for you than the market price.
  • You need it joined to things a vendor cannot see. Payroll, delivery costs, your general ledger. A vendor computes margin on the fill. Only you can compute profit on the store.
  • Your contracts are unusual. Chains, 340B contract pharmacy arrangements and LTC operations often have economics a general product models badly.
  • You want no vendor in the data path. A legitimate position, and one no amount of security documentation should have to argue you out of.

When buying is right

  • The value is in acting within minutes, and you do not want an on-call rotation for a webhook.
  • Nobody on staff will own it in eighteen months.
  • You want the cost basis problem solved by someone whose full-time job it is.
  • You would rather spend your one scarce technical person on something that differentiates your pharmacy, which margin arithmetic does not.

What buying from Attergo actually gets you today

The platform is eight products on one event spine: Margin, Billing, Audit, Authorizations, Inventory, Compliance, Intelligence, and Integrations, which is the spine itself. Connecting it once is what makes the others cheap to switch on later, rather than eight separate integrations into your pharmacy system.

The platform runs on that spine end to end: real-time ingestion from PioneerRx’s Rx Event API with a per-store credential, an immutable archive of every payload as received, and per-fill margin against acquisition cost from your wholesaler invoice or NADAC, with the basis and its confidence shown on every fill, feeding eight products from the one connection.

So the real comparison is not a margin query against your SQL. It is a maintained, evidence-grade platform against a side project that has to survive staff turnover, payload changes and every audit that arrives after the person who wrote the script has left.

The middle path most people miss

You do not have to choose completely. Ask any vendor for a structured export of your own normalised events, and check the contract says you can have it. Let them run the ingestion, the idempotency, the archive and the cost matching, then build your own analysis on the clean output.

The part that is genuinely hard to operate becomes somebody’s full-time job, and the part specific to your business stays yours. If a vendor will not agree to that export, you have learned something more useful than anything in their demo.

See this analysis run on your own claims.

Attergo prices every fill, verifies every encounter and holds the evidence, in real time, on your data.