Migrate from Alpha Vantage to Narwhal

To move from Alpha Vantage, replace the apikey query parameter with an Authorization: Bearer header and map each function to a Narwhal path. CPI, unemployment, FX, stock quotes, daily bars, metals, oil and crypto have direct equivalents. Technical indicators, options and news sentiment do not.

Who should migrate, and who should stay

Teams move for licence and quota reasons. Alpha Vantage limits free and premium keys to personal, non-commercial use unless you agree otherwise in writing, while the Narwhal Free plan includes commercial app use. The Alpha Vantage free key allows 25 requests a day; Narwhal Free allows 5,000 a month. Alpha Vantage economic series cover the United States only, and Narwhal reads economics for 37 countries. One Narwhal key also works over MCP, which suits agent projects.

Stay with Alpha Vantage for technical indicators, options and news sentiment. It lists 25 or more years of daily history, while Narwhal Free reaches back 12 months, Basic 5 years and Pro full history. Narwhal stocks cover 42 exchanges, and Tokyo is not one of them.

Map each function to an endpoint

Each path below was called with a live key on 3 November 2026. Look a stock up with /v1/equities/search first, because Narwhal ids carry the exchange, as in XNYS:IBM.

Alpha Vantage functionNarwhal endpointWhat differs
CURRENCY_EXCHANGE_RATEGET /v1/fx/rates/{base}?currencies=Several currencies per call. A rate with a timestamp, no bid or ask.
FX_DAILYGET /v1/fx/rates/{base}/observationsOne rate per day. For open, high, low and close, call /v1/fx/rates/USD/bars with USD as the base.
GLOBAL_QUOTEGET /v1/equities/{id}/pricechange_percent carries no percent sign.
TIME_SERIES_DAILYGET /v1/equities/{id}/bars?interval=1dWeekly and monthly bars have no endpoint; aggregate the daily bars.
SYMBOL_SEARCHGET /v1/equities/searchNarrow results with country.
DIGITAL_CURRENCY_DAILYGET /v1/crypto/{pair}/barsPairs read BTC-USD.
CPIGET /v1/economics/{country}/cpi/observationsUses period, not date.
INFLATIONGET /v1/economics/{country}/inflation/observationsMonthly year-over-year, month-over-month and year-to-date, where Alpha Vantage gives an annual percent.
UNEMPLOYMENTGET /v1/economics/{country}/unemployment/observationsThe field is rate.
REAL_GDPGET /v1/economics/{country}/gdp-growth/observationsGrowth rates only. /gdp returns an annualized level, so check its definition before comparing.
FEDERAL_FUNDS_RATEGET /v1/economics/USA/central-bank/policy-rate/historyGives the target range as lower_bound and upper_bound, not the effective rate.
TREASURY_YIELDGET /v1/economics/USA/yield-curve/history?maturity=10yLowercase maturities such as 10y.
RETAIL_SALES, DURABLES, NONFARM_PAYROLLGET /v1/economics/calendarRead each release's values. Payrolls arrive as a monthly change in thousands.
GOLD_SILVER_SPOT, WTI, BRENTGET /v1/commodities/spot/{commodity}/{currency}Latest price, for example XAU/USD. History sits at /bars.
INCOME_STATEMENT, BALANCE_SHEET, CASH_FLOWGET /v1/companies/{company_id}/financials?statement=Filings data under ids such as usa:0000051143.

What has no Narwhal equivalent

Keep Alpha Vantage, or another source, for these.

  • Technical indicators, 53 functions such as SMA, RSI and MACD.
  • Options, both realtime and historical.
  • NEWS_SENTIMENT and IPO_CALENDAR.
  • Index breadth: INDEX_DATA lists 200 or more indices, and Narwhal prices 18.

Migrate three calls

  1. Set your key Get a free key and keep it in NARWHAL_API_KEY. Narwhal reads it from the Authorization: Bearer header, so remove apikey from every URL.
  2. Swap the CPI call The Narwhal path names the country and returns the latest value. For history, add /observations with start and end, which returns the same index values Alpha Vantage lists.
    curl, CPI before and after
    # Ran 2026-11-03: Alpha Vantage 200 OK with the demo key, Narwhal 200 OK both calls
    # Before: Alpha Vantage, CPI
    curl "https://www.alphavantage.co/query?function=CPI&interval=monthly&apikey=demo"
    
    # After: Narwhal, latest US CPI
    curl "https://api.narwhalapi.com/v1/economics/USA/cpi" \
      -H "Authorization: Bearer $NARWHAL_API_KEY"
    
    # After: Narwhal, CPI for July to September
    curl -G \
      --url "https://api.narwhalapi.com/v1/economics/USA/cpi/observations" \
      -d start=2026-07 -d end=2026-09 \
      -H "Authorization: Bearer $NARWHAL_API_KEY"
  3. Swap the quote and FX calls Narwhal resolves a stock by listing id, and an FX rate by base currency with the targets in currencies.
    curl, quote and FX before and after
    # Ran 2026-11-03: Alpha Vantage quote 200 OK (demo key), Narwhal quote and FX 200 OK
    # Before: Alpha Vantage, last price for IBM
    curl "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=IBM&apikey=demo"
    
    # After: Narwhal, same stock (ids look like XNYS:IBM)
    curl "https://api.narwhalapi.com/v1/equities/XNYS:IBM/price" \
      -H "Authorization: Bearer $NARWHAL_API_KEY"
    
    # Before: Alpha Vantage, USD to JPY (request taken from its documentation, not run)
    curl -G \
      --url "https://www.alphavantage.co/query" \
      -d function=CURRENCY_EXCHANGE_RATE -d from_currency=USD \
      -d to_currency=JPY -d apikey=YOUR_ALPHA_VANTAGE_KEY
    
    # After: Narwhal, USD to JPY
    curl "https://api.narwhalapi.com/v1/fx/rates/USD?currencies=JPY" \
      -H "Authorization: Bearer $NARWHAL_API_KEY"
  4. Rewrite the parser Fields lose their numbers, and the series becomes an array. The script makes all three Narwhal calls.
    Python, the three calls on Narwhal
    # Ran 2026-11-03: 200 OK for all three calls
    import os
    import requests
    
    session = requests.Session()
    session.headers["Authorization"] = f"Bearer {os.environ['NARWHAL_API_KEY']}"
    
    
    def get(path, **params):
        r = session.get("https://api.narwhalapi.com" + path, params=params, timeout=10)
        r.raise_for_status()
        return r.json()
    
    
    cpi = get("/v1/economics/USA/cpi")  # was function=CPI
    print(cpi["period"], cpi["value"])
    
    ibm = get("/v1/equities/search", q="IBM", country="USA")["results"][0]["id"]
    print(ibm, get(f"/v1/equities/{ibm}/price")["price"])  # was GLOBAL_QUOTE
    
    fx = get("/v1/fx/rates/USD", currencies="JPY")["rates"][0]  # was CURRENCY_EXCHANGE_RATE
    print(fx["currency"], fx["rate"])
  5. Compare the output Run both providers on the same inputs. US CPI for 2026-09 is 336.940 on both, and the IBM close of 2 November is 252.51 on both.

