V3/V4 to V5 migration guide

The legacy Epidata APIs, including the V4 main endpoint (pub_covidcast()) and the V3 endpoints (pub_fluview(), pub_flusurv(), pub_wiki(), and so on), are transitioning to the V5 API, served by epidata_snapshot(), epidata_archive(), and epidata_meta(). The transition is happening source by source. All V3 and V4 sources keep working until the migration is complete (tentatively October 2026), and endpoints that are no longer updated remain accessible on V3/V4. For new work, start on V5 and fall back to a legacy method only for a source that is not yet available there.

Starting in October 2026, the V4 methods are tentatively deprecated in favor of the V5 API, and calling them raises a UserWarning pointing back to this guide.

For the current list of sources and indicators available on the new API, see the V5 signals documentation.

This guide walks through the transition from pub_covidcast() and the other legacy methods. pub_covidcast() is the most widely used, but the V3 methods differ in their names and argument conventions, so the tables below compare both V4 (pub_covidcast()) and V3 (using pub_fluview() as the example) to their V5 equivalents.

from epidatpy import EpiDataContext, EpiRange

epidata = EpiDataContext()

Endpoint mapping

The legacy endpoints split into several purpose-built V5 routes determined by the kind of query. The “V3 (other endpoints)” column gives examples (pub_fluview(), pub_flusurv(), pub_wiki()) to illustrate how much the legacy endpoints differ from each other; check each method’s reference page for its own behavior.

Task

V4 (pub_covidcast)

V3 (other endpoints)

V5 equivalent

Fetch the latest data, or a snapshot as of a past date

pub_covidcast() (default, or with as_of)

Endpoint-specific (pub_fluview() has no as_of)

epidata_snapshot()

Fetch the full revision history of a signal

pub_covidcast(issues=...)

Supported by some (pub_fluview(), pub_flusurv() with issues)

epidata_archive()

Discover sources, signals, geo types, and date ranges

pub_covidcast_meta(), CovidcastEpidata()

Shared meta for some (pub_fluview_meta())

epidata_meta()

Filter by publication lag

pub_covidcast(lag=...)

Supported by some (pub_fluview(), pub_flusurv())

none (compute report_time - reference_time)

epidata() is a convenience wrapper that routes to epidata_archive() if you pass report_time, or to epidata_snapshot() if you pass snapshot_date (or neither).

Argument changes

Most pub_covidcast() arguments carry over to V5 under the same name, but some have been renamed, dropped, or added. The V3 methods do not share argument names with pub_covidcast(); pub_fluview() is shown as an example.

V4 argument (pub_covidcast)

V3 (pub_fluview)

V5 argument

Notes

data_source

not exposed (implied by the method name)

source

Identifies the source dataset in V5.

signals

none (implied by the endpoint)

signals

One or more signal names within the source, sent in a single request.

geo_type

not exposed (pub_fluview() only has regions)

geo_type

Geographic resolution (e.g. state, county, hhs, nation). Accepts several values; one request is made per value.

geo_values

regions

geo_values

The server returns all locations for the requested geo_type; geo_values is filtered locally after the fetch.

time_type

not exposed (pub_fluview() is always weekly)

none

Dropped. All V5 endpoints use calendar dates.

time_values

epiweeks

reference_time

Accepts dates or an EpiRange. Filtered locally after the fetch.

as_of

none

snapshot_date

epidata_snapshot() only. A date, a datetime, or a UTC timestamp string such as "2025-10-16T13:45:00Z". None returns the latest data.

issues

issues (where supported)

report_time

epidata_archive() only. A comparison string such as "<2025-10-16" or ">=2025-10-16T13:45:00Z", or an EpiRange for an inclusive range, both applied server-side. Bare dates and "=" are rejected: use snapshot_date for point-in-time data.

lag

lag (where supported)

none

Compute it yourself from epidata_archive() output as report_time - reference_time; see below.

