Bank Indonesia (BI_RATE) Rate Today

Bank Indonesia (BI_RATE) Rate Today

You need the Bank Indonesia policy rate (BI_RATE) inside your software, reliably, with clear effective dates and enough history to compute spreads, loan costs, and dashboards. By the end of this guide, you’ll fetch the live BI_RATE, compare it with prior periods, calculate a spread or monthly payment from the returned value, and wire it into a React widget—using only GET requests to the Interest Rates API.

What the BI_RATE represents and how to read it in the API

BI_RATE is the Bank Indonesia (BI) policy rate. In the Interest Rates API, it is a central bank benchmark associated with Indonesia and denominated in IDR. The BI_RATE is published on a monthly cadence, with updates reflecting central bank decisions and effective policy stances.

Illustration: Bank Indonesia (BI_RATE) Rate Today

In responses, BI_RATE values are expressed in percent per annum (for example, 5.75). The effective date tells you the last business day or the date the rate is considered valid as of. For monthly symbols, when you query a specific date, the API uses the last available day within that month if the exact date has no value.

  • Symbol: BI_RATE
  • Category: central bank
  • Currency code in responses: IDR (unless you request different symbols that yield MIXED)
  • Frequency: monthly (policy-driven, but accessible through endpoints that return daily-indexed series as needed for charts)

For authoritative API details, see the MCP page: MCP. To start building, you can also visit the homepage: Explore Interest Rates API features.

Fetch the latest BI_RATE

Use the /latest endpoint to retrieve the current BI_RATE. All requests are GET and authenticated with an api_key query parameter.

cURL (official sample)

curl -s "https://interestratesapi.com/api/v1/latest?api_key=YOUR_API_KEY&symbols=BI_RATE"

Official JSON response (fields and values)

{
    "success": true,
    "date": "2026-09-30",
    "base": "IDR",
    "rates": {
        "BI_RATE": 5.75
    },
    "dates": {
        "BI_RATE": "2026-09-30"
    },
    "currencies": {
        "BI_RATE": "IDR"
    },
    "base_filter_note": null
}

How to read this:

  • success: true indicates a valid response.
  • date: "2026-09-30" is the batch date of the response.
  • rates.BI_RATE: 5.75 means the BI policy rate is 5.75% per annum.
  • dates.BI_RATE: "2026-09-30" is the effective date for the rate value.
  • currencies.BI_RATE: "IDR" is the currency context for BI_RATE.

Python (requests)

import requests

resp = requests.get(
'https://interestratesapi.com/api/v1/latest',
params=dict(symbols='BI_RATE', api_key='YOUR_API_KEY')
)
data = resp.json()

rate = data['rates']['BI_RATE']
effective_date = data['dates']['BI_RATE']
currency = data['currencies']['BI_RATE']

print(f"BI_RATE {rate}% (effective {effective_date}, currency {currency})")

JavaScript (fetch)

async function fetchLatestBIRate() {
const url = 'https://interestratesapi.com/api/v1/latest?symbols=BI_RATE&api_key=YOUR_API_KEY';
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();

const rate = data.rates.BI_RATE;
const effectiveDate = data.dates.BI_RATE;
const currency = data.currencies.BI_RATE;

console.log(`BI_RATE ${rate}% (effective ${effectiveDate}, currency ${currency})`);
}

fetchLatestBIRate().catch(console.error);

PHP (cURL)

<?php
$url = 'https://interestratesapi.com/api/v1/latest?symbols=BI_RATE&api_key=YOUR_API_KEY';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10
]);
$body = curl_exec($ch);
if ($body === false) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);

$data = json_decode($body, true);
$rate = $data['rates']['BI_RATE'];
$effectiveDate = $data['dates']['BI_RATE'];
$currency = $data['currencies']['BI_RATE'];

echo "BI_RATE {$rate}% (effective {$effectiveDate}, currency {$currency})";
?>

Want to try it live? Try Interest Rates API. If you need an API key, you can Register.

Contrast today with 1 month ago and 1 year ago

The /historical endpoint returns the BI_RATE on a specified date. For monthly symbols, if the exact day lacks a datapoint, the API uses the last available day within that month. This is ideal for fixed lookbacks like “1 month ago” or “1 year ago”.

cURL

JSON example

Notes:

  • date: the query date you asked for (the API fills the last day with data in that month if needed).
  • rates.BI_RATE: the percent value for that period.
  • currencies: context for the symbol in this response example (as illustrated in the API documentation).

