Read each central bank's current policy rate and its change history from the economics endpoints, then add the market-implied path from the predictions API. The rate says where policy stands today. The path gives the odds of a cut, hold or hike at each meeting ahead.
Read the current policy rate
GET /v1/economics/{country}/central-bank/policy-rate returns the rate now in force for a country. This request asks for the United States.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/economics/USA/central-bank/policy-rate"{
"country": "USA",
"authority": "federal_reserve",
"currency": "USD",
"instrument": "federal_funds_target_range",
"unit": "percent",
"effective_on": "2026-09-17",
"observed_on": null,
"announced_on": null,
"rate_type": "range",
"lower_bound": "3.75",
"upper_bound": "4.00"
}The Federal Reserve sets a target range, so rate_type is range and the response has lower_bound 3.75 and upper_bound 4.00 in percent. The range took effect on effective_on 2026-09-17. A bank that sets a single rate has rate_type point and one rate field instead of the two bounds.
| Country | instrument | Rate | Date field |
|---|---|---|---|
| USA | federal_funds_target_range | 3.75 to 4.00 | effective_on 2026-09-17 |
| GBR | bank_rate | 3.75 | effective_on 2025-12-18 |
| JPN | overnight_call_rate_target | 1.25 | observed_on 2026-10-27 |
See how the rate got there
Add /history to read the series of rate observations. The start parameter sets the first date, and limit and cursor page through long histories. This request starts in September 2025.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/economics/USA/central-bank/policy-rate/history?start=2025-09-01"{
"country": "USA",
"observations": [
{
"country": "USA",
"authority": "federal_reserve",
"currency": "USD",
"instrument": "federal_funds_target_range",
"unit": "percent",
"effective_on": "2025-09-18",
"observed_on": null,
"announced_on": null,
"rate_type": "range",
"lower_bound": "4.00",
"upper_bound": "4.25"
},
{
"country": "USA",
"authority": "federal_reserve",
"currency": "USD",
"instrument": "federal_funds_target_range",
"unit": "percent",
"effective_on": "2025-10-30",
"observed_on": null,
"announced_on": null,
"rate_type": "range",
"lower_bound": "3.75",
"upper_bound": "4.00"
}
],
"next_cursor": null
}The full response has four rows, oldest first, and the block shows two. Subtracting each upper bound from the one before gives the moves: -25 basis points on 2025-10-30, -25 on 2025-12-11 and +25 on 2026-09-17. The script below does that subtraction with Decimal so no floating point error enters a rate. For a long history, pass end as well, or follow next_cursor until it is null.
Read the market-implied path
GET /v1/predictions/policy-paths/federal-reserve returns the odds for each coming meeting. The path holds changes only and never the current rate, so read the rate from the endpoint above.
curl -s -H "Authorization: Bearer $NARWHAL_API_KEY" \
"https://api.narwhalapi.com/v1/predictions/policy-paths/federal-reserve"{
"as_of": "2026-11-03T02:34:00Z",
"meetings": [
{
"event_id": "usa-fed-2026-12",
"p_cut": "0.0096",
"p_hold": "0.2533",
"p_hike": "0.7371",
"expected_change_bps": "18.6",
"cumulative_change_bps": "18.6",
"resolves_at": "2026-12-09T19:00:00Z"
},
{
"event_id": "usa-fed-2027-01",
"p_cut": "0.0280",
"p_hold": "0.7055",
"p_hike": "0.2665",
"expected_change_bps": "6.0",
"cumulative_change_bps": "24.6",
"resolves_at": "2027-01-27T19:00:00Z"
}
]
}as_of dates the odds. For each meeting, resolves_at is the decision time and p_cut, p_hold and p_hike are probabilities that sum to 1. The first meeting has a hike probability of 73.7 percent and an expected_change_bps of 18.6. cumulative_change_bps adds the meetings up: 18.6 plus 6.0 gives 24.6 after the second meeting.
Change the authority in the path for other banks, for example bank-of-japan. A response with an empty meetings list means no meetings are listed for that authority, which was the case for bank-of-england when this page was written.
Compare three banks in one table
A watch list needs the same columns for every bank. Take the rate from the rate endpoint and the first meeting from the path for the bank's authority name: federal-reserve, bank-of-england or bank-of-japan.
| Country | Authority | Rate now | First meeting in the path | Hike odds |
|---|---|---|---|---|
| USA | federal-reserve | 3.75 to 4.00 | 2026-12-09 | 73.7 percent |
| GBR | bank-of-england | 3.75 | None listed | Not available |
| JPN | bank-of-japan | 1.25 | 2026-12-18 | 83.6 percent |
The United Kingdom row stays empty because its path had no meetings when this page was written, while its rate is still current. Keep a row for such a bank in your table anyway. Showing the rate with a blank path is more useful than dropping the bank. Re-read each path before you rely on it, because as_of moves as the odds are updated.
Put the rate and the path in one script
- Get an API key Get an API key at signup and keep it in
NARWHAL_API_KEY. - Read the rate for each country The script prints the instrument, the rate and the date. It uses
effective_onand falls back toobserved_onwheneffective_onis null. - Compute the moves and the odds Differences between consecutive upper bounds give the moves in basis points, and the first two meetings print their hike and hold odds as percentages.
import os from decimal import Decimal import requests BASE = "https://api.narwhalapi.com" HEADERS = {"Authorization": f"Bearer {os.environ['NARWHAL_API_KEY']}"} def get(path, **params): r = requests.get(f"{BASE}{path}", headers=HEADERS, params=params, timeout=10) r.raise_for_status() return r.json() def text(o): if o["rate_type"] == "range": return f"{o['lower_bound']} to {o['upper_bound']}" return o["rate"] def top(o): return Decimal(o["upper_bound"] if o["rate_type"] == "range" else o["rate"]) for country in ("USA", "GBR", "JPN"): o = get(f"/v1/economics/{country}/central-bank/policy-rate") print(country, o["instrument"], text(o), "since", o["effective_on"] or o["observed_on"]) rows = get("/v1/economics/USA/central-bank/policy-rate/history", start="2025-09-01")["observations"] for before, now in zip(rows, rows[1:]): print(now["effective_on"], int((top(now) - top(before)) * 100), "bp") for m in get("/v1/predictions/policy-paths/federal-reserve")["meetings"][:2]: print(m["resolves_at"][:10], "hike", f"{Decimal(m['p_hike']) * 100:.1f}%", "hold", f"{Decimal(m['p_hold']) * 100:.1f}%", "expected", m["expected_change_bps"], "bp")
USA federal_funds_target_range 3.75 to 4.00 since 2026-09-17
GBR bank_rate 3.75 since 2025-12-18
JPN overnight_call_rate_target 1.25 since 2026-10-27
2025-10-30 -25 bp
2025-12-11 -25 bp
2026-09-17 25 bp
2026-12-09 hike 73.7% hold 25.3% expected 18.6 bp
2027-01-27 hike 26.6% hold 70.6% expected 6.0 bpWhich date shows when a rate changed?
Use effective_on when it has a value, and observed_on otherwise. The United States and the United Kingdom returned effective_on. Japan returned observed_on with effective_on set to null. announced_on was null in all three responses.
Can I read the rate on a past date?
Yes. Pass date to the policy rate endpoint. A request with date=2025-11-15 for the United States returned the 3.75 to 4.00 range with effective_on 2025-10-30, the date that range began.
Does the path contain the current rate?
No. It carries odds and expected moves in basis points for each meeting, so add the move to the rate you read from the policy rate endpoint. Divide basis points by 100 to get percentage points: 18.6 basis points for the first meeting is 0.186 percentage points.
That is a probability-weighted average across cut, hold and hike outcomes, so it is a blend of outcomes and not the size of any move the bank will announce.
Published .