none

none

fill_method

New in V5. Selects the imputation variant ("source", "fill_ave", or "fill_zero"); see below.

none

none

limit

New in V5. Caps the rows returned, for previewing a query. The query has no stable sort order, so it is not a filter.

The new methods also add fill_method, which has no covidcast equivalent. Some sources publish several variants of the same signal that differ in how nulls were handled during geographic aggregation:

  • "source" is the raw source data, with no imputation

  • "fill_ave" has null values filled with the average of neighboring values

  • "fill_zero" has null values filled with zero

The default None returns all variants, so filter on this column (or pass a value to the argument) if you want exactly one time series per location.

Column changes

Response fields follow a similar pattern. pub_fluview() again serves as the V3 example; column names vary across legacy endpoints (pub_wiki(), for instance, returns article, count, and hour).

V4 column (pub_covidcast)

V3 (pub_fluview)

V5 column

Notes

source

not returned

dropped

You queried by source; add it back with .assign() if you concatenate results across sources.

signal

none (implied by the endpoint)

signal

The signal name.

value

endpoint-specific columns (e.g. num_ili, wili, ili)

value

One standardized value column across all V5 sources.

not returned

not returned

geo_type

Included in V5 responses.

geo_value

region

geo_value

Standardized location identifier.

time_value

epiweek

reference_time

The date the value describes. Always a date.

issue

issue (where returned)

report_time

When the value was published. A UTC timestamp (datetime64[ns, UTC]), present in both snapshot and archive output.

lag

lag (where returned)

dropped

Compute as report_time - reference_time; see calculating reporting lag.

direction

none

dropped

Was already deprecated in the covidcast API.

stderr, sample_size

none

ci_lower, ci_upper

Uncertainty is now expressed as confidence-interval bounds on value, for the sources that publish them. See below.

missing_value, missing_stderr, missing_sample_size

none

dropped

Missingness is now expressed through fill_method variants and plain NaNs.

none

none

fill_method

Which null-handling variant of the signal this row belongs to. See above.

Some sources also carry extra columns in the new API, for example age_group (pophive) and nwss_source, sample_index, pcr_target (nwss). Each source’s documentation page lists its extra columns.

Uncertainty columns

The covidcast columns stderr and sample_size have no fixed replacement. The shared schema carries only value; a source that quantifies uncertainty adds its own columns, such as ci_lower and ci_upper. Use the metadata or the documentation to see which value columns a source returns:

meta_sleepcycle = epidata.epidata_meta(source="sleepcycle")
meta_sleepcycle["value_columns"]
['ci_lower', 'ci_upper', 'value']

A query, before and after

V4 example: NSSP through covidcast

Fetching NSSP influenza ED visit percentages for two states, as the data looked on January 1, 2025:

old = epidata.pub_covidcast(
    data_source="nssp",
    signals="pct_ed_visits_influenza",
    geo_type="state",
    time_type="week",
    geo_values=["pa", "ca"],
    time_values=EpiRange(202440, 202501),
    as_of=20250101,
).df()
old.head()
/home/runner/work/epidatpy/epidatpy/epidatpy/_endpoints.py:786: UserWarning: `pub_covidcast` uses the V4 Epidata API. Starting in October 2026, V4 is tentatively deprecated in favor of the V5 API. See the migration guide (https://cmu-delphi.github.io/epidatpy/migration_guide.html) for the V5 endpoints and how to move to them.
  _warn_v4_sunset("pub_covidcast")
/home/runner/work/epidatpy/epidatpy/epidatpy/_call.py:540: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  df[info.name] = to_datetime(df[info.name])
source signal geo_type geo_value time_type time_value issue lag value stderr sample_size direction missing_value missing_stderr missing_sample_size
0 nssp pct_ed_visits_influenza state ca week 202440 2026-03-08 103 0.14 <NA> <NA> <NA> 0 1 1
1 nssp pct_ed_visits_influenza state pa week 202440 2026-03-08 103 0.05 <NA> <NA> <NA> 0 1 1
2 nssp pct_ed_visits_influenza state ca week 202441 2026-03-08 102 0.14 <NA> <NA> <NA> 0 1 1
3 nssp pct_ed_visits_influenza state pa week 202441 2026-03-08 102 0.07 <NA> <NA> <NA> 0 1 1
4 nssp pct_ed_visits_influenza state ca week 202442 2026-03-08 101 0.16 <NA> <NA> <NA> 0 1 1
new = epidata.epidata_snapshot(
    source="nssp",
    signals="pct_ed_visits_influenza",
    geo_type="state",
    geo_values=["pa", "ca"],
    reference_time=EpiRange("2024-10-01", "2025-01-01"),
    snapshot_date="2025-01-01",
).df()
new.head()
signal report_time geo_type geo_value fill_method reference_time value
510 pct_ed_visits_influenza 2024-12-27 00:00:00+00:00 state ca source 2024-10-05 0.14
511 pct_ed_visits_influenza 2024-12-27 00:00:00+00:00 state ca source 2024-10-12 0.14
512 pct_ed_visits_influenza 2024-12-27 00:00:00+00:00 state ca source 2024-10-19 0.16
513 pct_ed_visits_influenza 2024-12-27 00:00:00+00:00 state ca source 2024-10-26 0.2
514 pct_ed_visits_influenza 2024-12-27 00:00:00+00:00 state ca source 2024-11-02 0.25

Both queries return the same signal, just with renamed and reshaped columns:

print(list(old.columns))
print(list(new.columns))
['source', 'signal', 'geo_type', 'geo_value', 'time_type', 'time_value', 'issue', 'lag', 'value', 'stderr', 'sample_size', 'direction', 'missing_value', 'missing_stderr', 'missing_sample_size']
['signal', 'report_time', 'geo_type', 'geo_value', 'fill_method', 'reference_time', 'value']

V3 example: FluView

For V3 endpoints like pub_fluview(), metrics that used to be separate columns (num_ili, ili, wili, …) become individual signal names that you request through signals, and the results land in the single value column:

old_flu = epidata.pub_fluview(
    regions="nat",
    epiweeks=EpiRange(202440, 202445),
).df()
old_flu[["release_date", "region", "epiweek", "wili", "ili"]].head()
/home/runner/work/epidatpy/epidatpy/epidatpy/_endpoints.py:1205: UserWarning: `pub_fluview` uses the V4 Epidata API. Starting in October 2026, V4 is tentatively deprecated in favor of the V5 API. See the migration guide (https://cmu-delphi.github.io/epidatpy/migration_guide.html) for the V5 endpoints and how to move to them.
  _warn_v4_sunset("pub_fluview")
release_date region epiweek wili ili
0 2026-09-18 nat 202440 1.90509 1.8485
1 2026-09-18 nat 202441 2.02014 1.94416
2 2026-09-18 nat 202442 2.07037 2.00964
3 2026-09-18 nat 202443 2.22044 2.15518
4 2026-09-18 nat 202444 2.31725 2.23339
new_flu = epidata.epidata_snapshot(
    source="fluview_ilinet",
    signals="wili",
    geo_type="nation",
    geo_values="us",
    reference_time=EpiRange("2024-10-01", "2024-11-15"),
).df()
new_flu.head()
signal report_time geo_type geo_value fill_method reference_time value age_group
1314 wili 2025-09-12 00:00:00+00:00 nation us source 2024-10-12 2.02014 all
1315 wili 2025-09-12 00:00:00+00:00 nation us source 2024-10-19 2.07037 all
1316 wili 2025-09-12 00:00:00+00:00 nation us source 2024-10-26 2.22044 all
1317 wili 2025-09-12 00:00:00+00:00 nation us source 2024-11-02 2.31725 all
1318 wili 2025-09-12 00:00:00+00:00 nation us source 2024-11-09 2.4719 all

Revision history queries

Where you passed issues to pub_covidcast(), use epidata_archive() with report_time:

old_revisions = epidata.pub_covidcast(
    data_source="nssp",
    signals="pct_ed_visits_influenza",
    geo_type="state",
    time_type="week",
    geo_values="pa",
    time_values=EpiRange(202440, 202501),
    issues=EpiRange(202440, 202522),
).df()
old_revisions.head()
/home/runner/work/epidatpy/epidatpy/epidatpy/_endpoints.py:786: UserWarning: `pub_covidcast` uses the V4 Epidata API. Starting in October 2026, V4 is tentatively deprecated in favor of the V5 API. See the migration guide (https://cmu-delphi.github.io/epidatpy/migration_guide.html) for the V5 endpoints and how to move to them.
  _warn_v4_sunset("pub_covidcast")
/home/runner/work/epidatpy/epidatpy/epidatpy/_call.py:540: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  df[info.name] = to_datetime(df[info.name])
/home/runner/work/epidatpy/epidatpy/epidatpy/_call.py:540: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  df[info.name] = to_datetime(df[info.name])
source signal geo_type geo_value time_type time_value issue lag value stderr sample_size direction missing_value missing_stderr missing_sample_size
0 nssp pct_ed_visits_influenza state pa week 202440 202445 5 0.05 <NA> <NA> <NA> 0 1 1
1 nssp pct_ed_visits_influenza state pa week 202440 202446 6 0.05 <NA> <NA> <NA> 0 1 1
2 nssp pct_ed_visits_influenza state pa week 202440 202447 7 0.05 <NA> <NA> <NA> 0 1 1
3 nssp pct_ed_visits_influenza state pa week 202440 202448 8 0.05 <NA> <NA> <NA> 0 1 1
4 nssp pct_ed_visits_influenza state pa week 202440 202449 9 0.05 <NA> <NA> <NA> 0 1 1
revisions = epidata.epidata_archive(
    source="nssp",
    signals="pct_ed_visits_influenza",
    geo_type="state",
    geo_values="pa",
    reference_time=EpiRange("2024-10-01", "2025-01-01"),
    report_time="<2025-06-01",
).df()
revisions.head()
signal report_time geo_type geo_value fill_method reference_time value
82644 pct_ed_visits_influenza 2024-11-08 00:00:00+00:00 state pa source 2024-10-05 0.05
82645 pct_ed_visits_influenza 2024-11-08 00:00:00+00:00 state pa source 2024-10-12 0.07
82646 pct_ed_visits_influenza 2024-11-08 00:00:00+00:00 state pa source 2024-10-19 0.08
82647 pct_ed_visits_influenza 2024-11-08 00:00:00+00:00 state pa source 2024-10-26 0.13
82648 pct_ed_visits_influenza 2024-11-08 00:00:00+00:00 state pa source 2024-11-02 0.14

If you filtered by lag, fetch the archive and filter afterwards. Because report_time is a timezone-aware timestamp and reference_time a naive date, drop the timezone before subtracting:

lag_days = (revisions["report_time"].dt.tz_localize(None) - revisions["reference_time"]).dt.days

# For an exact lag (e.g. 7 days):
revisions[lag_days == 7].head()
signal report_time geo_type geo_value fill_method reference_time value
87897 pct_ed_visits_influenza 2024-11-23 00:00:00+00:00 state pa source 2024-11-16 0.17
99213 pct_ed_visits_influenza 2024-12-07 00:00:00+00:00 state pa source 2024-11-30 0.35
# Or for maximum latency (e.g. at most 7 days of delay):
revisions[lag_days <= 7].head()
signal report_time geo_type geo_value fill_method reference_time value
82648 pct_ed_visits_influenza 2024-11-08 00:00:00+00:00 state pa source 2024-11-02 0.14
87897 pct_ed_visits_influenza 2024-11-23 00:00:00+00:00 state pa source 2024-11-16 0.17
99213 pct_ed_visits_influenza 2024-12-07 00:00:00+00:00 state pa source 2024-11-30 0.35
104608 pct_ed_visits_influenza 2024-12-13 00:00:00+00:00 state pa source 2024-12-07 0.55
110556 pct_ed_visits_influenza 2024-12-20 00:00:00+00:00 state pa source 2024-12-14 0.85

Checking whether a source is available

Use epidata_meta() to see what a source offers in the new API. It returns the signals, geo types, and the available reference_time and report_time ranges:

meta = epidata.epidata_meta(source="nssp")

# All the fields available for this source
list(meta)
['report_time_range',
 'reference_time_range',
 'signals',
 'geo_types',
 'key_columns',
 'extra_key_columns',
 'value_columns',
 'column_types']
meta["signals"]  # available signal names
['pct_ed_visits_ari',
 'pct_ed_visits_combined',
 'pct_ed_visits_covid',
 'pct_ed_visits_influenza',
 'pct_ed_visits_rsv',
 'smoothed_pct_ed_visits_combined',
 'smoothed_pct_ed_visits_covid',
 'smoothed_pct_ed_visits_influenza',
 'smoothed_pct_ed_visits_rsv']
meta["geo_types"]  # supported geography levels
['census_division',
 'census_region',
 'county',
 'hhs',
 'hrr',
 'hsa_nci',
 'msa',
 'nation',
 'state']
meta["reference_time_range"]  # earliest/latest reference_time available
{'latest': '2026-09-19', 'first': '2022-10-01'}
meta["report_time_range"]  # earliest/latest report_time (publication instant, UTC) available
{'latest': '2026-09-23T00:00:00Z', 'first': '2024-04-18T00:00:00Z'}

Called with no argument, epidata_meta() returns the entries for every available source, keyed by source name.

If epidata_meta() does not know the source yet, keep using pub_covidcast() (or the relevant pub_*/pvt_* method) for it and check back after package updates. The API mailing list announces sources as they move.

Endpoints kept for historical reference

Not every V4 endpoint is moving to V5. The methods below cover data sources whose collection has already ended (e.g. Google Flu Trends, the HealthTweets signal, the various nowcasts). They are not part of the V4-to-V5 transition, so they are not deprecated and will keep working. The historical data they return is frozen and will remain available. They will just no longer receive new data.

Method

Data source

pvt_cdc()

CDC total and by-topic webpage visits

pub_covid_hosp_facility_lookup()

COVID hospitalization facility lookup

pub_covid_hosp_facility()

COVID hospitalizations by facility

pub_covid_hosp_state_timeseries()

COVID hospitalizations by state

pub_delphi()

Delphi’s ILINet outpatient doctor visits forecasts

pub_dengue_nowcast()

Delphi’s PAHO dengue nowcasts (Americas)

pvt_dengue_sensors()

PAHO dengue digital surveillance sensors (Americas)

pub_ecdc_ili()

ECDC ILI incidence (Europe)

pub_gft()

Google Flu Trends flu search volume

pvt_ght()

Google Health Trends health topics search volume

pub_kcdc_ili()

KCDC ILI incidence (Korea)

pvt_meta_norostat()

Metadata for the NoroSTAT endpoint

pub_nidss_dengue()

NIDSS dengue cases (Taiwan)

pub_nidss_flu()

NIDSS flu doctor visits (Taiwan)

pvt_norostat()

CDC NoroSTAT norovirus outbreaks

pub_nowcast()

Delphi’s ILI Nearby nowcasts

pub_paho_dengue()

PAHO dengue data (Americas)

pvt_sensors()

Influenza and dengue digital surveillance sensors

pvt_twitter()

HealthTweets total and influenza-related tweets

pub_wiki()

Wikipedia webpage counts by article