Python (requests) for 1M and 1Y comparisons

from datetime import date, timedelta

import requests

def fetch_historical(d):
resp = requests.get(
'https://interestratesapi.com/api/v1/historical',
params=dict(date=d, symbols='BI_RATE', api_key='YOUR_API_KEY')
)
resp.raise_for_status()
return resp.json()

today = date.today()
one_month_ago = (today.replace(day=15) - timedelta(days=30)).strftime('%Y-%m-%d')
one_year_ago = today.replace(year=today.year - 1).strftime('%Y-%m-%d')

h1m = fetch_historical(one_month_ago)
h1y = fetch_historical(one_year_ago)

print('1M-ago BI_RATE:', h1m['rates'].get('BI_RATE'), 'effective month of', h1m['date'])
print('1Y-ago BI_RATE:', h1y['rates'].get('BI_RATE'), 'effective month of', h1y['date'])

JavaScript (fetch) for 1M and 1Y comparisons

async function historicalCompare(isoDate) {
const url = `https://interestratesapi.com/api/v1/historical?date=${isoDate}&symbols=BI_RATE&api_key=YOUR_API_KEY`;
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data;
}

PHP (cURL)

<?php
function fetch_historical($isoDate) {
$url = "https://interestratesapi.com/api/v1/historical?date={$isoDate}&symbols=BI_RATE&api_key=YOUR_API_KEY";
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10
]);
$body = curl_exec($ch);
if ($body === false) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
return json_decode($body, true);
}
?>

Measure the last 30 days of change with /fluctuation

To summarize recent movement—start and end values, absolute and percent change, and the range—use /fluctuation.

cURL

JSON example

Use this to render a concise “change over period” widget or alerts if the rate breaches a threshold (for example, new 12-month low).

Time series and OHLC for BI_RATE

For charting and backtesting, fetch a continuous series with /timeseries. If you need OHLC aggregates (monthly, weekly, or quarterly), use /ohlc, which the API computes on-the-fly from daily-indexed data.

Time series: cURL

Time series: JSON example

OHLC: cURL

OHLC: JSON example

A minimal React widget to show the live BI_RATE

This snippet fetches the latest BI_RATE, updates every 10 minutes, and handles simple retries and errors. Mount it inside your dashboard to keep users current on Indonesia’s policy stance.

import React, { useEffect, useState } from 'react';

function useLatestBIRate(apiKey) {
const [state, setState] = useState({ rate: null, effectiveDate: null, loading: true, error: null });

useEffect(() => {
let timer;
const fetchNow = async () => {
setState(s => ({ ...s, loading: true, error: null }));
const url = `https://interestratesapi.com/api/v1/latest?symbols=BI_RATE&api_key=${apiKey}`;
try {
const res = await fetch(url, { cache: 'no-store' });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
setState({
rate: data.rates.BI_RATE,
effectiveDate: data.dates.BI_RATE,
loading: false,
error: null
});
} catch (e) {
setState(s => ({ ...s, loading: false, error: e.message || 'Request failed' }));
}
};

fetchNow();
timer = setInterval(fetchNow, 10 * 60 * 1000); // refresh every 10 minutes
return () => clearInterval(timer);
}, [apiKey]);

return state;
}

export default function BIRateCard({ apiKey }) {
const { rate, effectiveDate, loading, error } = useLatestBIRate(apiKey);

if (loading) return <div>Loading BI_RATE…</div>;
if (error) return <div>Failed to load BI_RATE: {error}</div>;

return (
<div style={{ border: '1px solid #ddd', borderRadius: 8, padding: 12 }}>
<div style={{ fontSize: 12, color: '#666' }}>Bank Indonesia Policy Rate</div>
<div style={{ fontSize: 28, fontWeight: 600 }}>{rate}%</div>
<div style={{ fontSize: 12, color: '#666' }}>Effective: {effectiveDate}</div>
</div>
);
}

Computing spreads and monthly payments from BI_RATE

Developers commonly need two quick calculations from the returned BI_RATE:

  1. Rate spread versus another benchmark—for example, comparing BI_RATE to ECB_MRO for treasury allocation or hedging analyses.
  2. Monthly payment estimates for a loan priced off BI_RATE plus a margin.

Spread using the /convert endpoint

The API can compare the simple interest cost for two symbols over a given term. This is a practical way to obtain a spread and interest difference without building the arithmetic yourself.

