Build a macro dashboard panel for one country

A country macro panel needs five numbers: inflation, unemployment, GDP growth, the policy rate and the trade balance. Narwhal returns each from its own country route with the period it covers and the day it was released, and the economic calendar gives the time of the next release.

Request the inflation figure for one country

curl, US inflation
curl -s "https://api.narwhalapi.com/v1/economics/USA/inflation" \
  -H "Authorization: Bearer $NARWHAL_API_KEY"
Response
{
  "country": "USA",
  "period": "2026-09",
  "year_over_year": "3.7",
  "month_over_month": "0.6",
  "year_to_date": "4.0",
  "released_on": "2026-10-14"
}

year_over_year is the headline number for a tile. period is the month the figure describes and released_on is the day it was published, so a tile can print both. Values arrive as decimal strings, so convert them before you chart them.

The other four panel lines come from sibling routes with the same shape. Each returns the latest period when you send no date.

Panel lineRouteHeadline fieldPeriod format
Inflation/v1/economics/{country}/inflationyear_over_year2026-09
Unemployment/v1/economics/{country}/unemploymentrate2026-09
GDP growth/v1/economics/{country}/gdp-growthyear_over_year2026-Q3
Policy rate/v1/economics/{country}/central-bank/policy-ratelower_bound and upper_bound, or ratenone, see effective_on
Trade balance/v1/economics/{country}/tradebalance2026-08

Handle period and released_on

The five lines do not share a period. For the US the inflation and unemployment responses describe 2026-09, GDP growth describes the quarter 2026-Q3 and the trade response describes 2026-08. Label each tile with its own period and do not line the tiles up by release day.

released_on is the publication date of that figure. Keep it as its own field. A tile that shows only the release date reads as if the figure describes that month, and a tile that shows only the period hides how old the number is.

  • The policy rate response has no period. It carries effective_on, observed_on and announced_on, and any of them can be null. For the US it returned rate_type of range with lower_bound 3.75 and upper_bound 4.00, so print the range. A country with rate_type of point returns a single rate.
  • The trade response gives exports, imports and balance in currency, here USD. The balance is exports minus imports, so the US value of -131421164606 means imports were larger.
  • A country without a series answers 404 with the problem code series_not_found. Mexico returned that for its policy rate while its inflation, GDP growth and unemployment answered. Show a gap for that line and keep drawing the others.

Add the next release time from the calendar

To know when a tile should change, read GET /v1/economics/calendar for the same country. Each entry has a series_id, the period it will cover and an at time in UTC. The script below pulls the calendar for the next 60 days, picks the earliest at for each line and prints the whole panel.

  1. Get a key Create an API key and export it as NARWHAL_API_KEY. The script sends it as a Bearer token.
  2. Run the script It requests the calendar once, then the five data routes. A 404 returns None and prints no data for that line.
    Python, macro panel for one country
    import os
    from datetime import date, timedelta
    import requests
    
    BASE = "https://api.narwhalapi.com"
    HEAD = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"}
    country = "USA"
    
    def get(path, **params):
        r = requests.get(BASE + path, params=params, headers=HEAD, timeout=10)
        if r.status_code == 404:
            return None
        r.raise_for_status()
        return r.json()
    
    calendar = get(
        "/v1/economics/calendar",
        countries=country,
        start_date=date.today().isoformat(),
        end_date=(date.today() + timedelta(days=60)).isoformat(),
    )["releases"]
    
    def next_release(series_id):
        due = [x["at"] for x in calendar if x["series_id"] == series_id and "at" in x]
        return min(due) if due else None
    
    panel = [
        ("Inflation, % y/y", "inflation", "year_over_year", "usa-consumer-prices"),
        ("Unemployment, %", "unemployment", "rate", "usa-employment-report"),
        ("GDP growth, % y/y", "gdp-growth", "year_over_year", "usa-gdp"),
        ("Trade balance, USD", "trade", "balance", "usa-goods-and-services-trade"),
    ]
    for label, path, field, series_id in panel:
        d = get(f"/v1/economics/{country}/{path}")
        if d is None:
            print(label, "no data")
            continue
        print(label, d[field], d["period"], d["released_on"], next_release(series_id))
    
    rate = get(f"/v1/economics/{country}/central-bank/policy-rate")
    if rate:
        print("Policy rate, %", rate["lower_bound"], rate["upper_bound"], rate["effective_on"],
              next_release("usa-policy-rate-decision"))
  3. Read the output Each printed row holds the value, its period, released_on and the next at. Compare at with the clock to decide when to call the route again.
LineValuePeriodReleased onNext release (UTC)
Inflation, % y/y3.72026-092026-10-142026-11-10T13:30:00Z
Unemployment, %4.22026-092026-10-022026-11-06T13:30:00Z
GDP growth, % y/y2.12026-Q32026-10-292026-11-25T13:30:00Z
Trade balance, USD-1314211646062026-082026-10-062026-11-04T13:30:00Z
Policy rate, %3.75 to 4.00effective 2026-09-17not applicable2026-12-09T19:00:00Z

The calendar entry for GDP on 2026-11-25 has stage of second, so it covers 2026-Q3 again. The panel should show the same period with a possibly different value after that time.

How often should the panel refresh?

Poll the calendar once a day and re-read a line when the clock passes its at time. Between those times the calendar lists no new figure for that line. The at time can move, so read it again on each poll instead of storing it for weeks.

Each entry also carries a status, which is scheduled until the release is out, so a line whose status has changed is worth re-reading even before you reach its next poll.

Which period does a GDP tile show?

The newest quarter that has a figure. In the table above the latest quarter is 2026-Q3, released on 2026-10-29. The route answers with quarter_over_quarter as well, so a tile can show either rate. State which one it is, because the two differ.

Send period=2026-Q3 to read a named quarter and compare it with the latest.

What does a negative trade balance mean?

It means imports exceeded exports in that period. The US response shows exports of 204748660746 and imports of 336169825352, and 204748660746 minus 336169825352 equals the published balance of -131421164606 USD.

Published .

Next steps