Skip to main content
Back to all posts
Sep. 202610 min read

Sixteen real calls to pharmacies, zero prices, and the measured reason why: the agent talks over the pharmacist

Pharmacies paid about 43 cents for thirty metformin, a number CMS publishes weekly from invoices. What you pay is different at every counter and published nowhere, so the only way to learn it is to phone. Sticker gives a CALL-E phone agent a drug and a ZIP, reads the federal NPI registry, calls the pharmacies you authorize, and joins every quoted price to CMS NADAC. Sixteen real calls in one Manhattan ZIP produced zero prices and zero refusals. The platform's own event stream showed why: 24 collisions across 15 traced calls where the agent opened its turn while the pharmacist was still speaking. Filed upstream as issue #415, picked up by a maintainer the same day. The contribution merged as PR #404 after five review passes. Zero is a result if you say how you got it.

CALL-EPhone agentsCMS NADACNPPESPharmacy pricingTurn-takingUpstream contributionPythonHackathonShowDev
I wrote this post for the CALL-E phone-call agents hackathon (Sep 2026), and built Sticker for the same submission. Results page at jonathansolvesproblems.github.io/sticker, source at github.com/JonathanSolvesProblems/sticker, contribution merged upstream at CALLE-AI/awesome-phone-call-agents PR #404. #calle
The claim in one sentence: sixteen real calls to licensed pharmacies in one Manhattan ZIP code produced zero prices, and the reason is measured rather than described: 24 collisions across 15 traced calls, counted from CALL-E's own event stream, where the agent opened its turn while the pharmacist was still speaking. The benchmark the prices would have been compared to is CMS NADAC, 43 cents for thirty metformin that week, which I did not author. What is not claimed: a single cash price. The results page shows an empty price column, the transcript of why, and a bug report the platform is acting on.
Sticker's results page header: the drug, the ZIP code, the CMS NADAC benchmark of 43 cents for thirty metformin, and a price column with nothing in it.
Sticker phones pharmacies for a prescription's cash price. The benchmark is CMS NADAC: 43 cents for thirty metformin, cited to the week it was published. The price column is empty, and the rest of this post is why.

The number that is published, and the one that is not

Pharmacies nationally paid about 43 cents for thirty metformin tablets. That is the national average acquisition cost the federal government publishes every week, surveyed from pharmacy invoices, and anyone can look it up. What you pay is a different number. It is different at every counter, it changes, and it is published nowhere. Pharmacy contracts with benefit managers commonly require the pharmacy to hand the PBM its lowest price, so pharmacies keep the posted cash price above their negotiated rates instead of competing on it. Around 19,000 independent pharmacies sit largely outside the comparison sites. So the only reliable way to learn a cash price is to telephone the counter, and that is the established research method: a 2020 study in Psychiatric Services phoned 265 pharmacies over one month and found a 30-day supply of one generic ranging from $29.99 to $1,345.00 inside a single metro area. Those studies took teams of people weeks. That is the thing a phone agent should be able to do in an afternoon.

Three rules that make the headline smaller

Give Sticker a drug and a ZIP code. It reads the federal NPI registry for licensed community pharmacies near that ZIP, filtered to the walk-in retail taxonomy so mail-order and specialty pharmacies cannot quietly corrupt the sample. It calls the ones you authorize and asks one question: the cash price, no insurance, for this quantity. It reads back a sorted price map and joins every price to CMS NADAC, so each row also shows the national average pharmacies paid for the same bottle. The markup column is the point, and it is not our arithmetic about our own accuracy: a price a pharmacist said aloud, divided by a number CMS published that week. Three rules decide what counts. A price counts only if a dollar amount was said aloud for the quantity asked about; a quote for a different bottle size is reported and never rescaled, because ninety tablets are not three thirties. A refusal stays in the denominator, because the share of pharmacies that will not price a drug by phone is a finding about opacity, not a gap to drop. And a completed call is not an answered question, because a voicemail box returns status completed with task_completed true, so the structured answer decides, never the status.

The Sticker console running a simulated survey under a SAMPLE DATA banner: invented pharmacies, no calls placed, prices landing row by row against the NADAC benchmark.
The console running a simulated survey under its SAMPLE DATA banner: invented pharmacies, no calls placed, prices landing row by row. Labelled as simulated on the surface itself, so the sample board can never be mistaken for the real one.

Sixteen calls, zero prices, zero refusals

Sixteen real calls to licensed pharmacies in one Manhattan ZIP code, and not one produced a price. Not one refused either. Every conversation that reached a person ended within about forty seconds, usually right after the question was asked. The first call reached an after-hours voicemail box and the agent waited on it for three and a half minutes, because nothing in the API says what to do at a recording. That was fixable in prose. What was not fixable in prose was the thing I found next. CALL-E's own event stream logs bot-speaking and callee-speech events with timestamps, and reading them showed the agent opening its turn while the pharmacist was still mid-greeting. Six separate speech events from the callee bracket the moment the agent starts talking. A person who hears a machine speaking across their own words says hello, and hangs up.