Use difference.rate_spread for dashboard badges like “BI_RATE vs ECB_MRO: +0.83 pp” and the interest_saved output for side-by-side loan scenarios.

Monthly payment from the returned rate

Given principal P, annual nominal rate r (percent) from rates.BI_RATE, and term n months, the standard fixed-payment formula is:

  • i = (r / 100) / 12
  • payment = P × (i × (1 + i)^n) / ((1 + i)^n − 1)

Implementation detail: if you price loans at BI_RATE plus a margin m (in percentage points), compute r_eff = r + m before deriving i. Do not round intermediate values prematurely; round the final payment to cents as needed. If you need only a rough estimate for a short-term, interest-only structure, you can compute P × (r / 100) / 12 per month.

Publication cadence, business days, and caching

Publication frequency: BI_RATE is monthly in the API. Central bank decisions may not occur on the same calendar day each month, but the returned dates field gives the effective date you should display or store.

Business days and gaps: If you query a specific date with /historical and there is no exact datapoint for that day, the API uses the last day with data in that month for monthly symbols. This lets you compare across months without micromanaging calendars.

Caching strategy:

  • Latest reads: For policy rates that change infrequently, cache responses for minutes to hours depending on your latency needs. Dashboards often refresh every 5–15 minutes.
  • Historical/time series: Cache aggressively (hours to days) as past values do not change.
  • Use ETag or application-level memoization where appropriate; respect 429 responses with Retry-After for backoff.

Error handling and rate limits: On authentication or quota issues, the API returns standard error JSON with success=false, plus HTTP 401/403/429 and helpful headers like X-RateLimit-Remaining and X-RateLimit-Reset. Always check HTTP status and success before consuming fields.

You can explore endpoints and parameters at Get started with Interest Rates API.

Why developers track BI_RATE daily

Even though BI_RATE is monthly, trading desks, treasury functions, and lenders monitor it continuously because changes or guidance can affect IDR funding costs, cross-currency spreads, and mortgage repricing pipelines. A single policy shift can reprice forward curves and credit products priced off the policy rate plus a margin.

  • Funding costs: Corporate treasuries watch BI_RATE against interbank benchmarks to plan issuance windows.
  • Loan pricing: Lenders update variable-rate products or new-offer APRs immediately after policy changes.
  • Risk: Analysts track drawdowns and highs via /fluctuation to detect regime shifts.

Centralize these signals via one REST integration and avoid stitching together disparate data sources. Try Interest Rates API.

Bonus: Discover rate symbols programmatically

If you’re dynamically building rate pickers or validating symbols, use /symbols to browse available identifiers and filter by category or currency.

Use this endpoint to keep your UI synchronized with the latest catalogue without hard-coding symbol lists.

Integration checklist for production

  • Authentication: append api_key=YOUR_API_KEY to all GET requests.
  • Resilience: implement retries with jitter on 5xx and exponential backoff on 429 (respect Retry-After).
  • Validation: check success and required fields (rates, dates, currencies) before using values.
  • Caching: align TTLs to the BI_RATE cadence; purge caches on decision days.
  • Observability: log X-RateLimit-* headers and instrument error rates by endpoint (latest, historical, fluctuation).
  • Data hygiene: treat rates as percentages; for loan math, convert to decimal per month as needed.

FAQ

Q: What unit is BI_RATE in?
A: Percent per annum. For loan math, convert to a monthly decimal: i = (rate / 100) / 12.

Q: Which date should I display to users?
A: Use dates.BI_RATE from /latest or /historical. For monthly symbols, the API uses the last day with data in that month when a specific date has no value.

Q: How often should I refresh BI_RATE?
A: BI_RATE changes infrequently (monthly), but dashboards commonly refresh every 5–15 minutes to reflect any updates and maintain consistency with other live data.

Q: How do I compute a spread versus another rate?
A: Either subtract two latest values after fetching both with /latest, or use /convert to obtain difference.rate_spread and interest_saved for a given amount and term.

Q: What errors should I handle?
A: Expect 401/403 for auth/plan issues, 404 for missing symbols or ranges, 422 for invalid parameters, and 429 for limits. Parse success=false and the error message; observe Retry-After and X-RateLimit-* headers.

Build your BI_RATE integration now: Register, consult the MCP, and start testing endpoints on Explore Interest Rates API features.

Ready to get started?

Get your API key and start validating bank data in minutes.

Get API Key

Related posts