RyanShrum

AgelessRx

Automate the common case. Keep a human for the rest.

Two projects from my work building patient-facing and internal tools at a healthcare company. Each one takes a step that used to be manual, automates the common case, and keeps a person in the loop for the exceptions.

Team projects, described by what I owned. Figures are rounded percentages from internal data.

01 / 02

Automated identity checks

Replacing manual ID review end to end, with a person for the exceptions.

The problem

Every new patient's ID and selfie was reviewed by hand by customer service before an order could be approved: low-value, low-complexity work that grew with every new patient.

It cost patients too. The brief found that about half of those who skipped the ID and selfie step at intake never came back to finish it, and put the recoverable lifetime value at an estimated $750K to $1.49M.

What I owned

The vendor evaluation

Working prototypes of two vendors, compared head to head on capture, embedding, failure handling, admin handoff and resuming an abandoned session. I brought engineering's recommendation to product, who made the call.

Value before the finish line

The first release ran the vendor's records check silently at checkout and approved patients on the details they had already submitted. Intake didn't change and no one was rejected, but most patients stopped needing a manual review right away. The ID and selfie step followed in a second release.

The back-end

The verification model and migration, a vendor service behind an interface, and a signed webhook endpoint that rejects replayed and oversized requests. The checkout trigger logs vendor errors instead of throwing them, so it can never block a patient's checkout.

The admin review

The screen customer service uses when automation can't decide: the vendor's decline reasons, zoomable ID and selfie images, and a resubmission flow that messages the patient.

Reconciliation

The vendor confirms an ID is genuine, not that it matches what the patient typed. I designed and built the check that compares name, date of birth and address against what the ID reads, flags any disagreement on Admin Review, holds approval until a mismatched name or date of birth is settled, and settles them in one click. Customer service can filter the queue to find them.

I led it from the proof of concept through delivery and the later iterations. Another team built the patient-facing verification step on top of it.

How identity verification flows At checkout, a check starts with Persona's database records check, and it can never block the checkout. Persona reports the result to a signed webhook, which updates the patient's status. Verified patients are approved and their order moves on. Patients who need an ID are asked for an ID and selfie in the app, which Persona checks and reports back the same way. Anything Persona can't decide goes to admin review, where customer service approves it or asks the patient to resubmit, and mismatched names or dates of birth are held until settled. I built the checkout trigger, the webhook and status update, and the admin review. Another team built the ID and selfie step. Checkout Persona Signed webhook ID and selfie Admin review Approved starts the check, never blocks it database records check updates the patient’s status patient, in the app approve or resubmit; mismatches held the order moves on result verified needs an ID Persona checks it manual review approve resubmit What I built Built by another team Vendor
The flow in production, simplified. Most patients go straight across the top; the rest get an ID and selfie step, a person, or both.

Results

Identity review went from 100% manual, to about 86% automated with the first release, to about 95% with the second. Each release added a layer, and the gain held week after week.

Share of new patients verified automatically, by release Before the first release, identity review was 100% manual. After the first release, the database check verified about 86% of new patients automatically. After the second release, the ID and selfie step raised that to about 95%. 0% About 86% About 95% Before all by hand First release database check Second release adds ID and selfie
Share of new patients verified with no human involved. Each release added a layer: first the database check, then an ID and selfie step for those who fail it.

Decisions worth telling

Recommended one vendor, then changed my mind on the merits

My first recommendation was Vouched: easier to build with, richer data back. Working through the tradeoffs with the team, Persona fit the skip-and-return flow far better — it can resume an abandoned session and takes a date of birth in the first check — and a reputational concern I'd been weighing didn't outweigh that. We chose on fit, and product made the call.

Departing from the spec when it stranded patients

The spec said requesting a resubmission should set the vendor's status to "resubmission required." I built it, then found a patient's way back in only appeared for a different status, so they could be parked with no path forward. I replaced it by inferring resubmission from the verification's own history.

Hold approval, never rejection

Pharmacies need a patient's legal name and real date of birth, so a mismatch on either holds the order until it's settled. An address doesn't, because the one on an ID is often out of date. Rejection stays open, so a suspect order can be declined without editing the patient's record first. Each fix is its own audited record with the before and after values, and keeping the patient's value requires a reason.

C# / .NET Vendor API and webhooks HMAC signature verification Feature flags

02 / 02

Drug-interaction checks

Replacing a manual lookup with DrugBank, from patient intake to clinical review.

The problem

Every drug interaction was looked up by hand. For each new patient, prescription and renewal, a customer-service admin searched a consumer drug site, judged the severity, and typed it into the record. Non-clinical staff were interpreting severity, results were inconsistent, and it sat in front of every order approval.

DrugBank, our clinical data partner, could automate it, but its API only accepts validated drug IDs, not free text. Every product had to be mapped to DrugBank first, and every medication a patient entered had to be matched to it.

What I owned

Mapping the catalog

An admin page where staff map each product to its DrugBank entries, with search, filters, and a confirmation step that treats removing a mapping differently from saving one.

Matching at intake

A typeahead in the medications step, so patients pick their own match and the ID is captured at the source. Free text is still allowed for anything DrugBank doesn't know.

Checking automatically

The data model and API for interaction records, and background jobs that check every matched medication against the ordered product and record what DrugBank finds, including "no known interaction."

Clinical review

Severity-tinted alerts at order review for admins and doctors, with DrugBank's guidance. Clinicians can override a severity only with a written justification, validated on the back-end against the original. Moderate and Major interactions still need a clinician; Minor and None no longer hold approval.

A teammate built the proof of concept and broke down the work. I built the bulk of it, across the stack, and became the project's subject-matter expert.

Results

The measure that matters is how many orders reach admin review with their interaction check already done. Before, none did: someone looked up every interaction by hand. Once automatic checks went live, about 4 in 10 orders with medications arrived already checked, and it has held there every week since.

Drug-interaction checks done automatically, before and after the release Before the release, no drug-interaction checks were automatic: every one was a manual lookup. Now about 40% of orders with medications reach admin review already checked, and about 80% of patient-entered medications are matched by the patient at intake. 0% About 40% 0% About 80% Before Now Before Now Orders reaching review already checked Patient medications matched at intake
Drug-interaction checks done automatically. Before the release, every check was a manual lookup. Orders are screened orders with at least one medication listed.

Decisions worth telling

A write-once baseline

The record of what DrugBank originally said can't be rewritten, so an override can't quietly change history. The migration added nullable columns so existing rows couldn't fabricate a baseline that was never there.

A field that quietly rewrote medication names

An enrichment step replaced a patient's pick of "Acetaminophen" with a branded child product, which is wrong for an adult platform. I removed it: the name is now exactly what the provider chose.

Direction isn't ownership

In DrugBank, which drug is the "subject" of an interaction depends on the mechanism, not on which drug is ours. Ibuprofen is the subject in a liver-damage interaction with metformin. Cards were wrongly showing "no match"; I fixed it by identifying our drug by exclusion.

React / TypeScript C# / NHibernate Event-sourced commands DrugBank API

What ties them together

Automate the common case, keep a person for the exceptions

In each project the goal wasn't to remove people. It was to stop spending them on the easy cases, and to make the hard ones clearer.

Roll out in steps, behind flags

Identity went live as a database check first, then added the ID step. Each release was reversible and each had its own effect, which is why the results above are readable.

Notice what the spec missed

Stranded patients, ID details nobody compared, a field that rewrote a medication name. Most of the value was in the things nobody had written down.

Leave the system auditable

Write-once baselines, justified overrides, audited fixes. When a decision is questioned later, the record says what happened and who did it.