Home / Tools / Drugs and formularies

Drugs and formulariesL2 · v1.0.0 · read-only

formulary_churn

Formulary Churn

What it answers

Given a quarter-pair (report_quarter_from, report_quarter_to) AND a formulary or plan filter, returns the formulary delta: drugs added, drugs dropped, drugs re-tiered, and optionally drugs whose control flags (prior auth / step therapy / quantity limit) changed. Diffs drug_silver.fact_drug_formulary across two SPUF report_quarters on (formulary_id, ndc11) keys.

Returns: per-category row lists (cap 5000 each), aggregates (formularies_compared, n_added, n_dropped, n_tier_changed, n_control_changed, n_unchanged, churn_rate, tier_movement_distribution), truncated_by_category flags.

READING churn_rate: it is (added + dropped + re-tiered) divided by the number of drugs on the formulary in the FROM quarter — CHANGE EVENTS PER FROM-QUARTER DRUG, not a percentage. It is >= 0 and CAN EXCEED 1 (a formulary that drops everything and adds as many new drugs scores 2.0), because added drugs are not members of the denominator. The answer carries churn_rate_definition saying exactly this, the two denominators (n_in_from_quarter, n_in_to_quarter), and two bounded companions that ARE 0-1: share_dropped (dropped / FROM-quarter drugs) and share_added (added / TO-quarter drugs).

Use cases: year-over-year formulary stability tracking, drop investigations for a specific drug class, IRA-era churn rate (crossing 2025 → 2026 will surface the redesign-driven churn).

KNOWN GAPS: spuf_quarterly_publication_lag (CMS publishes 6 weeks after quarter end; very recent quarter changes won't show); ira_era_break_2026 (IRA Part D redesign in 2026 changed formulary structures; churn comparison crossing this boundary mixes regime changes with normal churn); formulary_churn_truncated (per-category lists capped at 5000).

Inputs

report_quarter_from
string · required
report_quarter_to
string · required
acknowledge_era_break
boolean · optional
default: false
contract_id_filter
string · optional
formulary_id_filter
array · optional
include_control_changes
boolean · optional
default: false
plan_id_filter
string · optional

Call it

From an agent: connect the Vlada MCP once (one click for Claude, ChatGPT, Cursor, VS Code) and ask in plain English; the agent selects formulary_churn when the question fits. From code: the same tool over REST with an API key. The schema endpoint needs no key.

curl -X POST https://api.vladahealth.com/v1/tools/formulary_churn \
  -H "Authorization: Bearer $VLADA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"report_quarter_from":"<report_quarter_from>","report_quarter_to":"<report_quarter_to>"}'
curl https://api.vladahealth.com/v1/tools/formulary_churn/schema      # the JSON schema, no auth
# MCP endpoint (Streamable HTTP): https://mcp.vladahealth.com/mcp

What comes back

Typed rows plus provenance on every answer: the public source file, its vintage, the methodology, and a response_hash you can replay. Prove and replay tools turn any number into a re-runnable receipt. A number the data cannot support comes back as “not in the data”, never as zero.

Sources behind it

  • drug_silver.fact_drug_formulary
  • drug_silver.dim_part_d_plan

tables: drug_silver.fact_drug_formulary · drug_silver.dim_part_d_plan

Known limits

  • spuf_quarterly_publication_lag
  • ira_era_break_2026
  • formulary_churn_truncated
  • formulary_churn_no_match

As of the 2026-09-19 build of the served surface · machine-readable catalog · the live server may run a different version; the schema endpoint above is authoritative for what is deployed.