@usa-open-data-connectors/usa-sources
v0.1.9
Published
Uniform TypeScript adapters for US public data sources
Readme
@usa-open-data-connectors/usa-sources
Uniform TypeScript adapters for US public data sources, with live probes and offline fixtures.
What this package does
- Exposes source adapters behind one interface.
- Fetches live data from each source and parses it into plain objects.
- Loads committed fixtures in tests only; a live fetch never falls back.
- Publishes the
US_DATA_SOURCESregistry for the API and the CLI. - Exports named functions for each source, with that source's query parameters.
Install
npm install @usa-open-data-connectors/usa-sourcesQuick start
import { probeAllUsDataSources } from '@usa-open-data-connectors/usa-sources';
const probes = await probeAllUsDataSources();
console.log(probes.map((probe) => `${probe.id}: ${probe.ok ? 'ok' : probe.status}`).join('\n'));Adapters
| Adapter | Publisher | What it reads |
| --- | --- | --- |
| bls-unemployment-rate | Bureau of Labor Statistics | Monthly national unemployment rate, seasonally adjusted, from the Current Population Survey. |
| usgs-hawaii-earthquakes | US Geological Survey | Earthquakes of magnitude 2.5 and above near the Hawaiian islands. |
| cdc-county-obesity | Centers for Disease Control and Prevention | Model-based share of adults with obesity in each US county, from CDC PLACES. |
| ncei-annual-temperature | NOAA National Centers for Environmental Information | Calendar-year average temperature for the contiguous United States since 1895. |
| noaa-sea-level | NOAA Center for Operational Oceanographic Products and Services | Monthly mean sea level at a tide gauge, folded into calendar-year averages with a fitted trend. |
| treasury-avg-interest-rate | US Department of the Treasury | Average interest rate on the interest-bearing federal debt outstanding, monthly since 2001. |
| fema-disaster-declarations | Federal Emergency Management Agency | Every disaster declaration FEMA has published, from 1953 to the newest. |
| openfda-food-recalls | US Food and Drug Administration | Every food recall the FDA publishes as an enforcement report, from June 2012. |
| usgs-peak-streamflow | US Geological Survey | Annual peak-flow record at a USGS stream gauge, from 1844 at the Mississippi River at St. Louis. |
| cpsc-product-recalls | US Consumer Product Safety Commission | Every consumer product recall CPSC has published, from 2014 to the newest. |
| cfpb-consumer-complaints | Consumer Financial Protection Bureau | Every consumer complaint sent to a company, counted by year, with the top products and companies. |
| treasury-debt-to-penny | US Department of the Treasury | Daily total public debt outstanding, in dollars, from the debt to the penny file. |
| sec-edgar-filings | US Securities and Exchange Commission | An issuer's recent filing history from SEC EDGAR, with the form type and the newest date. |
| fdic-bank-directory | Federal Deposit Insurance Corporation | Insured banks in the FDIC institution directory, with the city and state of each main office. |
| clinicaltrials-studies | ClinicalTrials.gov | Registered clinical studies, with the status, phase, lead sponsor, and enrollment. |
| nws-point-forecast | National Weather Service | The forecast grid point for a latitude and longitude, with the URLs for the daily and hourly forecast. |
| usaspending-agencies | USAspending | Top-tier federal agencies, with budget authority, obligations, and outlays for the active quarter. |
| epa-envirofacts-facilities | Environmental Protection Agency | Toxics Release Inventory facilities, with county, address, and open or closed status. |
| ncbi-pubmed-search | National Center for Biotechnology Information | PubMed literature search results, with the match count and a page of PubMed ids. |
| nih-reporter-projects | National Institutes of Health | NIH-funded projects for one fiscal year, with the title, award amount, organization, principal investigators, and administering institute. |
| cdc-socrata-catalogue | Centers for Disease Control and Prevention | The CDC Socrata catalogue, one row per dataset, chart, or story, with the portal's licence and attribution values when present. |
| healthdata-socrata-catalogue | HealthData.gov | The HealthData.gov Socrata catalogue, one row per dataset, chart, or story, with the portal's licence and attribution values. |
| bts-transportation-stats | Bureau of Transportation Statistics | The BTS Socrata catalogue, one row per dataset, chart, or story, with the portal's licence and attribution values. |
| estimatetax-income-tax | EstimateTax | US federal, state, and local income tax for one salary, with the official document behind every figure. |
| nyc-open-data-catalogue | New York City Open Data | The NYC Socrata catalogue, one row per published dataset or map, with licence and attribution fields that are empty when the portal supplies none. |
| callook-callsigns | Callook.info | US amateur radio callsign records from the FCC licence file, with the licence class, location, and expiry. |
| college-scorecard-institutions | College Scorecard, US Department of Education | Institution-level enrollment, cost, completion, debt, and earnings ten years after entry for US colleges. |
| publicdatahub-hospital-quality | PublicDataHub, from the Centers for Medicare & Medicaid Services | Medicare-certified hospital quality measures, with national ranks and provenance. |
| nextbus-transit-vehicles | Portland Streetcar, through the NextBus XML feed | Live positions, headings, speeds, and report ages for the streetcars on the NS line. |
| federal-register-documents | Office of the Federal Register | Documents published in the Federal Register, with type, publication date, agencies, abstract, and public HTML and PDF links. |
| nhtsa-vehicle-models | National Highway Traffic Safety Administration | Vehicle models for one model year and make, with the service total and next-page URL. |
| fcc-socrata-catalogue | Federal Communications Commission | The FCC Open Data Socrata catalogue, one row per dataset, chart, or story, with category, view count, and download count. |
| ny-state-open-data-catalogue | New York State Open Data | The New York State Socrata catalogue, one row per dataset or file, with state topic, view count, and download count. |
| chicago-open-data-catalogue | City of Chicago | The Chicago Data Portal Socrata catalogue, one row per dataset, chart, map, or story, with city topic, view count, and download count. |
| seattle-open-data-catalogue | City of Seattle | The Seattle Open Data Socrata catalogue, one row per dataset, map, chart, or story, with city topic, view count, and download count. |
| texas-open-data-catalogue | State of Texas | The Texas Open Data Socrata catalogue, one row per dataset, map, chart, or linked resource, with state topic, view count, and download count. |
| colorado-open-data-catalogue | State of Colorado | The Colorado Open Data Socrata catalogue, one row per dataset, map, chart, or linked resource, with state topic, view count, and download count. |
| washington-state-open-data-catalogue | State of Washington | The Washington State Open Data Socrata catalogue, one row per dataset, chart, story, or other resource, with state topic, view count, and download count. |
| michigan-open-data-catalogue | State of Michigan | The Michigan Open Data Socrata catalogue, one row per dataset, map, chart, story, or other resource, with state topic, view count, and download count. |
| oregon-open-data-catalogue | State of Oregon | The Oregon Open Data Socrata catalogue, one row per dataset, file, or filtered view, with state topic, view count, and download count. |
| pennsylvania-open-data-catalogue | Commonwealth of Pennsylvania | The Pennsylvania Open Data Socrata catalogue, one row per dataset, chart, or linked resource, with state topic, view count, and download count. |
| illinois-open-data-catalogue | State of Illinois | The Illinois Open Data Socrata catalogue, one row per dataset, chart, story, or filtered view, with state topic, view count, and download count. |
| new-jersey-open-data-catalogue | State of New Jersey | The New Jersey Open Data Socrata catalogue, one row per dataset, file, story, or other resource, with state topic, view count, and download count. |
| vermont-open-data-catalogue | State of Vermont | The Vermont Open Data Socrata catalogue, one row per dataset or filtered view, with state topic, view count, and download count. |
| los-angeles-open-data-catalogue | City of Los Angeles | The Los Angeles Open Data Socrata catalogue, one row per dataset, map, or filtered view, with city topic, view count, and download count. |
| san-francisco-open-data-catalogue | City and County of San Francisco | The San Francisco Open Data Socrata catalogue, one row per dataset, map, or filtered view, with city topic, view count, and download count. |
| california-open-data-catalogue | State of California | The California Open Data CKAN catalogue, one row per dataset package, with title, groups, resources, licence, and publishing organisation. |
The HTTP API and the CLI read this package's registry. A new adapter is exposed on
/api/sources, /api/sources/{id}/probe, and /api/sources/{id}/data as soon as it is registered.
Usage examples
The examples below hit the live sources and need no key. Each one uses the exported functions for that adapter.
bls-unemployment-rate:
import { fetchBlsSeries, US_UNEMPLOYMENT_SERIES_ID } from '@usa-open-data-connectors/usa-sources';
const rate = await fetchBlsSeries(US_UNEMPLOYMENT_SERIES_ID, {
startYear: 2006,
endYear: 2025,
});
console.log(rate.latest.year, rate.latest.period, rate.latest.value);usgs-hawaii-earthquakes:
import {
buildUsgsEarthquakeCatalogue,
fetchUsgsEarthquakes,
USGS_HAWAII_BOUNDS,
USGS_HAWAII_MIN_MAGNITUDE,
} from '@usa-open-data-connectors/usa-sources';
const earthquakes = await fetchUsgsEarthquakes({
startDate: '2025-01-01',
endDate: '2026-01-01',
minMagnitude: USGS_HAWAII_MIN_MAGNITUDE,
bounds: USGS_HAWAII_BOUNDS,
});
const catalogue = buildUsgsEarthquakeCatalogue(earthquakes);
console.log(catalogue.count, catalogue.strongest.place, catalogue.strongest.magnitude);cdc-county-obesity:
import {
buildCdcCountyObesitySet,
fetchCdcCountyObesity,
} from '@usa-open-data-connectors/usa-sources';
const set = buildCdcCountyObesitySet(await fetchCdcCountyObesity());
console.log(set.countyCount, set.lowest.countyName, set.highest.percent, set.national.percent);ncei-annual-temperature:
import {
buildNceiAnnualTemperatureSeries,
fetchNceiAnnualTemperature,
} from '@usa-open-data-connectors/usa-sources';
const series = await fetchNceiAnnualTemperature({
startYear: 1895,
endYear: new Date().getFullYear(),
});
console.log(series.yearCount, series.warmest.year, series.coldest.valueFahrenheit);noaa-sea-level:
import { buildNoaaSeaLevelSeries, fetchNoaaSeaLevel } from '@usa-open-data-connectors/usa-sources';
const seaLevel = buildNoaaSeaLevelSeries(await fetchNoaaSeaLevel());
console.log(
seaLevel.station.name,
seaLevel.yearCount,
seaLevel.highest.year,
seaLevel.trendMillimetresPerYear
);treasury-avg-interest-rate:
import { fetchTreasuryAvgInterestRates } from '@usa-open-data-connectors/usa-sources';
const rates = await fetchTreasuryAvgInterestRates();
console.log(rates.monthCount, rates.lastMonth.averageInterestRatePercent, rates.lowest.recordDate);treasury-debt-to-penny:
import {
buildTreasuryDebtToPennyPage,
fetchTreasuryDebtToPenny,
} from '@usa-open-data-connectors/usa-sources';
const page = buildTreasuryDebtToPennyPage(
(await fetchTreasuryDebtToPenny({ rowLimit: 10_000 })).days
);
console.log(
page.dayCount,
page.firstDay.recordDate,
page.lastDay.recordDate,
page.lastDay.totalPublicDebtOutstandingUsd
);fdic-bank-directory:
import {
buildFdicBankDirectoryUrl,
parseFdicBankDirectoryPayload,
} from '@usa-open-data-connectors/usa-sources';
const url = new URL(
buildFdicBankDirectoryUrl({ rowLimit: 10_000, fields: 'ID,NAME,CITY,STALP' })
);
url.searchParams.set('filters', 'ACTIVE:1');
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status} from ${url.toString()}`);
}
const directory = parseFdicBankDirectoryPayload(await response.json());
console.log(directory.bankCount, directory.totalBanks, directory.states[0]);The public API is FDIC_BANK_API_BASE, FDIC_BANK_ROW_LIMIT,
FDIC_BANK_FIELDS, buildFdicBankDirectoryUrl,
parseFdicBankDirectoryPayload, fetchFdicBankDirectory, and
fdicBankDirectoryAdapter, with the FdicBank, FdicBankStateCount, and
FdicBankDirectory types. The parser validates the response with a zod schema:
meta.total, totals.count, data[].data.{ID,NAME,CITY,STALP}, and
errors. A row missing any of the four fields throws UsSourceParseError; a
body with an errors array throws UsSourceApiError.
sec-edgar-filings:
import {
fetchSecEdgarFilings,
SEC_EDGAR_APPLE_CIK,
} from '@usa-open-data-connectors/usa-sources';
const company = await fetchSecEdgarFilings({ cik: SEC_EDGAR_APPLE_CIK });
console.log(
company.name,
company.filingCount,
company.newestFilingDate,
company.formCounts[0]
);The public API is SEC_EDGAR_SUBMISSIONS_API_BASE, SEC_EDGAR_APPLE_CIK,
SEC_EDGAR_USER_AGENT, buildSecEdgarSubmissionsUrl,
parseSecEdgarFilingsPayload, fetchSecEdgarFilings, and
secEdgarFilingsAdapter, with the SecEdgarFiling, SecEdgarFormCount, and
SecEdgarCompanyFilings types. The parser validates the response with a zod
schema over cik, name, tickers, exchanges, fiscalYearEnd, and
filings.recent. The recent block sends parallel arrays for the accession
number, filing date, report date, form, size, XBRL flags, primary document,
and description. The parser zips them into one row per filing and throws
UsSourceParseError when the arrays do not line up or a filing date is not
YYYY-MM-DD.
epa-envirofacts-facilities:
import {
buildEpaEnvirofactsFacilitiesUrl,
parseEpaEnvirofactsFacilitiesPayload,
} from '@usa-open-data-connectors/usa-sources';
const url = buildEpaEnvirofactsFacilitiesUrl({ stateAbbr: 'CA', rowWindow: '0:9999' });
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status} from ${url}`);
}
const page = parseEpaEnvirofactsFacilitiesPayload(await response.json());
console.log(page.facilityCount, page.openCount, page.counties[0]);The public API is EPA_ENVIROFACTS_API_BASE, EPA_ENVIROFACTS_TABLE,
EPA_ENVIROFACTS_STATE_COLUMN, EPA_ENVIROFACTS_STATE_ABBR,
EPA_ENVIROFACTS_ROW_WINDOW, buildEpaEnvirofactsFacilitiesUrl,
parseEpaEnvirofactsFacilitiesPayload, fetchEpaEnvirofactsFacilities, and
epaEnvirofactsFacilitiesAdapter, with the EpaEnvirofactsFacility,
EpaEnvirofactsCountyCount, and EpaEnvirofactsFacilityPage types. The
parser validates a bare JSON array against a zod schema over
tri_facility_id, facility_name, state_abbr, and the optional
street_address, city_name, county_name, zip_code, region,
fac_closed_ind, and parent_co_name fields. A rejected query answers with
{error} rather than an array, which throws UsSourceApiError.
cdc-socrata-catalogue:
import {
buildCdcSocrataCatalogueUrl,
parseCdcSocrataCataloguePayload,
} from '@usa-open-data-connectors/usa-sources';
const url = buildCdcSocrataCatalogueUrl({ limit: 10_000 });
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status} from ${url}`);
}
const catalogue = parseCdcSocrataCataloguePayload(await response.json());
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is CDC_SOCRATA_CATALOGUE_API_BASE,
CDC_SOCRATA_CATALOGUE_LIMIT, buildCdcSocrataCatalogueUrl,
parseCdcSocrataCataloguePayload, fetchCdcSocrataCatalogue, and
cdcSocrataCatalogueAdapter, with the CdcSocrataCatalogueEntry,
CdcSocrataCategoryCount, and CdcSocrataCatalogue types. The parser
validates a bare JSON array against a zod schema over id, name,
assetType, category, viewType, createdAt, viewLastModified,
viewCount, downloadCount, and metadata. Every entry carries licenceUrl
and attribution, copied from the entry's License and Publisher metadata
and empty when the portal supplies none. A row missing id, name, or
createdAt throws UsSourceParseError. A response with no rows also throws,
because an empty catalogue is not a usable answer.
bts-transportation-stats:
import {
buildBtsTransportationStatsUrl,
parseBtsTransportationStatsPayload,
} from '@usa-open-data-connectors/usa-sources';
const url = buildBtsTransportationStatsUrl({ limit: 10_000 });
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status} from ${url}`);
}
const catalogue = parseBtsTransportationStatsPayload(await response.json());
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is BTS_TRANSPORTATION_STATS_API_BASE,
BTS_TRANSPORTATION_STATS_LIMIT, buildBtsTransportationStatsUrl,
parseBtsTransportationStatsPayload, fetchBtsTransportationStats, and
btsTransportationStatsAdapter, with the BtsCatalogueEntry,
BtsCatalogueCategoryCount, and BtsTransportationCatalogue types. The parser
validates a bare JSON array against a zod schema over id, name,
assetType, category, viewType, createdAt, viewLastModified,
viewCount, downloadCount, and metadata. Every entry carries licenceUrl
and attribution, copied from the entry's License and Publisher metadata
and empty when the portal supplies none. A row missing id, name, or
createdAt throws UsSourceParseError. A response with no rows also throws,
because an empty catalogue is not a usable answer.
nextbus-transit-vehicles:
import { fetchNextBusVehicles } from '@usa-open-data-connectors/usa-sources';
const snapshot = await fetchNextBusVehicles();
console.log(snapshot.vehicleCount, snapshot.vehicles[0]);The public API is NEXTBUS_XML_FEED_BASE, NEXTBUS_PORTLAND_STREETCAR_AGENCY_TAG,
NEXTBUS_PORTLAND_STREETCAR_ROUTE_TAG, NEXTBUS_PORTLAND_STREETCAR_QUERY,
buildNextBusVehicleUrl, parseNextBusVehiclePayload, fetchNextBusVehicles,
and nextBusTransitVehiclesAdapter, with the NextBusVehicle,
NextBusVehicleQuery, and NextBusVehicleSnapshot types. The parser reads
the XML attributes as strings and validates every field with zod. An error
body, a missing timestamp, or a position outside the map throws
UsSourceParseError. A route with no vehicles is valid and returns an empty
vehicles list.
fema-disaster-declarations:
import { fetchFemaDeclarations } from '@usa-open-data-connectors/usa-sources';
const declarations = await fetchFemaDeclarations();
console.log(
declarations.declarationCount,
declarations.busiestYear.year,
declarations.incidentTypes[0]?.name
);usgs-peak-streamflow:
import {
buildUsgsPeakStreamflowSeries,
fetchUsgsPeakStreamflow,
} from '@usa-open-data-connectors/usa-sources';
const record = await fetchUsgsPeakStreamflow();
console.log(
record.yearCount,
record.highest.waterYear,
record.highest.peakDischargeCubicFeetPerSecond,
record.highestToLowestRatio
);cpsc-product-recalls:
import { fetchCpscProductRecalls } from '@usa-open-data-connectors/usa-sources';
const recalls = await fetchCpscProductRecalls();
console.log(
recalls.totalRecalls,
recalls.busiestCompleteYear.year,
recalls.remedyOptions[0]?.option,
recalls.manufacturerCountries[0]?.country
);cfpb-consumer-complaints:
import { fetchCfpConsumerComplaints } from '@usa-open-data-connectors/usa-sources';
const complaints = await fetchCfpConsumerComplaints();
console.log(
complaints.totalComplaints,
complaints.busiestCompleteYear.year,
complaints.newestReceivedDate,
complaints.topCompanies[0]?.company
);estimatetax-income-tax:
import { fetchEstimateTaxCalculation } from '@usa-open-data-connectors/usa-sources';
const tax = await fetchEstimateTaxCalculation({
query: { income: 85_000, filingStatus: 'single', state: 'NY', city: 'new-york-city' },
});
console.log(tax.totals.totalTax, tax.totals.effectiveRate, tax.sources.federal.url);ncbi-pubmed-search:
import { fetchNcbiPubmedSearch } from '@usa-open-data-connectors/usa-sources';
const result = await fetchNcbiPubmedSearch({
term: '"long COVID"[tiab] AND 2025[edat]',
retmax: 0,
});
console.log(result.totalCount, result.queryTranslation);The public API is NCBI_EUTILS_API_BASE, NCBI_PUBMED_ESEARCH_PATH,
NCBI_PUBMED_DEFAULT_TERM, NCBI_PUBMED_DEFAULT_RETMAX, buildNcbiPubmedSearchUrl,
parseNcbiPubmedSearchPayload, fetchNcbiPubmedSearch, and
ncbiPubmedSearchAdapter, with the NcbiPubmedSearchResult and
NcbiPubmedTranslation types. The parser validates the response with a zod
schema over header and esearchresult, where esearchresult can carry
count, retmax, retstart, idlist, querytranslation, translationset,
error, and warninglist. The counts arrive as strings and are converted once.
An esearchresult.error is thrown as UsSourceApiError even though the HTTP
status is 200.
nih-reporter-projects:
import { fetchNihReporterProjects } from '@usa-open-data-connectors/usa-sources';
const page = await fetchNihReporterProjects({ fiscalYear: 2025, limit: 10 });
console.log(page.totalCount, page.pageAwardAmountUsd, page.projects[0]);The public API is NIH_REPORTER_SEARCH_URL, NIH_REPORTER_SOURCE_ID,
NIH_REPORTER_DEFAULT_FISCAL_YEAR, NIH_REPORTER_PAGE_SIZE,
buildNihReporterSearchBody, parseNihReporterProjectsPayload,
fetchNihReporterProjects, and nihReporterProjectsAdapter, with the
NihReporterProject, NihReporterProjectPage, NihReporterProjectQuery, and
NihReporterSearchBody types. The parser validates meta and results, keeps
the project number, core project number, title, fiscal year, award amount,
organization, city and state, investigators, administering institute, start and
end dates, and detail URL, and adds the agency total and the award sum for the
page. A top-level message throws UsSourceApiError even when the HTTP status
is 200. The default search is fiscal 2025, ten rows, largest award first.
clinicaltrials-studies:
import {
buildClinicalTrialsStudiesUrl,
parseClinicalTrialsStudiesPayload,
} from '@usa-open-data-connectors/usa-sources';
const url = new URL(buildClinicalTrialsStudiesUrl({ pageSize: 1000 }));
url.searchParams.set('query.cond', 'long COVID');
url.searchParams.set(
'fields',
'NCTId,BriefTitle,OverallStatus,StartDate,StudyType,Phase,Condition,LeadSponsorName,EnrollmentCount,EnrollmentType,LastUpdatePostDate'
);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status} from ${url.toString()}`);
}
const page = parseClinicalTrialsStudiesPayload(await response.json());
console.log(page.studyCount, page.statusCounts[0], page.nextPageToken);The public API is CLINICALTRIALS_STUDIES_API_BASE,
CLINICALTRIALS_STUDIES_PAGE_SIZE, CLINICALTRIALS_STUDIES_SOURCE_ID,
buildClinicalTrialsStudiesUrl, parseClinicalTrialsStudiesPayload,
fetchClinicalTrialsStudies, and clinicalTrialsStudiesAdapter, with the
ClinicalTrialStudy, ClinicalTrialStatusCount, and ClinicalTrialStudyPage
types. The parser validates the response with a zod schema over studies and
nextPageToken. Each study carries an optional protocolSection with
identificationModule (nctId, briefTitle), statusModule
(overallStatus, startDateStruct, lastUpdatePostDateStruct),
sponsorCollaboratorsModule (leadSponsor.name), conditionsModule
(conditions), and designModule (studyType, phases, enrollmentInfo). A
study without a registry id or a brief title throws UsSourceParseError, and an
empty page also throws.
The adapter reads one page of the register and keeps the id, title, status,
study type, phases, conditions, lead sponsor, enrollment, start date, and last
update date. The default page size is ten. buildClinicalTrialsStudiesUrl takes
only pageSize, so a filtered story builds the URL and adds query.cond,
query.term, or filter.* itself before calling the parser. The full protocol
record is large: 737 long COVID studies were 12.2 MB without a field projection
and 426 KB with the eleven fields above on 2026-10-20. The fields parameter
accepts those short field names, so a caller does not need to ask for the whole
record.
Three shape notes. A start date can be day precision (2024-12-10) or month
precision (2026-05), and the adapter keeps the string as the registry wrote
it. A start date can be planned rather than actual, so a recent year can still
gain studies. query.cond is the registry's own condition search rather than a
filter over the conditions array; a long COVID search returns more studies
than the subset whose condition string contains "long COVID", because keywords
and related terms also match. The response has no total count unless the
request adds countTotal=true, so count studies for the page or ask for the
total separately.
nws-point-forecast:
import { fetchNwsPointForecast } from '@usa-open-data-connectors/usa-sources';
const point = await fetchNwsPointForecast({ latitude: 47.601, longitude: -122.33 });
console.log(point.gridId, point.gridX, point.gridY, point.forecastUrl);The public API is NWS_API_BASE, NWS_POINT_FORECAST_PATH,
NWS_POINT_FORECAST_SOURCE_ID, NWS_USER_AGENT, NWS_DEFAULT_LATITUDE,
NWS_DEFAULT_LONGITUDE, buildNwsPointUrl, parseNwsPointForecastPayload,
fetchNwsPointForecast, and nwsPointForecastAdapter, with the
NwsForecastPoint type. The parser validates the response with a zod schema
over type, geometry.coordinates, and a properties object carrying
city, state, gridId, gridX, gridY, forecastOffice, forecast,
forecastHourly, forecastGridData, observationStations, timeZone,
radarStation, county, fireWeatherZone, and the nested
relativeLocation.properties place label. A response that is not a GeoJSON
feature, has no coordinate pair, or has no grid id, grid cell, forecast URL, or
forecast office throws UsSourceParseError.
Three shape notes. The point lookup returns the forecast grid and the URLs that
lead to the forecast, not the forecast periods themselves; a caller that needs
temperatures reads forecastUrl or forecastHourlyUrl next. Grid cell numbers
are local to an office, so gridX 100 in one office and gridX 100 in another
point at different places; always keep gridId next to the cell. The place
label is the nearest place the service knows, not the caller's own name: a
lookup for Tacoma came back as "Seattle" on 2026-10-20, and a lookup for
Tacoma Old City Hall landed in office SEW at cell 125,68.
callook-callsigns:
import { fetchCallookCallsigns } from '@usa-open-data-connectors/usa-sources';
const directory = await fetchCallookCallsigns({ callsigns: ['W1AW'] });
console.log(directory.callsigns[0]?.callsign, directory.soonestExpiry?.expiryDate);Callook answers one callsign per request. The default fetch reads W1ABC through
W0ABC, one callsign for each US call district. Pass callsigns to read a
different set. The parser keeps a lookup with status INVALID or UPDATING as
a record with no licence fields, and counts only VALID records in the folded
totals.
college-scorecard-institutions:
import { fetchCollegeScorecardInstitutions } from '@usa-open-data-connectors/usa-sources';
const snapshot = await fetchCollegeScorecardInstitutions();
console.log(snapshot.institutionCount, snapshot.highestEarningState?.stateAbbr);The adapter reads the keyless institution-level bulk download, not the keyed College Scorecard API. The archive is a zip that holds one wide CSV, and a live fetch takes about 20 seconds on a fast connection.
federal-register-documents:
import { fetchFederalRegisterDocuments } from '@usa-open-data-connectors/usa-sources';
const page = await fetchFederalRegisterDocuments({ perPage: 10, order: 'newest' });
console.log(page.documentCount, page.reportedCount, page.documents[0]?.documentNumber);The public API is FEDERAL_REGISTER_API_BASE,
FEDERAL_REGISTER_DEFAULT_PAGE_SIZE, FEDERAL_REGISTER_DEFAULT_ORDER,
FEDERAL_REGISTER_DOCUMENTS_SOURCE_ID, buildFederalRegisterDocumentsUrl,
parseFederalRegisterDocumentsPayload, fetchFederalRegisterDocuments, and
federalRegisterDocumentsAdapter, with the FederalRegisterDocument,
FederalRegisterDocumentsPage, and FederalRegisterDocumentsQuery types. The
parser keeps the document number, title, type, publication date, abstract,
agency names, and HTML and PDF links. It also keeps the service's count and
total_pages as reportedCount and totalPages. A document without its
number, title, type, HTML page, or a readable YYYY-MM-DD publication date
throws UsSourceParseError.
nhtsa-vehicle-models:
import { fetchNhtsaVehicleModels } from '@usa-open-data-connectors/usa-sources';
const page = await fetchNhtsaVehicleModels({ modelYear: 2025, make: 'Honda' });
console.log(page.modelCount, page.totalCount, page.models[0]?.vehicleModel);The public API is NHTSA_VEHICLE_MODELS_API_BASE,
NHTSA_VEHICLE_MODELS_SOURCE_ID, NHTSA_DEFAULT_MODEL_YEAR,
NHTSA_DEFAULT_MAKE, NHTSA_MODEL_PAGE_SIZE, NHTSA_MIN_MODEL_YEAR,
NHTSA_MAX_MODEL_YEAR, buildNhtsaVehicleModelsUrl,
parseNhtsaVehicleModelsPayload, fetchNhtsaVehicleModels, and
nhtsaVehicleModelsAdapter, with the NhtsaVehicleModel,
NhtsaVehicleModelPage, and NhtsaVehicleModelsQuery types. A blank make or a
model year outside 1900-2100 throws UsSourceApiError before a request leaves.
A non-200 service status in the body also throws UsSourceApiError.
fcc-socrata-catalogue:
import { fetchFccSocrataCatalogue } from '@usa-open-data-connectors/usa-sources';
const catalogue = await fetchFccSocrataCatalogue({ limit: 10 });
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is FCC_SOCRATA_CATALOGUE_API_BASE,
FCC_SOCRATA_CATALOGUE_LIMIT, FCC_SOCRATA_CATALOGUE_SOURCE_ID,
buildFccSocrataCatalogueUrl, parseFccSocrataCataloguePayload,
fetchFccSocrataCatalogue, and fccSocrataCatalogueAdapter, with the
FccSocrataCatalogueEntry, FccSocrataCategoryCount, and
FccSocrataCatalogue types. The parser folds the entries into a dataset count,
the newest entry, and category counts. A missing id, name, or creation time
throws UsSourceParseError, and so does an empty page.
ny-state-open-data-catalogue:
import { fetchNyStateOpenDataCatalogue } from '@usa-open-data-connectors/usa-sources';
const catalogue = await fetchNyStateOpenDataCatalogue({ limit: 10 });
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is NY_STATE_OPEN_DATA_API_BASE,
NY_STATE_OPEN_DATA_CATALOGUE_LIMIT, NY_STATE_OPEN_DATA_CATALOGUE_SOURCE_ID,
buildNyStateOpenDataCatalogueUrl, parseNyStateOpenDataCataloguePayload,
fetchNyStateOpenDataCatalogue, and nyStateOpenDataCatalogueAdapter, with the
NyStateOpenDataCatalogueEntry, NyStateOpenDataCategoryCount, and
NyStateOpenDataCatalogue types. The parser follows the same Socrata catalogue
shape as the FCC adapter.
chicago-open-data-catalogue:
import { fetchChicagoOpenDataCatalogue } from '@usa-open-data-connectors/usa-sources';
const catalogue = await fetchChicagoOpenDataCatalogue({ limit: 10 });
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is CHICAGO_OPEN_DATA_API_BASE,
CHICAGO_OPEN_DATA_CATALOGUE_LIMIT, CHICAGO_OPEN_DATA_CATALOGUE_SOURCE_ID,
buildChicagoOpenDataCatalogueUrl, parseChicagoOpenDataCataloguePayload,
fetchChicagoOpenDataCatalogue, and chicagoOpenDataCatalogueAdapter, with the
ChicagoOpenDataCatalogueEntry, ChicagoOpenDataCategoryCount, and
ChicagoOpenDataCatalogue types. The parser folds the entries into a dataset
count, the newest entry, and category counts.
seattle-open-data-catalogue:
import { fetchSeattleOpenDataCatalogue } from '@usa-open-data-connectors/usa-sources';
const catalogue = await fetchSeattleOpenDataCatalogue({ limit: 10 });
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is SEATTLE_OPEN_DATA_API_BASE,
SEATTLE_OPEN_DATA_CATALOGUE_LIMIT, SEATTLE_OPEN_DATA_CATALOGUE_SOURCE_ID,
buildSeattleOpenDataCatalogueUrl, parseSeattleOpenDataCataloguePayload,
fetchSeattleOpenDataCatalogue, and seattleOpenDataCatalogueAdapter, with the
SeattleOpenDataCatalogueEntry, SeattleOpenDataCategoryCount, and
SeattleOpenDataCatalogue types. The parser follows the same Socrata catalogue
shape as the Chicago adapter.
texas-open-data-catalogue:
import { fetchTexasOpenDataCatalogue } from '@usa-open-data-connectors/usa-sources';
const catalogue = await fetchTexasOpenDataCatalogue({ limit: 10 });
console.log(catalogue.entryCount, catalogue.datasetCount, catalogue.categories[0]);The public API is TEXAS_OPEN_DATA_API_BASE,
TEXAS_OPEN_DATA_CATALOGUE_LIMIT, TEXAS_OPEN_DATA_CATALOGUE_SOURCE_ID,
buildTexasOpenDataCatalogueUrl, parseTexasOpenDataCataloguePayload,
fetchTexasOpenDataCatalogue, and texasOpenDataCatalogueAdapter, with the
TexasOpenDataCatalogueEntry, TexasOpenDataCategoryCount, and
TexasOpenDataCatalogue types. The parser follows the same Socrata catalogue
shape as the Chicago and Seattle adapters.
Notes and limits
bls-unemployment-rate: the public API refuses a window longer than ten years.fetchBlsSeriessplits a longer range into windows, so two decades cost three calls once the range reaches the current year.bls-unemployment-rate: keyless access allows 25 series queries a day. A registered key allows 500, and the adapter takesapiKeyfor the day that matters.bls-unemployment-rate: the agency uses-for a month it could not publish andM13for an annual average. The parser drops both, so one year holds twelve monthly values.usgs-hawaii-earthquakes: the event query answers a window of any length, one request per window. The caller sets the box, the magnitude floor, and the dates.usgs-hawaii-earthquakes: the feed mixes tectonic earthquakes with quarry blasts, explosions, and ice quakes. A row can arrive without a magnitude. The parser keeps only tectonic earthquakes that carry a magnitude and a depth.usgs-hawaii-earthquakes: the catalogue answers newest first.parseUsgsEarthquakesreturns oldest first, so a caller reading index 0 gets the start of the window.cdc-county-obesity: the resource id is per release. This adapter reads the 2025 release. Its estimates come from the 2023 Behavioral Risk Factor Surveillance System (BRFSS) and the Census Bureau 2023 county population estimates. A new release gets a new id, so a caller pinned to this one keeps reading the numbers it was written against.cdc-county-obesity: every row is a model-based estimate, not a count. The release publishes each measure as crude prevalence and as age-adjusted prevalence. The adapter reads the crude rows, because age-adjusted rows answer a different question.cdc-county-obesity: a county the model could not estimate arrives with no value. The release carries no obesity rows for Kentucky and Pennsylvania. The parser drops rows without a value and keeps the national row apart from the counties.ncei-annual-temperature: the download is a CSV, not JSON. It holds two comment lines, a header, then one row per year asYYYYMM,valuein degrees Fahrenheit.parseNceiAnnualTemperatureCsvskips the comments and the header, and stops on any other line shape rather than dropping it.ncei-annual-temperature: the URL carries a window length and a window end month. Twelve months ending in December is the calendar year. The parser refuses a file with more than one row per year.ncei-annual-temperature: the current year joins the file only after December closes it, so the newest row is the last complete calendar year. The 2026 download is dated 2026-09-26 and ends at 2025.noaa-sea-level: one request covers the whole window. Themonthly_meanproduct answers one row per month rather than one row per reading, so 170 years cost one call and about 460 KB. The endpoint is keyless.noaa-sea-level: values are metres against the station Mean Sea Level (MSL) datum, the average of hourly heights over the 1983-2001 National Tidal Datum Epoch. Reading the whole record against one fixed epoch is what makes two years comparable.noaa-sea-level: the API answers a row for every month in the window and leaves the value blank when it has none. Blank rows are dropped. A year's average is taken over the months it has, somonthCountsays how much of the year a value covers.noaa-sea-level: errors come back in the body with HTTP 200, as{"error":{"message":"..."}}. The parser checks for that before reading the data. A wrong product name answers with plain text instead, which fails the shape check.treasury-avg-interest-rate: one keyless request covers the whole run. The dataset answers a row per month per security type. The filter pins the response tosecurity_type_desc:eq:Interest-bearing Debt. That is the portfolio total the bureau's monthly statement is built from. The other rows never reach the parser. They hold the rates on bills, notes, bonds, and non-marketable debt.treasury-avg-interest-rate: the rate is the average across everything outstanding, not the rate on anything issued today. That is why it moves slowly. A new bill reprices a fraction of the portfolio, and a bond issued in 2019 still pays its own coupon.treasury-avg-interest-rate: a page holds at most 10,000 rows and the run is around 300. The adapter asks for the whole series in one request and does not page. The row limit is a named constant.treasury-avg-interest-rate: each row is dated to the last day of its month. A month the agency could not compute arrives without a value, and the parser drops those rows.treasury-avg-interest-rate: a request the API rejects answers with an HTTP error and a body of{"error":"Invalid Query Param","message":"..."}. The parser reports an API error rather than a shape error.treasury-debt-to-penny: one keyless request covers the whole run if the row limit is raised. The file starts on 1993-04-01 and held 8,415 business-day rows on 2026-10-16, about 2.8 MB. The defaultTREASURY_DEBT_TO_PENNY_ROW_LIMITis 10 and the API returns oldest first, so the default page is the first ten days of 1993 rather than recent debt. Pass{ rowLimit: 10_000 }to read the whole series in one request.treasury-debt-to-penny: the API capspage[size]at 10,000 rows and the run still fits under that cap. A caller asking for more gets the cap's worth, so checkdayCountagainst the API'smeta.countwhen the run grows past it.treasury-debt-to-penny: every value arrives as a string, and a figure the agency could not report arrives as the literal text"null". The adapter reads that as null and drops a row with no total. The first row, 1993-04-01, has a total but no public or intragovernmental split.treasury-debt-to-penny:tot_pub_debt_out_amtequalsdebt_held_public_amtplusintragov_hold_amton the rows that carry all three. Keep the split fields when the story compares public debt with intragovernmental holdings, and use the total field for the headline.treasury-debt-to-penny: rows cover business days only. A weekend or federal holiday has no row, so a daily series has gaps by design. Use therecord_daterather than an index when aligning debt with another daily series.treasury-debt-to-penny:sort=-record_dateworks on the API but the URL builder does not set it. The helper reads the oldest-first default, which keeps a fixture and a live response in the same order. A rejected request answers with an HTTP error and a body of{"error":"...","message":"..."}.usgs-peak-streamflow: the adapter reads thepeakscollection on the USGS Water Data OGC API. It does not read the olderwaterservices.usgs.govendpoints. The older statistics service answers503 Service unavailableto about half of scripted requests, which is enough to fail a build. The daily-values service on the older host still works when a daily series is what a story needs.usgs-peak-streamflow: every number in a row arrives as a string, including the peak itself. The parser converts once and keeps the number. A blankvaluemeans the agency filed no peak for that year. The parser drops that row.usgs-peak-streamflow: the rows are dated by water year, which starts on 1 October. A peak on 1955-10-08 is filed under water year 1956, sowaterYearandcalendarYearare separate fields and are not always the same number.usgs-peak-streamflow: the record has holes. At the default gauge there is no row for the 17 water years from 1845 to 1861. The series lists them inmissingWaterYearsrather than drawing them as zero.usgs-peak-streamflow: a gauge with several peaks in one water year is filed once, with the largest. The adapter does not de-duplicate, so two rows for one water year would be a change in the source worth seeing.usgs-peak-streamflow: rows carry the agency's qualifiers, for exampleUNKNOWNREGULATIONorMAXDAILYMEAN. The parser keeps them on each year.usgs-peak-streamflow: one keyless request covers the whole record. The default gauge answers 165 water years in one page of about 126 KB.cpsc-product-recalls: the adapter reads the same service behind the public SaferProducts.gov search. It is keyless.cpsc-product-recalls: one request covers one calendar year, and a wider range fails. The service answers HTTP 200 with a single row. Its title readsError retrieving Recalls: The underlying provider failed on Open.The adapter reads a year at a time for that reason. The parser throws on that row rather than counting it as a recall.cpsc-product-recalls: a year of rows is heavy as JSON. 2025 is 420 recalls in about 1.3 MB, so the default window of 2014 to the current year costs about 11 MB across 13 requests. A year with no recall keeps a zero row inyears.cpsc-product-recalls: the newest year is the year the agency is still filling, sobusiestCompleteYearandquietestCompleteYearare picked from the years before it.completeYearCountsays how many those were.cpsc-product-recalls:ManufacturerCountriesnames every country a recall touches, so a recall can list several countries. The country counts add to more than the recall count. In the 2014 to 2026 window China appears on 2,312 of 3,986 recalls. The United States appears on 753, and 122 countries appear at least once.cpsc-product-recalls:RemedyOptionsis nearly an enum (Refund, Repair, Replace, Dispose, New Instructions, Label, Inspect) with two junk rows. One carriesRand one carries a whole paragraph of consumer instructions. The adapter keeps whatever the agency sends and sorts the counts.cpsc-product-recalls: the service holds recalls from the 1970s. The adapter starts at 2014, which keeps the window to 13 requests.cfpb-consumer-complaints: the adapter reads the search endpoint behind the public Consumer Complaint Database. It is keyless. The bureau answers a scripted request with 403 and a request with a declared user agent with 200.cfpb-consumer-complaints: the search API computes its term aggregations on every request, which takes the body from about fifteen kilobytes to about four hundred. The adapter asks forsize=0&no_aggs=trueand readshits.total.valuewhen it only needs a count. It makes one extra request withoutno_aggsfor the product and company tallies.cfpb-consumer-complaints: the API answers one question per request and has no date sort. The window costs one request per year plus one for the tallies plus one or two to find the newest day.findNewestCfpComplaintDatewalks back from today. It stops at the first day with a complaint.cfpb-consumer-complaints: the first year in the window, 2011, holds only December. The bureau published its first complaints on 1 December 2011. The adapter keeps the year, and the page's data note says the first bar covers one month.cfpb-consumer-complaints: the product tally splits credit reporting across more than one label because the bureau changed its product taxonomy over the years. The adapter keeps whatever the API sends, so the labels intopProductsare not stable.cfpb-consumer-complaints: the committed snapshot holds the folded counts, not the raw complaint rows.fdic-bank-directory: the default request asks for ten rows and sets no active filter. The full file includes historical institutions the FDIC marks inactive, so the first page is not a current bank count. Addfilters=ACTIVE:1to the URL to read the active directory.fdic-bank-directory: the filtered count arrives in bothmeta.totalandtotals.count. Both fields describe the filtered result, not the size of the unfiltered file, sototalBanksis the active count when the request carries the active filter.fdic-bank-directory:banks.data.fdic.govanswers with a redirect toapi.fdic.gov.fetchfollows it. Both hosts answer 200 to a scripted request, and neither needs a key.fdic-bank-directory:FDIC_BANK_FIELDSasks forNAME,CITY,STALP, but the parser requiresIDas well. The service addsIDto the response even when it is not infields, but a caller should ask forID,NAME,CITY,STALPso the request and the parser agree without relying on that behaviour.fdic-bank-directory: each row sits inside adatawrapper with a separatescorefield. The parser readsrow.data, not the wrapper.fdic-bank-directory: the active rows cover state-level codes beyond the 50 states. DC, Puerto Rico, Guam, Micronesia, and the US Virgin Islands each hold active banks, so a caller that labels the counts as states will overstate the map.fdic-bank-directory: the directory counts institutions at the state of the main office. It is not a branch count, and a bank with branches across several states appears once.sec-edgar-filings: the SEC asks every caller to identify itself with a User-Agent header. The adapter sendsSEC_EDGAR_USER_AGENT, which carries a placeholder contact address. A deployment should override it with its own application name and address before the request leaves a shared host.sec-edgar-filings: the submissions file carries the last 1,000 filings, not the issuer's full history. Apple's block ran from 18 September 2015 to 16 October 2026 on 2026-10-19. A caller that needs older rows has to read the filing archive rather than this endpoint.sec-edgar-filings: the default CIK is Apple's,0000320193.fetchSecEdgarFilings({ cik })accepts one to ten digits and zero-pads the value, so320193and0000320193ask for the same issuer.sec-edgar-filings: therecentblock is a set of parallel arrays, not one object per filing. A column the form does not carry arrives as an empty string. The parser turns a blank report date or document description into null, and stops rather than guessing when a column length differs from the accession list.sec-edgar-filings: a filing'ssizeis in bytes and describes the submission file. It is not the size of the main document, and it is not a count of pages.epa-envirofacts-facilities: the state filter takes the value directly after the column name, asTRI_FACILITY/STATE_ABBR/CA/rows/0:9999/JSON. Adding anequalssegment is accepted but ignored, and the service then returns the first rows of the whole table instead of the state asked for.epa-envirofacts-facilities: the default row window is the first ten rows.fetchEpaEnvirofactsFacilitiestakes a state but not a row window, so a caller that needs the whole state builds the URL withbuildEpaEnvirofactsFacilitiesUrl({ stateAbbr, rowWindow })and parses the response withparseEpaEnvirofactsFacilitiesPayload.epa-envirofacts-facilities: the table holds facility records, not release amounts. It is the Toxics Release Inventory facility register, so a row says where a site is and whether the EPA marks it closed (fac_closed_indof1), not how much it released in a year.epa-envirofacts-facilities: every key arrives in lower case, and the parent company is sometimes the literal textNA. The parser reads that as null rather than a company name.epa-envirofacts-facilities: a state response can be large. A full California response runs to several megabytes, and trimming it to the ten fields the parser keeps reduces it to about a megabyte.estimatetax-income-tax: one keyless request answers the federal, state, and local income tax for one salary. The endpoint is limited to 60 requests a minute per address.estimatetax-income-tax: the response is a calculation from the publisher's own engine, not a row from an official statistical release. Every layer cites the IRS or state document it was read from, so the source and the date are visible in the response.estimatetax-income-tax: the engine assumes the standard deduction unlesspreTaxDeductionsis supplied. It does not model itemised deductions, capital gains, or credits, and the response carries that disclaimer.estimatetax-income-tax: the default query is the $85,000 single filer in New York City recorded in the fixture. A federal-only query setsstateto null.ncbi-pubmed-search: the default term isasthmaand the default page is ten ids. Passtermfor another query andretmax: 0when only the match count is needed; the count still arrives.ncbi-pubmed-search:[dp]means Date - Publication, and PubMed can hold both an electronic and a print date for one record. Year buckets built with[dp]can overlap, so their counts can add to more than the unfiltered total. Use[edat](Date - Entry) when each record must fall in exactly one year.ncbi-pubmed-search: keyless NCBI allows about three requests a second. The adapter makes one request per call and does not add a delay, so a caller reading six years must space the calls itself.ncbi-pubmed-search: a query field tag such as[tiab]restricts the match to the title and abstract. Without a tag, PubMed maps the words through MeSH and searches every indexed field, which answers a wider and different count.queryTranslationshows what PubMed actually ran.ncbi-pubmed-search: a bad query answers HTTP 200 withesearchresult.errorinstead of a result block. The parser turns that intoUsSourceApiError, so a caller does not count an error as zero papers.cdc-socrata-catalogue: the default request asks for ten rows. The discovery API answers the whole catalogue when the limit is high enough. CallbuildCdcSocrataCatalogueUrl({ limit: 10_000 })or passlimittofetchCdcSocrataCataloguewhen you need every entry. A limit below the catalogue size truncates the response without an error.cdc-socrata-catalogue: each row is a catalogue entry, not a dataset record.assetTypecan bedataset,file,href,filter,chart,story, ormap. A category can hold one type or a mix, so count the asset type before you describe a category as a dataset collection.cdc-socrata-catalogue: an entry without a category hasnullin the response. The adapter keeps the null on the entry and counts it underUncategorisedincategories. That bucket is an adapter label, not a category the CDC assigned.cdc-socrata-catalogue: the full response is large because each row carries portal metadata. The parser keeps eleven fields, and a fixture trimmed to those fields is much smaller.cdc-socrata-catalogue: the entry carrieslicenceUrlandattributionwhen the portal supplies aLicenseandPublishervalue. On the captured page no entry named a licence URL and only some named a publisher. An empty value means the portal supplied none; check the entry before reuse.bts-transportation-stats: the default request asks for ten rows. The story that consumed this adapter needed the whole catalogue, so it callsbuildBtsTransportationStatsUrl({ limit: 10_000 })and parses the full response withparseBtsTransportationStatsPayload. A lower limit truncates the catalogue without an error.bts-transportation-stats: each row is a catalogue entry, not a dataset record.assetTypecan bestory,dataset,chart,measure,filter,href,map, orfile. The story and dataset counts are different questions, and the catalogue carries both.bts-transportation-stats:viewCountanddownloadCountare the portal's own counters for an item page and its files. They are not unique people. Stories carry views and a zero download count because Socrata does not give a story a download counter, while many entries report no downloads at all.bts-transportation-stats: the response is large because every entry carries portal metadata. The parser keeps eleven fields, and a fixture trimmed to those fields is much smaller.bts-transportation-stats: every entry carrieslicenceUrlandattributionfrom the portal's Common Core metadata. The captured page names the USA.gov public-domain label and the Bureau of Transportation Statistics for every entry.bts-transportation-stats: an entry without a category hasnullin the response. The adapter keeps the null on the entry and counts it underUncategorisedincategories. That bucket is an adapter label, not a category the bureau assigned.healthdata-socrata-catalogue: each entry carrieslicenceUrlandattributionfrom the portal's Common Core metadata. The captured page uses the USA.gov government-works label, ODbL, and PDDL, with publishers including federal agencies and state and city governments.nyc-open-data-catalogue: the discovery API answers a bare JSON array of catalogue entries, not dataset rows. An entry can arrive without a category, which the adapter counts underUncategorised.nyc-open-data-catalogue: the page captured on 2026-10-19 mixes datasets and maps. The adapter counts both, and keeps the view and download totals for the page it read.nyc-open-data-catalogue: entries carrylicenceUrlandattribution, but the captured page supplied neither, so both are empty. Check the portal entry before reusing an item.Unit tests use the committed fixtures and run offline. Run them with
npm run test --workspace @usa-open-data-connectors/usa-sources.Smoke tests hit the live APIs and need
RUN_SMOKE=1. Run them withnpm run test:smoke --workspace @usa-open-data-connectors/usa-sources.nws-point-forecast: one keyless request covers one coordinate. The service asks every caller to send a User-Agent that identifies the application, andfetchNwsPointForecastsendsNWS_USER_AGENTon every call.nws-point-forecast: the response is a GeoJSON feature whosepropertieshold the grid and the links. The forecast itself is a second request toforecastUrl(daily periods) orforecastHourlyUrl(hourly periods).nws-point-forecast:gridXandgridYare numbered inside one forecast office. The same pair in two offices is not the same place, and there is no national grid coordinate in the response.nws-point-forecast:relativeLocation.propertiesnames the nearest place the service knows, which can be a neighboring city. A Tacoma lookup returned "Seattle", so a caller that needs its own label should keep it outside the response.nws-point-forecast: one point response is about 3.5 KB. Twenty-five lookups cost twenty-five requests and about 88 KB of committed JSON when saved as a snapshot.callook-callsigns: the service answers one callsign per request and has no bulk list endpoint. The default ten-district sample costs ten requests. The service asks for no key, and its API reference says the data comes from the FCC licence file, refreshed daily.callook-callsigns: a lookup returnsINVALIDfor a callsign with no current licence. The adapter keeps that answer as a record with statusINVALIDrather than treating it as an HTTP failure. A callsign with a current licence has statusVALIDand carries the licence fields.callook-callsigns: coordinates and the grid square are calculated by Callook from the mailing address, not taken from the FCC file. A record can have an empty location. The adapter keeps the coordinates as null in that case and does not invent a place.college-scorecard-institutions: the bulk archive is 24 MB and the CSV inside it is 102 MB. The adapter raises its request timeout to two minutes. The CSV has 3,379 columns, so the adapter reads only the outcome fields it exposes.college-scorecard-institutions:NAandPSmean the Department of Education did not publish a figure. The adapter keeps those as null, so a chart does not turn a suppressed value into a zero.college-scorecard-institutions: the state summary is a median of the institution medians, not a weighted student average. It answers "what does a typical college in this state report", not "what does a typical student earn".college-scorecard-institutions: the earnings field isMD_EARN_WNE_P10, the median for graduates working and not enrolled ten years after entry. It is not a first-year salary.nextbus-transit-vehicles: the adapter reads one agency route, the Portland Streetcar NS line (portland-sc, route193). The feed also serves other agencies, including non-US ones, so the adapter does not claim to cover every agency on the feed.nextbus-transit-vehicles:t=0asks for every report the feed still holds for the route. The feed returns the current set of streetcars, not a history, so the snapshot describes one moment and is replaced on the next request.nextbus-transit-vehicles: a route with no service returns a snapshot with zero vehicles and a valid timestamp. That is a real answer, not a failure, so the parser keeps it.nextbus-transit-vehicles: the feed carries a copyright notice for the transit agency and Umo IQ, and states no open licence. Check the agency's terms before republishing the positions.federal-register-documents: the newest-documents query answeredcount10,000 andtotal_pages50 on 2026-11-08 even though the request asked for ten rows. The adapter preserves both values as the service reported them and does not treat either as the page size.federal-register-documents: a document can have several agencies, and a Presidential Document can have an empty abstract. Both are valid and the parser keeps them.nhtsa-vehicle-models: the service echoes the make in upper case, so a request forHondareturns rows whosemakeisHONDA. The adapter keeps the response value.nhtsa-vehicle-models: the default query is the 2025 Honda list, which returned 50 models in one page withmax=100on 2026-11-08. A model year or page window outside the validator's range is refused before a request leaves.fcc-socrata-catalogue: the ten-entry page captured on 2026-11-08 mixed one story with nine datasets. The adapter counts onlyassetTypevalues equal todatasetindatasetCount.fcc-socrata-catalogue: the captured page supplied no Common CoreLicenseorPublishervalue, solicenceUrlandattributionare empty. Check each portal entry before reuse.ny-state-open-data-catalogue: the ten-entry page captured on 2026-11-08 mixed nine datasets with one file. The adapter counts onlyassetTypevalues equal todatasetindatasetCount.ny-state-open-data-catalogue: the captured page supplied no Common CoreLicenseorPublishervalue, solicenceUrlandattributionare empty. Check each portal entry before reuse.chicago-open-data-catalogue: the ten-entry page captured on 2026-11-08 mixed five datasets with charts, maps, and stories. The adapter counts onlyassetTypevalues equal todatasetindatasetCount.chicago-open-data-catalogue: the captured page supplied no Common CoreLicenseorPublishervalue, solicenceUrlandattributionare empty. Check each portal entry before reuse.seattle-open-data-catalogue: the ten-entry page captured on 2026-11-08 held three datasets and sevenfederated_hrefentries. The adapter counts onlyassetTypevalues equal todatasetindatasetCount.seattle-open-data-catalogue: the first captured entry supplied licence text that begins "The City of Seattle makes no representation or warranty" and publisherCity of Seattle ArcGIS Online. The adapter keeps both values per entry; other entries can supply neither.texas-open-data-catalogue: the ten-entry page captured on 2026-11-08 held five datasets, three linked resources, one map, and one measure. The adapter counts onlyassetTypevalues equal todatasetindatasetCount.texas-open-data-catalogue: the captured page supplied no Common CoreLicenseorPublishervalue, solicenceUrlandattributionare empty. Check each portal entry before reuse.
Data sources and licences
The data comes from US federal agencies and the open data catalogue services they publish on.
| Publisher | Source URL |
| --- | --- |
| Bureau of Labor Statistics | https://api.bls.gov/publicAPI/v2/timeseries/data |
| US Geological Survey | https://earthquake.usgs.gov/fdsnws/event/1/query and https://api.waterdata.usgs.gov/ogcapi/v0/collections/peak/items |
| Centers for Disease Control and Prevention | https://data.cdc.gov/resource/swc5-untb.json and https://data.cdc.gov/api/views.json |
| NOAA National Centers for Environmental Information | https://www.ncei.noaa.gov/access/monitoring/climate-at-a-glance |
| NOAA Center for Operational Oceanographic Products and Services | https://api.tidesandcurrents.noaa.gov/api/prod/datagetter |
| US Department of the Treasury | https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/accounting/od/avg_interest_rates and https://api.fiscaldata.treasury.gov/services/api/fiscal_service/v2/accounting/od/debt_to_penny |
| Federal Emergency Management Agency | https://www.fema.gov/api/open/v1/FemaWebDisasterDeclarations |
| US Food and Drug Administration | https://api.fda.gov/food/enforcement.json |
| US Consumer Product Safety Commission | https://www.saferproducts.gov/RestWebServices/Recall |
| Consumer Financial Protection Bureau | https://www.consumerfinance.gov/data-research/consumer-complaints/search/api/v1/ |
| US Securities and Exchange Commission | https://data.sec.gov/submissions/CIK0000320193.json |
| Federal Deposit Insurance Corporation | https://banks.data.fdic.gov/api/institutions |
| ClinicalTrials.gov | https://clinicaltrials.gov/api/v2/studies |
| National Weather Service | https://api.weather.gov/points/38.8894,-77.0352 |
| USAspending | https://api.usaspending.gov/api/v2/references/toptier_agencies/ |
| Environmental Protection Agency | https://data.epa.gov/efservice/TRI_FACILITY/STATE_ABBR/RI/rows/0:9/JSON |
| National Center for Biotechnology Information | https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi |
| Bureau of Transportation Statistics | https://data.bts.gov/api/views.json |
| EstimateTax | https://estimatetax.net/api/v1/calculate |
| HealthData.gov | https://healthdata.gov/api/views.json |
| New York City Open Data | https://data.cityofnewyork.us/api/views.json |
| Callook.info | https://callook.info/[callsign]/json |
| College Scorecard, US Department of Education | https://ed-public-download.scorecard.network/downloads/Most-Recent-Cohorts-Institution_10152026.zip |
| PublicDataHub, from the Centers for Medicare & Medicaid Services | https://publicdatahub.org/api/export/hospital/{slug}.json |
| Portland Streetcar, through the NextBus XML feed | https://retro.umoiq.com/service/publicXMLFeed?command=vehicleLocations&a=portland-sc&r=193&t=0 |
| Office of the Federal Register | https://www.federalregister.gov/api/v1/documents.json |
| National Highway Traffic Safety Administration | https://api.nhtsa.gov/vehicles/models |
| Federal Communications Commission | https://opendata.fcc.gov/api/views.json |
| New York State Open Data | https://data.ny.gov/api/views.json |
| City of Chicago | https://data.cityofchicago.org/api/views.json |
| City of Seattle | https://data.seattle.gov/api/views.json |
| State of Texas | https://data.texas.gov/api/views.json |
Each publisher sets its own terms for its data. The Socrata and CKAN catalogue adapters keep the License and
Publisher values from an entry's Common Core metadata as licenceUrl and attribution. An empty
value means the portal supplied none. Check the licence on the portal entry before you reuse an item.
A catalogue can list entrie