Fifteen real calls drawn as two-channel timing traces over sixty seconds, callee speech on one channel and agent speech on the other, with magenta marks where the agent starts talking while the pharmacist is still speaking.
Fifteen real calls drawn as two-channel traces over 60 seconds. Magenta is the agent opening its turn while the pharmacist still speaks. The finding is visible without reading a word, and it is counted from the platform's own event stream, not from my impression of the audio.

I rewrote the opening four times, ending with a single word, hello with a question mark, followed by silence until the line was quiet, and the agent still cut in. There is no request parameter for turn-taking: the create call has six fields and rejects unknown keys. Another contributor's app hit the same wall independently. Chain pharmacies were a second wall: one phone tree demanded a ten-digit phone number for identity verification, could not validate a caller with no patient record, and routed straight to voicemail. A price check cannot get past that by design. And the account has a concurrent-call limit documented nowhere; I found it by exceeding it, HTTP 429 account_concurrency_exceeded. That one turned into a feature, because a 429 means nothing was dialled, so it is the one error that is safe to wait out and retry.

The reading of the trace board: fifteen calls, seven answered by a person, zero prices, twenty-four collisions, with a link to the upstream issue where a maintainer is reproducing it.
Fifteen calls, seven people answered, zero prices, 24 collisions. Filed upstream as issue #415 with reproducible call IDs, where a CALL-E maintainer asked for examples the same day and is reproducing it.

The side effect is a telephone ringing at a working counter

The safety surface is the part I spent the most time on. Discovery never dials: it writes a candidate list a person edits into an allowlist, and an empty allowlist authorizes nothing rather than everything. Numbers are validated as strict ASCII E.164, because Python's digit class also matches Arabic-Indic and fullwidth digits and would dial something other than what you read. The API origin is parsed and allowlisted before the key is attached to a header, and redirects are off. Idempotency keys are derived from request content, so a crash and a restart reuse the key instead of dialling twice. A rejected request is a fact, but a timeout is not, so an ambiguous create halts the run for a human rather than retrying. The agent's first word is only hello, and it waits for the pharmacy to finish its greeting before saying anything else. Then one sentence both discloses that it is an AI and asks the question, the disclosure before the question every time, including after a transfer. CALL-E does not announce itself and offers no setting for it, so it exists only in the task prose. That is why the test suite asserts on it.

Four independent safety gates each refusing on its own: an empty allowlist, a malformed number, an unrecognised API origin, and an ambiguous create result, with discovery output showing masked phone numbers.
Four independent gates, each refusing on its own. Discovery prints masked numbers; the exact list goes only to a file a person edits. Every control fails closed, and every one is asserted by the 94-test suite.

Merged upstream, after five passes that found real things

The contribution merged upstream into CALLE-AI/awesome-phone-call-agents after five review passes with the repository maintainer, and three of them found something real in the code and the claims: false claims about what a pharmacy paid when the benchmark is a national average, real-call timings that had crept into docstrings as engineering rationale, an invented per-call cost, a call counter that credited calls a halted run had prevented. All fixed, and the suite went from 61 tests to 94 and from 47 seconds to under 2. A fact learned from a live call is a real-call artifact even when it is phrased as the reason for a design decision. The maintainer caught me reintroducing exactly the thing I had been told to remove, twice, because I had written it as rationale rather than as data. The behaviour it justifies can go in the repository. The observation that produced it cannot.

GitHub's merged banner on pull request #404 in CALLE-AI/awesome-phone-call-agents: a runnable app and a reusable skill across 24 files.
Pull request #404 merged upstream into CALL-E's community repository: a runnable app and a reusable skill across 24 files. Merged, not drafted, which is the version of an upstream contribution that counts.
Issue #415 on the CALL-E community repository: the turn-taking bug filed with reproducible call IDs, and the maintainer's same-day reply asking for examples.
The turn-taking bug filed with reproducible call IDs. A CALL-E maintainer asked for examples the same day and is reproducing it. That is the sponsor's engineer investigating a bug their platform has, using evidence I supplied.

What is not claimed

A single cash price. Zero is a result if you say how you got it. I could have shipped a simulated board with prices on it and a paragraph about live testing pending. Instead the results page shows sixteen real calls with nothing in the price column, the transcript of why, and a bug report the platform is acting on. Everything else about the project worked: the registry lookup, the federal benchmark, the schema, the safety model, the halt logic. None of it mattered, because the conversation never got to the point where a price could be said. The whole product lives or dies in about two seconds of turn-taking that I do not control. And a survey method built for human callers does not transfer to a disclosed AI caller without the platform's help. That is a finding about the tool, not about the pharmacies, and I have tried to say it that way everywhere. NADAC is a benchmark and not an invoice: the multiple tells you how far a price sits above what a drug generally costs to buy, not what any one shop paid its wholesaler, and the report says so on every run.

The closing summary card: sixteen real calls, zero prices, twenty-four collisions across fifteen traced calls, one real two-channel trace, and the note that nothing on it is invented.
Sixteen real calls, zero prices, and the measured reason why. One real trace, the four figures, nothing invented. I would rather be judged on that than on a board of prices a script put there.
Related project

Sticker: phones pharmacies for a prescription's cash price and prices it against the federal benchmark. Sixteen real calls, zero prices, and the measured reason why

View the project