Government — entry 001 of 90
Bank Negara Malaysia Open Data
Bank Negara Malaysia's OpenAPI developer portal catalogues dozens of free, key-free JSON APIs — exchange rates, interest and lending rates, government securities, and monetary statistics — confirmed live with an anonymous call returning real exchange-rate data with no signup. The documentation site runs on a separate host from the live API itself (api.bnm.gov.my), and its CORS header is allow-listed to BNM's own portal domain rather than reflecting arbitrary origins, so third-party web apps on other domains will be blocked by the browser.
Bank Negara Malaysia's Open API platform serves dozens of free, keyless JSON endpoints — exchange rates, gold-coin (Kijang Emas) prices, and bank base rates — from api.bnm.gov.my/public, a separate host from the documentation portal at apikijangportal.bnm.gov.my. A live GET this run against /exchange-rate with Accept: application/vnd.BNM.API.v1+json returned a genuine 200, 4,205 B array of 27 currency rates, content-type: application/json, with access-control-allow-credentials: true but no access-control-allow-origin for a third-party Origin — browser code needs a server-side proxy.
GreatAPIs Score
Auth quickstart
- No API key, signup, or credit card required — but every route needs an explicit version header or it 404s instead of serving JSON. A live GET this run against
/exchange-ratewith noAcceptheader at all returned HTTP 404 withcontent-type: text/html; charset=UTF-8(2,491 B) — the portal's own HTML page, not a JSON error. SendingAccept: application/vnd.BNM.API.v1+jsonon the same URL returns real data; sending an unsupported version instead (Accept: application/vnd.BNM.API.v9+json) still 404s, but as 21 B of real JSON:{"message": ""}.
Your key is stored only in this browser (localStorage) and sent directly to the API — never to greatapis.
Fetch the latest exchange rates
GEThttps://api.bnm.gov.my/public/exchange-rate
{
"data": [
{
"currency_code": "CHF",
"unit": 1,
"rate": {
"date": "2026-07-31",
"buying_rate": 5.0576999999999996,
"selling_rate": 5.0656999999999996,
"middle_rate": 5.0617000000000001
}
},
{
"currency_code": "USD",
"unit": 1,
"rate": {
"date": "2026-07-31",
"buying_rate": 4.0780000000000003,
"selling_rate": 4.0839999999999996,
"middle_rate": 4.0810000000000004
}
}
],
"meta": {
"quote": "rm",
"session": "1700",
"last_updated": "2026-07-31 23:01:41",
"total_result": 27
}
}A live GET this run against /kijang-emas (Malaysia's official gold bullion coin) returned 200, 230 B: {"data":{"effective_date":"2026-07-31","one_oz":{"buying":17038,"selling":17758},"half_oz":{...},"quarter_oz":{...}},"meta":{...}}. /base-rate returned 200, 5,952 B of per-bank lending benchmark rates for every licensed bank in Malaysia.
Try it
Developer reference
https://api.bnm.gov.my/public- GET/exchange-rate
- GET/kijang-emas
- GET/base-rate
Gotchas & limits
- An unrecognised API version in the
Acceptheader is a different failure from a missing header entirely — confirmed live above: no header at all is a 404 HTML page (2,491 B), whileAccept: application/vnd.BNM.API.v9+jsonis a 404 in real JSON ({"message": ""}, 21 B). Code that checkscontent-typeto decide whether a 404 is "real" will misclassify the header-version case. - A malformed path (confirmed live this run with a
../../traversal segment appended to/exchange-rate) returns HTTP 200, not an error status, withcontent-type: text/html— an F5-style WAF interstitial titled "Request Rejected" carrying a numeric "support ID" rather than any BNM API data. A 200 status here does not mean the requested data came back; response bodies must be sniffed forcontent-type: application/jsonbefore parsing. - Rate figures carry raw IEEE-754 double noise instead of clean decimals — confirmed live above: CHF's
buying_rateis literally5.0576999999999996, and/base-rate's figures show the same pattern. Code that string-compares or directly displays these numbers without rounding will show visibly wrong digits to users. - Only
access-control-allow-credentials: trueis sent on every response — confirmed live this run with an explicitOrigin: https://greatapis.comheader on/exchange-rate— there's noaccess-control-allow-originof any kind, not even a same-origin echo. Direct browserfetch()calls from any third-party site are blocked by the browser even though the server itself answers fine; a server-side proxy is required.