Use the Narwhal API with pandas and Jupyter

Use pandas and Jupyter with Narwhal API to pull holidays, release dates, economics, commodity spot prices, exchange rates and prediction-market odds. Make authenticated requests with requests, then turn the response fields into pandas DataFrames.

What you'll set up

Jupyter is the notebook for this pandas workflow: you end up with a request helper, DataFrames for the returned records and a numeric Brent spot price. Narwhal uses one account and one API key across its data APIs. REST and MCP share that key. The notebook uses REST requests to https://api.narwhalapi.com, with the key in the Authorization: Bearer YOUR_KEY header. The economics API includes CPI, inflation, GDP and yields; this notebook uses CPI observations for a month-on-month calculation.

Set your API key

  1. Create a free key Get a free key at Narwhal signup. Use that key for the notebook's requests across the data areas.
  2. Install the notebook packages Install pandas, requests and Jupyter before opening the notebook. The code uses requests for HTTP calls and pandas for the returned records.
    Install packages
    pip install pandas requests jupyter
  3. Set the key and start Jupyter Replace YOUR_KEY with your key and export NARWHAL_API_KEY before starting Jupyter Lab. Never put the key in a notebook cell you save; the Python code reads it from the environment. The os.environ lookup in the cell uses that exact variable name when it builds the bearer header.
    Start Jupyter with the key
    export NARWHAL_API_KEY=YOUR_KEY
    jupyter lab

Pull data with code

Put this Python code in your notebook. pd.read_json(url) cannot send the authorization header, so the get helper makes the request with requests and returns the JSON. Each DataFrame uses the response field for its area. The CPI calculation uses the returned levels to calculate month on month, while the prediction dates are converted with pd.to_datetime. The helper passes query parameters through params, sends HEADERS with each call and sets timeout=10. It calls raise_for_status() before reading the JSON response. Keep that helper with the area calls so each request uses the same authorization handling.

pandas, all six areas
import os
import pandas as pd
import requests

API = "https://api.narwhalapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"}

def get(path, **params):
    r = requests.get(API + path, params=params, headers=HEADERS, timeout=10)
    r.raise_for_status()
    return r.json()

holidays = pd.DataFrame(get("/v1/calendars/holidays/USA/2026")["holidays"])
releases = pd.DataFrame(get("/v1/economics/calendar", countries="USA", start_date="2026-11-01", end_date="2026-11-30", limit=100)["releases"])
cpi = pd.DataFrame(get("/v1/economics/USA/cpi/observations", start="2025-09")["observations"])
fx = pd.DataFrame(get("/v1/fx/rates/USD", currencies="EUR,IDR")["rates"])
fed = pd.DataFrame(get("/v1/predictions/policy-paths/federal-reserve")["meetings"])
brent = float(get("/v1/commodities/spot/BRENT/USD")["price"])

cpi["value"] = cpi["value"].astype(float)
cpi["mom_pct"] = cpi["value"].pct_change() * 100
fed["resolves_at"] = pd.to_datetime(fed["resolves_at"]).dt.date

print(holidays[["date", "name"]].head(3))
print(cpi[["period", "value", "mom_pct"]].tail(3))
print(fx)
print(fed[["resolves_at", "p_cut", "p_hold", "p_hike"]].head(2))
print("Brent", brent)

On 24 October 2026, the last three CPI rows were July 2026 at 333.918 with month-on-month inflation of -0.01%, August 2026 at 334.980 with 0.32%, and September 2026 at 336.940 with 0.59%. The mom_pct column is calculated from the CPI levels by pct_change() * 100.

Run it on a schedule

Convert the notebook to a script with jupyter nbconvert, then run the script from cron. Keep the key in NARWHAL_API_KEY for the scheduled script as well: its HEADERS assignment reads the same environment variable as the notebook. The conversion command uses pull.ipynb as the notebook filename.

Convert the notebook
jupyter nbconvert --to script pull.ipynb

