finance-query v3.0.0

BLS (Bureau of Labor Statistics)#

info · Feature flag required

toml
finance-query = { version = "...", features = ["bls"] }

The BLS Public Data API is the primary source for US CPI, unemployment, payrolls, average hourly earnings, and PPI. Alpha Vantage exposes a fixed handful of these, and FRED mirrors them with a lag behind a key — BLS publishes them first.

Keyless / keyed dual mode#

BLS is the only provider in the library that works both with and without a key, and it decides per call:

No keyBLS_API_KEY set
API versionv1v2
Daily quota25 queries per IP500 queries
History per request~3 years20 years
Series titlenot returnedreturned (catalog)

Nothing else differs — the same series ids, the same EconomicSeries response. Get a free key at data.bls.gov/registrationEngine and export it:

bash
export BLS_API_KEY="your-bls-key"

The tier is resolved on every request, so exporting a key mid-process takes effect immediately.

Setup#

rust · no_run feature=bls
use finance_query::{Capability, Provider, Providers};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let providers = Providers::builder()
        .route(Capability::ECONOMIC, [Provider::Bls])
        .build()
        .await?;

    let cpi = providers.economic("CUUR0000SA0").series().await?;
    for obs in cpi.observations.iter().rev().take(3) {
        println!("{} {:?}", obs.date, obs.value);
    }
    Ok(())
}

Series Identifiers#

Series are addressed by their native BLS id. Common ones:

Series idDescriptionFrequency
CUUR0000SA0CPI-U, all items, US city average (NSA)Monthly
CUSR0000SA0CPI-U, all items, US city average (SA)Monthly
CUUR0000SA0L1ECPI-U, all items less food and energyMonthly
LNS14000000Unemployment rateMonthly
LNS11300000Labor force participation rateMonthly
CES0000000001Total nonfarm payroll employmentMonthly
CES0500000003Average hourly earnings, privateMonthly
WPUFD4PPI, final demandMonthly

Full series-id structure is documented in the BLS series-id guide.

Response Shape#

Results come back as the provider-neutral EconomicSeries:

FieldValue from BLS
series_idThe BLS id you passed in
titleThe catalog series title — keyed v2 only, None on the keyless route
unitsAlways None; BLS returns no unit field, and the unit is implied by the series id
frequency"Monthly", "Quarterly", "Semiannual", or "Annual", from the period codes
observationsChronological (oldest first)

Two BLS conventions are normalised:

Errors#

BLS answers an unknown series id with REQUEST_SUCCEEDED, an empty data array, and the complaint in a message field. That surfaces as FinanceError::SymbolNotFound carrying the BLS text, rather than as a silent empty series. A genuine failure status (quota exhausted, malformed request) surfaces as FinanceError::MacroDataError.

Rate Limits#

The BLS quota is daily, not per-second, so it cannot be enforced client-side; the client paces at 2 requests/second only to avoid looking abusive. Exhausting the daily quota returns a REQUEST_NOT_PROCESSED status, which surfaces as MacroDataError with the BLS explanation.

Next Steps#

built with cargo soothfast docs build source