How the responses differ

Alpha Vantage nests an FX rate under Realtime Currency Exchange Rate with numbered keys. Narwhal returns a rates array with one object per currency.

AspectAlpha VantageNarwhal
Field namesNumbered, such as 05. pricePlain, such as price
SeriesObject keyed by date, newest firstArray of observations or bars, oldest first
NumbersStringsStrings, so parse them as decimals
PagingNone; outputsize picks 100 points or allnext_cursor
ErrorsHTTP 200 with Information or Error MessageAn HTTP error status and a body with code
Alpha Vantage CPI, trimmed
{
  "name": "Consumer Price Index for all Urban Consumers",
  "interval": "monthly",
  "unit": "index 1982-1984=100",
  "data": [
    { "date": "2026-09-01", "value": "336.940" },
    { "date": "2026-08-01", "value": "334.980" }
  ]
}
Narwhal CPI, trimmed
{
  "country": "USA",
  "period": "2026-09",
  "value": "336.940",
  "index_base": "1982-84=100",
  "released_on": "2026-10-14"
}
Alpha Vantage quote, trimmed
{
  "Global Quote": {
    "01. symbol": "IBM",
    "05. price": "252.5100",
    "07. latest trading day": "2026-11-02",
    "08. previous close": "257.8100",
    "10. change percent": "-2.0558%"
  }
}
Narwhal quote, trimmed
{
  "id": "XNYS:IBM",
  "symbol": "IBM",
  "currency": "USD",
  "price": "252.51",
  "previous_close": "257.81",
  "change_percent": "-2.06",
  "market_session": "closed",
  "timestamp": "2026-11-02T21:00:00Z",
  "stale": false
}

Handle rate limits

The Alpha Vantage free key allows 25 requests a day. Its premium plans run from 75 to 1,200 requests a minute with no daily cap, starting at $49.99 a month. Narwhal Free allows 30 requests a minute and 5,000 a month. Basic allows 120 a minute and 100,000 a month, and Pro allows 500 and 1,000,000.

Alpha Vantage reports problems inside a 200 response, so a check on the status code misses them; for calls outside its examples, the demo key returned an Information note. Narwhal answers 429. A rate_limit_exceeded code means wait for the Retry-After header and retry, and quota_exhausted means the month is spent until 00:00 UTC on the 1st. Neither counts against your quota. Each success carries X-RateLimit-Remaining and X-RateLimit-Reset. See cache responses and handle 429 errors for caching.

Python, retry on Retry-After
# Ran 2026-11-03: 200 OK on both test calls; the 429 branch follows the documented codes
import os
import time
import requests

session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['NARWHAL_API_KEY']}"


def get(path, **params):
    for attempt in range(4):
        r = session.get("https://api.narwhalapi.com" + path, params=params, timeout=10)
        if r.status_code == 429:
            if r.json().get("code") == "quota_exhausted":
                raise RuntimeError("Monthly quota used up; it resets on the 1st (UTC).")
            time.sleep(float(r.headers.get("Retry-After", 2)))
            continue
        r.raise_for_status()
        return r.json()
    raise RuntimeError(f"Gave up on {path}")

How do I find the id of a stock?

Call /v1/equities/search?q=IBM&country=USA. Each result holds an id such as XNYS:IBM for prices and bars, and a company_id such as usa:0000051143 for financials.

Can I keep Alpha Vantage for the rest?

Yes. Each provider keeps its own key and quota, so move the families in the table and leave indicators, options and sentiment where they are. Narwhal compared with Alpha Vantage lists the other differences.

Migration checklist

  • List every function your code calls and mark it against the table.
  • Resolve stock symbols to listing ids once, and store the ids.
  • Move the key to the Bearer header and strip it from logged URLs.
  • Rewrite parsers for plain names, oldest-first arrays and string numbers.
  • Replace checks for Information with checks on status and code.
  • Confirm the definition of GDP and the federal funds rate before comparing numbers.
  • Retry on Retry-After and stop on quota_exhausted.
  • Run both providers side by side and compare values before you switch.

Published .

Next steps