---
name: bea-data-api-ingestion
description: "How to get U.S. BEA Data API data into a pandas DataFrame and Parquet: access, the request, the format, limits, quirks and terms."
---

# Load BEA regional personal income into pandas and Parquet

Source entry: https://signal-lab-jet.vercel.app/datasets/bea-data-api
Provider: https://apps.bea.gov/API/docs/index.htm
Checked against the provider's documentation: 2026-11-01

## Access
- Register for a free 36-character UserID and activate it from the email link.
- Set the key in the BEA_API_KEY environment variable; do not place it in source code.

## Request
```bash
curl 'https://apps.bea.gov/api/data/?UserID=$BEA_API_KEY&method=GetData&datasetname=Regional&TableName=CAINC1&LineCode=1&Year=2024&GeoFips=STATE&ResultFormat=JSON'
```

## Format
JSON containing request metadata and Regional data rows with geography codes and names, time period, line code, unit, value and note references.

## Load into pandas and Parquet
Needs Python 3 with requests, pandas and pyarrow.
```python
"""BEA state personal income for 2024 -> pandas -> Parquet. Free API key required."""
import os
import requests
import pandas as pd

URL = "https://apps.bea.gov/api/data/"
params = {
    "UserID": os.environ["BEA_API_KEY"],
    "method": "GetData",
    "datasetname": "Regional",
    "TableName": "CAINC1",
    "LineCode": "1",
    "Year": "2024",
    "GeoFips": "STATE",
    "ResultFormat": "JSON",
}
r = requests.get(URL, params=params, timeout=60)
r.raise_for_status()
payload = r.json()["BEAAPI"]["Results"]
if "Error" in payload:
    raise RuntimeError(payload["Error"])
df = pd.DataFrame(payload["Data"])
df["DataValue"] = pd.to_numeric(df["DataValue"].str.replace(",", "", regex=False), errors="coerce")
df.to_parquet("bea_state_personal_income_2024.parquet", index=False)
print(len(df), "rows", df["TimePeriod"].min(), "to", df["TimePeriod"].max())
```
Not run: it needs a free API key.

## Limits
- 100 requests per minute.
- 100 MB retrieved per minute.
- 30 errors per minute; throttled responses use HTTP 429 and Retry-After.

## Quirks
- DataValue is commonly returned as formatted text with commas; parse it after preserving the original unit and note fields.
- Dataset parameters differ. Use GetParameterList and GetParameterValues rather than assuming a shared schema.
- Keep table and line identifiers because similarly named measures can have different units or adjustments.

## Terms and attribution
- Display BEA's specified non-endorsement notice prominently in services that use the API.
- Do not modify or falsely represent API content while claiming BEA as the source.
- BEA may monitor, limit or terminate API access under its terms.
- Terms page: https://apps.bea.gov/api/_pdf/bea_api_tos.pdf

## Sources
- https://apps.bea.gov/API/docs/index.htm: "Our Data API provides programmatic access to published economic statistics using industry-standard methods and procedures."
- https://apps.bea.gov/api/_pdf/bea_web_service_api_user_guide.pdf: "Before using the API, users must obtain a unique 36-character UserID by registering"
- https://apps.bea.gov/api/_pdf/bea_web_service_api_user_guide.pdf: "Number of requests per minute (100), and/or"
- https://apps.bea.gov/api/_pdf/bea_api_tos.pdf: "This product uses the Bureau of Economic Analysis (BEA) Data API but is not endorsed or certified by BEA."

## Help improve this skill
Missing a source, or see something to improve? Call the MCP tool suggest_source or feedback (or POST /api/suggest or /api/feedback). Reviewed ideas: https://signal-lab-jet.vercel.app/agent-suggestions

Information for educational purposes only. Free tiers, limits and licenses belong to the providers and may change; check the provider's own terms before using the data.