You can also call the same functions from a scheduled job. Use the request helper and the area calls from the notebook for that job, with the bearer header supplied through HEADERS. For scheduling the pull, see schedule a daily data pull.

Holidays in pandas

Read USA holidays for 2026 from the holidays response field. Each holiday has date and name, so those columns give you the holiday date beside its name in the notebook. This sample uses the same authenticated get helper as the full cell and selects those fields for display. Keep the helper defined before using the area samples.

Read holiday dates and names
data = get("/v1/calendars/holidays/USA/2026")
holidays = pd.DataFrame(data["holidays"])
print(holidays[["date", "name"]].head(3))

Release dates in pandas

Pull the economic calendar for USA releases from 1 November 2026 through 30 November 2026, with limit=100. The response field is releases. Its records have at, period, topic and status, which you can display together in a DataFrame. Use this call for release dates; use the observations call in the economics sample for CPI levels by period.

Read economic release dates
data = get("/v1/economics/calendar", countries="USA", start_date="2026-11-01", end_date="2026-11-30", limit=100)
releases = pd.DataFrame(data["releases"])
print(releases[["at", "period", "topic", "status"]])

Economics in pandas

Request USA CPI observations with start=2025-09 and read observations into a DataFrame. Each record has a period and a value. Convert the value column before calculating month-on-month changes. If the requested start is earlier than your plan's history window, it moves up to the window's first day without an error, so the response begins later than requested. A 403 plan_upgrade_required response applies when the whole range ends before the window, or when you read a single date or period outside it.

Calculate CPI month on month
data = get("/v1/economics/USA/cpi/observations", start="2025-09")
cpi = pd.DataFrame(data["observations"])
cpi["value"] = cpi["value"].astype(float)
cpi["mom_pct"] = cpi["value"].pct_change() * 100
print(cpi[["period", "value", "mom_pct"]].tail(3))

Commodity spot prices in pandas

The Brent call reads the price field and converts it to a float. It uses BRENT as the spot code and USD in the request path. Spot codes include, for example, XAU, XAG, XPT, XPD, XCU, BRENT and WTI. For this sample, keep the Brent path and use the numeric value returned by float in your notebook.

Read the Brent spot price
data = get("/v1/commodities/spot/BRENT/USD")
brent = float(data["price"])
print("Brent", brent)

Exchange rates in pandas

Use the USD rates path with currencies=EUR,IDR to request the exchange rates in this sample. Read the rates field into a DataFrame; each returned record has currency and rate. Selecting those columns keeps the currency beside its rate. The request uses the same key and header as the CPI and holiday calls.

Read USD exchange rates
data = get("/v1/fx/rates/USD", currencies="EUR,IDR")
fx = pd.DataFrame(data["rates"])
print(fx[["currency", "rate"]])

Prediction-market odds in pandas

Read the Federal Reserve policy path from the meetings field. Each meeting has resolves_at, p_cut, p_hold and p_hike. Convert resolves_at to a date with the same pandas expression used in the full cell, then display it beside the odds fields. This keeps the meeting's resolution date and its cut, hold and hike fields together in the notebook output.

Read policy-path meetings
data = get("/v1/predictions/policy-paths/federal-reserve")
fed = pd.DataFrame(data["meetings"])
fed["resolves_at"] = pd.to_datetime(fed["resolves_at"]).dt.date
print(fed[["resolves_at", "p_cut", "p_hold", "p_hike"]].head(2))

Why are my numbers text?

The API returns decimals as strings to keep precision. Use astype(float) on a DataFrame column when you need numeric calculations, as in cpi["value"].astype(float). For the single Brent price, the sample uses float on the returned price field. Apply the conversion to the values you need for arithmetic. The response field names stay the same when the values become numeric.

How do I get year over year?

Call /v1/economics/USA/inflation for the headline rate. It returns year_over_year and month_over_month on every plan. A year-over-year calculation from CPI levels needs the level 12 months before the month being compared, which a Free key's 12-month history window does not hold.

Published .