Ask ChatGPT about this API API Playground — try it live
IBR Live Forex API

IBR Live Forex API

Real-time and historical forex data over REST and WebSocket. One API key, passed as a query parameter, unlocks everything your plan allows — no OAuth, no signing, no header gymnastics.

Base URLhttps://api.ibrlive.com
WebSocketwss://api.ibrlive.com
Auth?apiKey=YOUR_API_KEY on every request (WebSocket also accepts api_key)

01Quick Start

1. Get a key. Sign up and grab your API key from Dashboard → API Settings.

2. Make a request. Append apiKey=YOUR_API_KEY to any endpoint:

bash
curl -X GET "https://api.ibrlive.com/api/forex/snapshot/USDINR?apiKey=YOUR_API_KEY"
json — response
{
  "success": true,
  "requested_symbols": ["USDINR"],
  "lastQuotes": [
    { "s": "USDINR", "a": 83.58, "b": 83.56, "t": 1704123456789 }
  ],
  "source": "redis_cache",
  "timestamp": "2024-01-15T18:30:00Z"
}

3. Check success. Every response — success or failure — is JSON with a top-level success boolean. See §6 Error Handling for the failure shape.

That's the whole integration loop. Everything below fills in the details: which endpoints exist, what each one needs, and what plan unlocks it.

02Authentication

MethodAPI key as a query parameter: ?apiKey=YOUR_API_KEY
Required onEvery endpoint, REST and WebSocket, no exceptions
Where to find itDashboard → API Settings
TransportQuery string only — there is no header-based alternative
javascript
// fetch
fetch(`https://api.ibrlive.com/api/forex/snapshot/USDINR?apiKey=${apiKey}`)
  .then(r => r.json())
  .then(console.log);

// axios
const { data } = await axios.get('https://api.ibrlive.com/api/forex/snapshot/USDINR', {
  params: { apiKey }
});
⚠️
Security. Because the key lives in the URL, never call the API directly from frontend/client-side code — it will leak in browser history, logs, and network panels. Route requests through your own backend and keep the key in an environment variable there.

03Endpoints

All REST endpoints share the base URL https://api.ibrlive.com. "Min. plan" is the lowest plan that unlocks the endpoint — anything higher also has access.

#EndpointMethodMin. planUpdate frequency
1Forex Snapshot (Live Rate API)GETFREEReal-time (Pro/Ultimate); periodic (Essential)
2Snapshot WebSocketWSPROInit + delta stream, ~3s
3Currency ConversionGETBASICReal-time / ~60s, plan-dependent
4Forex AggregatesGETBASICDaily, midnight IST
5Technical IndicatorsGETULTIMATEEvery 3s
6Previous CloseGETBASICEvery 3s
7Indian Customs Reference RatesGETESSENTIALMon–Fri 6:40 PM IST
8RBI Reference Rates (Latest)GETESSENTIALOn RBI publish
9DXY Index (Last Value)GETESSENTIAL~Every 3s
10RBI Reference Rates (Historical)GETBASICStatic — date range, up to 5 years
11Forward Rate (Broken Date)GETPRO add-onOn-demand (broken-date calc)
12Monthly Forward RatesGETPRO add-onOn-demand (1M–12M ladder)
13Cash / Tom / SpotGETPRO add-onOn-demand (1M-derived points)
📌
#10 RBI Historical is Basic+ (like Aggregates / Previous Close). Live reference feeds — Indian Customs, RBI Latest, and DXY — remain Essential+.

3.1Forex Snapshot (Live Rate API)

GETFREE+

Live bid/ask quotes and last trades. Three URL shapes depending on whether you want all pairs, one pair, or a specific list.

VariantURLMin. planCall cost
All pairsGET /api/forex/snapshot?apiKey=...FREEceil(total pairs ÷ 5), min 1
Single pairGET /api/forex/snapshot/{symbol}?apiKey=...FREE1
Multiple pairs (batch)GET /api/forex/snapshot/symbols?symbols=A,B,C&apiKey=...FREE1 call per pair requested
All-pairs Snapshot
ceil(total pairs ÷ 5)

You pay for the batch, not the count. ~150 live pairs → 30 calls per request, regardless of which pairs you actually need.

Batch / Multi-symbol
1 call × pairs requested

You pay for the count, not the batch. Request 7 pairs in one URL → 7 calls deducted. No discount for batching.

⚠️
Correction — batch billing works differently from all-pairs billing. The multi-symbol/batch endpoint does not use the ceil(pairs ÷ 5) formula that the all-pairs endpoint uses. Batch is billed 1 call per pair, full stop — request 7 pairs in one URL, that's 7 calls deducted, not ceil(7 ÷ 5) = 2. Conflating the two cost models is the easiest way to misforecast usage.
💡
What this costs Free-plan users. Free accounts can call all three Snapshot variants (all-pairs, single-symbol, and batch/multi-symbol). With ~150 pairs currently live, one all-pairs Snapshot call costs ceil(150 ÷ 5) = 30 calls deducted from the 100/month Free allowance — so a Free key supports roughly 3 all-pairs calls per month, or many more single/batch calls (1 call each). Free is free forever, not a one-time trial. See §4.5 for the full Free-plan onboarding guide.

Path Parameter

NameTypeDescription
symbolstringSingle pair, e.g. USDINR (single-pair variant only)

Query Parameters

NameRequiredDescription
apiKey✅Your API key
symbolsMulti-symbol onlyComma-separated pairs, e.g. USDINR,EURUSD,GBPINR
bash
# All pairs — Free and above
curl "https://api.ibrlive.com/api/forex/snapshot?apiKey=YOUR_API_KEY"

# Single pair — Free and above
curl "https://api.ibrlive.com/api/forex/snapshot/USDINR?apiKey=YOUR_API_KEY"

# Multiple pairs / batch — Free and above
curl "https://api.ibrlive.com/api/forex/snapshot/symbols?symbols=USDINR,EURUSD,GBPINR&apiKey=YOUR_API_KEY"
json — response (all-pairs or multi-symbol)
"success": true,
  "user": "[email protected]",
  "lastQuotes": [
    { "s": "USDINR", "a": 83.58, "b": 83.56, "t": 1704123456789, "t_ist": "2024-01-15T18:30:00+05:30" },
    { "s": "EURUSD", "a": 1.0852, "b": 1.0850, "t": 1704123456789, "t_ist": "2024-01-15T18:30:00+05:30" }
  ],
  "lastTrades": [
    { "s": "USDINR", "p": 83.57, "t": 1704123456789, "t_ist": "2024-01-15T18:30:00+05:30" }
  ]
}

Response fields: a = ask, b = bid, p = last trade price, t = Unix ms timestamp (IBR response time, not upstream feed time), t_ist = same time in IST, s = symbol. The single-pair variant returns quote and trade objects instead of lastQuotes/lastTrades arrays. Multi-symbol errors may include requested_symbols and not_found_symbols in the JSON body.

3.2Snapshot WebSocket (Live Stream)

WSPRO & ULTIMATE

Streams snapshot updates instead of polling REST — connect once, get an init snapshot, then automatic delta pushes (~3s refresh) for as long as the socket stays open. Deltas contain only pairs whose quote/trade values changed; if nothing changed, no message is sent and no tokens are deducted.

Connection limits: Pro — up to 2 concurrent connections per account. Ultimate — up to 5.

Connection URLs

wss
# All pairs
wss://api.ibrlive.com/api/forex/ws/snapshot?api_key={apiKey}

# Filtered on connect
wss://api.ibrlive.com/api/forex/ws/snapshot?api_key={apiKey}&symbols=USDINR,EURUSD,GBPINR
ParamRequiredNotes
api_key✅Also accepts apiKey
symbolsoptionalComma-separated filter applied at connect; omit for all pairs. Changeable later via subscribe.

Call Usage

All-pairs stream
ceil(pairs ÷ 5)

Init: full snapshot — e.g. ~207 pairs → 42 tokens.
Delta: only changed pairs — e.g. 22 changed → 5 tokens.
connected, subscribed, pong are free.

Filtered symbols (e.g. EURUSD, GBPUSD)
1 token × pairs

Init: 1 token per subscribed pair — 2 pairs → 2 tokens.
Delta: 1 token per changed pair — 1 pair moves → 1 token.
Same per-pair logic as REST batch/multi-symbol (§3.1).

  • Each billed push includes request_units_deducted, pairs_in_push, and billing_mode (all_pairs_ceil5 or filtered_per_pair_delta).
  • Changing filters via subscribe sends a new init and bills again for the new pair count.

Client → Server Messages

ActionPayloadEffect
subscribe{"action":"subscribe","symbols":["USDINR","EURUSD"]}Switch to filtered pairs
subscribe{"action":"subscribe"}Switch to all pairs (no symbols / empty array)
ping{"action":"ping"}Keep-alive / latency check — server replies pong

Server → Client Message Types

javascript
// 1. connected — immediately after successful auth (free)
{ "type": "connected", "plan": "PRO", "max_connections": 2,
  "active_connections": 1, "symbols": "all",
  "message": "Send {\"action\":\"subscribe\",\"symbols\":[\"EURUSD\"]} to filter..." }

// 2. init — full snapshot on connect or after subscribe (billed)
{ "type": "init", "success": true, "totalResults": 207,
  "lastQuotes": [{ "s": "USDINR", "a": 83.58, "b": 83.56, "t": 1704123456789, "t_ist": "2024-01-15T18:30:00+05:30" }],
  "lastTrades": [{ "s": "USDINR", "p": 83.57, "t": 1704123456789, "t_ist": "2024-01-15T18:30:00+05:30" }],
  "removedSymbols": [], "timestamp": "2024-01-15T18:30:00Z", "lastUpdate": 1704123456789,
  "source": "finage_snapshot", "request_units_deducted": 42, "pairs_in_push": 207,
  "billing_mode": "all_pairs_ceil5", "filtered_symbols": null }

// 3. delta — only changed pairs on each ~3s tick (billed; skipped if nothing changed)
{ "type": "delta", "success": true, "totalResults": 207,
  "lastQuotes": [{ "s": "EURUSD", "a": 1.0852, "b": 1.0850, "t": 1704123456790, "t_ist": "2024-01-15T18:30:01+05:30" }],
  "lastTrades": [], "removedSymbols": [], "changed_pairs": 1,
  "timestamp": "2024-01-15T18:30:01Z", "lastUpdate": 1704123456790,
  "source": "finage_snapshot", "request_units_deducted": 1, "pairs_in_push": 1,
  "billing_mode": "filtered_per_pair_delta", "filtered_symbols": ["EURUSD", "GBPUSD"] }

// 4. subscribed — confirms a filter change (free; followed by init)
{ "type": "subscribed", "symbols": ["USDINR", "EURUSD"],
  "message": "Receiving updates for selected symbols only" }

// 5. pong — reply to ping (free)
{ "type": "pong", "ts": 1704123456789 }

// 6. error — auth, plan, or limit failures
{ "type": "error", "error": "WebSocket snapshot is only available on Pro and Ultimate plans",
  "current_plan": "ESSENTIAL", "required_plans": ["PRO", "ULTIMATE"] }

Client Example

javascript
const apiKey = "YOUR_API_KEY";
const ws = new WebSocket(`wss://api.ibrlive.com/api/forex/ws/snapshot?api_key=${apiKey}`);

ws.onopen = () => console.log("WebSocket connected");

ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);
  switch (msg.type) {
    case "init":
    case "delta":
      console.log(msg.type, "pairs:", msg.pairs_in_push, "tokens:", msg.request_units_deducted);
      console.log("Quotes:", msg.lastQuotes);
      break;
    case "connected":
      console.log("Plan:", msg.plan, "Max connections:", msg.max_connections);
      break;
    case "error":
      console.error(msg.error, msg.details);
      break;
  }
};

ws.send(JSON.stringify({ action: "subscribe", symbols: ["USDINR", "EURUSD"] }));
ws.send(JSON.stringify({ action: "subscribe" }));

ws.onerror = (err) => console.error("WebSocket error", err);
ws.onclose = (e) => console.log("Closed", e.code, e.reason);
💡
If you only need periodic snapshots, REST polling is usually cheaper and simpler than holding a socket open — especially for all pairs, where each init/delta uses ceil(pairs ÷ 5). Filtered WebSocket (1 token per pair) is often competitive with REST batch for a small symbol list, and delta-only pushes avoid charging when prices are unchanged.

3.3Currency Conversion

GETBASIC+1 call per request

Converts an amount between two currencies using cached snapshot bid/ask mid rates. Cross-rates resolve via direct pair, inverse pair, or a USD cross when no direct pair exists. Rate freshness follows your plan's cache tier: Basic/Essential use ~60-second snapshot data; Pro/Ultimate use real-time data.

url schema
GET https://api.ibrlive.com/api/forex/convert?from={from}&to={to}&amount={amount}&apiKey={apiKey}
ParamRequiredDescription
from✅Source currency, 3-letter ISO code, e.g. USD
to✅Target currency, 3-letter ISO code, e.g. INR
amount✅Amount in source currency
apiKey✅Your API key
bash
curl "https://api.ibrlive.com/api/forex/convert?from=USD&to=INR&amount=100&apiKey=YOUR_API_KEY"
json — response
{
  "success": true,
  "from": "USD",
  "to": "INR",
  "amount": 100,
  "rate": 83.57,
  "converted_amount": 8357,
  "user": "[email protected]"
}

3.4Forex Aggregates

GETBASIC+

Historical OHLCV bars. Bar size is controlled by time + multiply; range by from/to. Server caps results at 10,000 records per request for performance.

url schema
GET https://api.ibrlive.com/api/aggregate/data?symbol={symbol}&time={time}&multiply={multiply}&from={from}&to={to}&apiKey={apiKey}
ParamRequiredDescription
symbol✅Forex pair, e.g. USDINR
time✅Bar size: day, month, quarter, year
multiplyoptionalPositive multiplier on time. Default 1
from✅Start date, YYYY-MM-DD
to✅End date, YYYY-MM-DD
apiKey✅Your API key
bash
curl "https://api.ibrlive.com/api/aggregate/data?symbol=USDINR&time=day&multiply=1&from=2020-01-01&to=2026-04-30&apiKey=YOUR_API_KEY"
json — response
{
  "success": true,
  "symbol": "USDINR",
  "time": "day",
  "multiply": 1,
  "from": "2020-01-01",
  "to": "2026-04-30",
  "limit": 10000,
  "data": {
    "results": [
      { "o": 83.45, "h": 83.67, "l": 83.32, "c": 83.58, "v": 1250000, "t": 1704067200000 }
    ]
  },
  "recordCount": 10000,
  "source": "redis_cache",
  "responseTimeMs": 15,
  "dataAgeSeconds": 3600,
  "lastUpdate": "2024-01-15T18:30:00Z",
  "user": "[email protected]"
}

o/h/l/c = open/high/low/close, v = volume, t = Unix ms timestamp. Data refreshes daily at midnight IST; a manual refetch endpoint exists but should be used sparingly since it's a heavy backend operation and consumes extra calls.

3.5Technical Indicators

GETULTIMATE ONLY

RSI, MACD, SMA/EMA, Bollinger Bands, and Stochastic oscillators, refreshed every 3 seconds.

url schema
GET https://api.ibrlive.com/api/forex/get-technical-indicators?symbol={symbol}&timeframe={timeframe}&apiKey={apiKey}
ParamRequiredDescription
symbol✅Forex pair, e.g. USDINR
timeframeoptionaldaily (default) or weekly
apiKey✅Your API key
python
import requests

def get_technical_indicators(symbol, timeframe='daily', api_key='YOUR_API_KEY'):
    response = requests.get(
        "https://api.ibrlive.com/api/forex/get-technical-indicators",
        params={"symbol": symbol, "timeframe": timeframe, "apiKey": api_key}
    )
    response.raise_for_status()
    data = response.json()
    if not data['success']:
        raise Exception(data['error'])
    return data['data']
json — response
{
  "success": true,
  "data": { /* indicator values from upstream */ },
  "symbol": "USDINR",
  "timeframe": "daily",
  "source": "redis_cache",
  "response_time_ms": 12,
  "data_age_seconds": 2,
  "timestamp": "2024-01-15T18:30:00Z",
  "redis_key": "forex:technical:USDINR:daily",
  "user_info": {
    "email": "[email protected]",
    "subscription_plan": "ULTIMATE",
    "remaining_api_calls": 12999000
  }
}

3.6Previous Close

GETBASIC+

Previous trading day's OHLCV for a pair, updated every 3 seconds and cached.

url schema
GET https://api.ibrlive.com/api/forex/previous-close?symbol={symbol}&apiKey={apiKey}
ParamRequiredDescription
symbol✅Forex pair, e.g. USDINR
apiKey✅Your API key
json — response
{
  "success": true,
  "symbol": "USDINR",
  "data": {
    "open": 83.42,
    "high": 83.68,
    "low": 83.28,
    "close": 83.55,
    "volume": 1180000,
    "timestamp": 1703980800000,
    "date": "2024-01-14T18:30:00Z"
  },
  "source": "redis_cache",
  "response_time_ms": 8,
  "data_age_seconds": 45,
  "timestamp": "2024-01-15T18:30:00Z",
  "user": "[email protected]"
}

3.7Indian Customs Forex Reference Rates

GETESSENTIAL+1 call per request

ICEGATE-aligned customs valuation rates. Rates are refreshed Monday to Friday at 6:40 PM IST. Response has no extra wrapper — just meta and data[], and no top-level success field, unlike every other endpoint in this API.

url schema
GET https://api.ibrlive.com/api/forex/reference-rates/indian-customs?apiKey={apiKey}
json — response
{
  "meta": { "row_count": 22 },
  "data": [
    {
      "Currency Code": "AED",
      "Currency Name": "UAE Dirham",
      "Effective start Date": "2026-04-06",
      "Units of foreign currency equivalent to Indian rupees": "1",
      "Import Rate": "26.1",
      "Export Rate": "24.55"
    }
  ]
}
⚠️
Heads up for client code: because this response omits success, code that does if (!data.success) throw ... (as recommended elsewhere in this doc) will misfire here. Check for data.data / data.meta instead.

3.8RBI Forex Reference Rates (Latest)

GETESSENTIAL+1 call per request

Most recently published RBI reference rate (date plus USD/INR, GBP/INR, EUR/INR, JPY/INR per 100 JPY, AED/INR, and IDR/INR per 10,000 IDR — all returned as strings). Same no-success-field shape as Customs above.

url schema
GET https://api.ibrlive.com/api/forex/reference-rates/rbi-latest?apiKey={apiKey}
json — response
{
  "data": [
    {
      "date": "04/09/2026",
      "USD/INR": "94.4914",
      "GBP/INR": "127.9703",
      "EUR/INR": "109.8822",
      "JPY/INR": "60.5200",
      "AED/INR": "25.7272",
      "IDR/INR": "53.5864"
    }
  ]
}

3.9DXY Index (Last Value)

GETESSENTIAL+

US Dollar Index value against a basket of major currencies. Cached, refreshed roughly every 3 seconds. Minimal response shape — symbol, price, timestamp, timestamp_ist (no top-level success field).

url schema
GET https://api.ibrlive.com/api/last/index/DXY?apiKey={apiKey}
json — response
{
  "symbol": "DXY",
  "price": 99.1852,
  "timestamp": 1774339583085,
  "timestamp_ist": "2026-03-24T12:16:23+05:30"
}

3.10RBI Forex Reference Rates (Historical)

GETBASIC+1 call per request

Up to 5 years of RBI reference rates by date range. Fields: date, USD/INR, GBP/INR, EUR/INR, JPY/INR (per 100 JPY), AED/INR, and IDR/INR (per 10,000 IDR).

url schema
GET https://api.ibrlive.com/api/forex/reference-rates/rbi-historical?from={from}&to={to}&apiKey={apiKey}
ParamRequiredDescription
from✅Start date (inclusive), DD-MM-YYYY or DD/MM/YYYY
to✅End date (inclusive), DD-MM-YYYY or DD/MM/YYYY
apiKey✅Your API key
📌
Note the date format here (DD-MM-YYYY) differs from Forex Aggregates (YYYY-MM-DD) — easy to trip over if you're calling both in the same integration.
json — response
{
  "data": [
    { "date": "15/09/2026", "USD/INR": "95.9253", "GBP/INR": "129.1900", "EUR/INR": "110.5920", "JPY/INR": "61.9400", "AED/INR": "26.1171", "IDR/INR": "54.2010" },
    { "date": "16/09/2026", "USD/INR": "95.9433", "GBP/INR": "129.3204", "EUR/INR": "110.7908", "JPY/INR": "61.8600", "AED/INR": "26.1220", "IDR/INR": "54.2073" }
  ]
}

3.11Forward Rate (Broken Date)

GETPRO add-on1 call per request

Add-on pricing: ₹9,999/mo (INR) or $119/mo (USD) on Pro or Ultimate at checkout — not included by default. Yearly billing adds the add-on to your plan total first, then applies ×12 with 10% discount on the combined amount.

What it is for: Get a forward exchange rate for any custom settlement date (not just fixed monthly tenors) — useful for hedging, invoicing, and broken-date FX pricing on your website or app.

How to use: Call the endpoint with a supported currency pair, the forward settlement date you need, and your apiKey. Optionally pass trade_date if you want to price as of a specific day (defaults to today UTC).

What you get: Spot bid/ask, forward premium bid/ask, final forward rate bid/ask, plus the related settlement dates for that request.

url schema
GET https://api.ibrlive.com/api/forex/forward-rate?pair={pair}&date={date}&apiKey={apiKey}
ParamRequiredDescription
pair✅e.g. USDINR or USD/INR — one of 24 supported pairs
date✅Forward settlement date YYYY-MM-DD
trade_dateoptionalDefaults to today (UTC)
apiKey✅Your API key
bash
curl "https://api.ibrlive.com/api/forex/forward-rate?pair=USDINR&date=2026-08-19&apiKey=YOUR_API_KEY"
json — response (shape)
{
  "pair": "USDINR",
  "display_pair": "USD/INR",
  "trade_date": "2026-06-30",
  "spot_settlement_date": "2026-07-02",
  "forward_start_date": "2026-07-03",
  "target_date": "2026-08-19",
  "max_settlement_date": "2027-07-02",
  "spot": { "bid": 94.657, "ask": 94.66 },
  "premium": { "bid": 0.3666, "ask": 0.3866 },
  "forward": { "bid": 95.0236, "ask": 95.0466 }
}

Supported pairs: GET /api/forex/forward-rate/pairs. Requires Pro or Ultimate with Forward Rate add-on at checkout; Free, Basic, and Essential receive 403.

Supported forward pairs (20):

USDINR USDCNY EURCNY JPYCNY HKDCNY GBPCNY EURUSD USDJPY USDHKD GBPUSD AUDUSD USDCHF USDCAD JPYINR CNYINR GBPINR EURINR AUDINR CADINR CHFINR

3.12Monthly Forward Rates

GETPRO add-on1 call per request

What it is for: Show a full month-by-month forward premium table (1M to 12M) with exporter and importer yields — ideal for forward rate boards, exporter/importer dashboards, and tenor comparison UIs.

How to use: Call the endpoint with a supported currency pair and your apiKey. Optionally pass trade_date (defaults to today UTC). One request returns all 12 monthly tenors.

What you get: A 12-row array. Each row includes tenor, bid_premium, ask_premium, exporter_yield, and importer_yield.

url schema
GET https://api.ibrlive.com/api/forex/forward-rate/monthly?pair={pair}&apiKey={apiKey}
ParamRequiredDescription
pair✅e.g. USDINR or USD/INR — one of 24 supported pairs
trade_dateoptionalDefaults to today (UTC)
apiKey✅Your API key
bash
curl "https://api.ibrlive.com/api/forex/forward-rate/monthly?pair=USDINR&apiKey=YOUR_API_KEY"
json — response (shape)
[
  {
    "tenor": "1M",
    "bid_premium": 24.32,
    "ask_premium": 26.32,
    "exporter_yield": 2.9722,
    "importer_yield": 3.216
  },
  {
    "tenor": "2M",
    "bid_premium": 47.46,
    "ask_premium": 49.46,
    "exporter_yield": 2.85,
    "importer_yield": 3.08
  }
  /* … 3M through 12M */
]

Same 20 pairs as §3.11. Requires Pro or Ultimate with Forward Rate add-on; Free, Basic, and Essential receive 403.

3.13Cash / Tom / Spot

GETPRO add-on1 call per request

What it is for: Get near-term Cash, Tom, and Spot FX values for a currency pair — useful for same-day / next-day settlement screens, treasury tools, and short-dated FX pricing.

How to use: Call the endpoint with a supported currency pair and your apiKey. Optionally pass trade_date (defaults to today UTC).

What you get: Spot rate, Cash premium, Cash rate, Tom premium, and Tom rate — each with bid and ask. Enough to build a treasury Cash/Tom/Spot board.

url schema
GET https://api.ibrlive.com/api/forex/cash-tom-spot?pair={pair}&apiKey={apiKey}
ParamRequiredDescription
pair✅e.g. USDINR or USD/INR — one of 24 supported pairs
trade_dateoptionalDefaults to today (UTC)
apiKey✅Your API key
bash
curl "https://api.ibrlive.com/api/forex/cash-tom-spot?pair=USDINR&apiKey=YOUR_API_KEY"
json — response (shape)
{
  "spot": { "bid": 96.3227, "ask": 96.342 },
  "cash_premium": { "bid": 1.5, "ask": 1.9 },
  "cash": { "bid": 96.3077, "ask": 96.323 },
  "tom_premium": { "bid": 0.3, "ask": 0.5 },
  "tom": { "bid": 96.3197, "ask": 96.337 }
}

Same 20 pairs as §3.11. Requires Pro or Ultimate with Forward Rate add-on; Free, Basic, and Essential receive 403.

Supported Symbols

Snapshot / conversion / aggregates support 3,000+ pairs (separate from the 20 Forward Rate pairs above). Approximately 150 are live in the all-pairs Snapshot at any given time. Commonly used:

USDINR EURINR GBPINR AUDINR CADINR NZDINR AEDINR SGDINR THBINR CNYINR JPYINR CHFINR MYRINR EURUSD GBPUSD USDJPY USDCNY

Data Refresh Rates

Data typeFrequency
Snapshot (REST & WebSocket)~3 seconds
Previous Close~3 seconds
AggregatesDaily at midnight IST
Technical Indicators~3 seconds
Currency Conversion~60s (Basic/Essential) or real-time (Pro/Ultimate)
DXY Index~3 seconds
Indian Customs RatesMon–Fri 6:40 PM IST
RBI Reference (Latest)On RBI publish
RBI Reference (Historical)Static — date-range lookup
Forward RateOn-demand broken-date calculation
Monthly Forward RatesOn-demand 1M–12M ladder
Cash / Tom / SpotOn-demand near-term settlement points

04Plans & Limits

💰
Currency note: base prices are shown in USD. Overage/additional-call pricing is confirmed in both ₹ and $ — see §4.2 for the full table, exchange-rate basis, and USD-specific rounding rules.

4.1Plan Tiers

Free
$0
free forever
100/month
60-second
Basic
$10
per month
35,000/month
60-second
Essential
$35
per month
1,500,000/month
real-time (3s)
Ultimate
$294
per month
15,000,000/month
real-time (3s)
✅
Correction from earlier drafts: Free is free forever, not a one-time trial. An earlier version of the pricing page said "one-time trial" — that wording is being corrected, and this doc now reflects the accurate, ongoing model: 100 calls every month, recurring, for as long as the account exists.

4.2Overage Pricing — Calls Beyond Your Plan's Included Amount

Once a paid plan's included monthly calls are used up, additional calls are billed per-call rather than hard-blocked, up to a recommended maximum. This is new information not previously documented — earlier drafts of this doc assumed a hard monthly cap with no overage option, which was incorrect for paid plans.

PlanIncluded calls/monthPrice (₹)Price ($)Recommended max/month
Basic35,000₹0.00200$0.00002353500,000
Essential1,500,000₹0.00175$0.000020591,500,000
Pro3,500,000₹0.00150$0.0000176510,000,000
Ultimate15,000,000₹0.00125$0.0000147130,000,000
💱
Exchange rate basis: USD figures are calculated at ₹85 / $1 and will change if the reference rate is updated.

How to read this table:

  • Included calls is what your base price covers — once you exceed this in a billing month, you're charged per call at the additional-call rate for every call past that point.
  • Recommended maximum is a guardrail, not a hard technical block. Per-call price gets cheaper at higher tiers, so heavy users get better unit economics by upgrading rather than paying overage indefinitely on a lower tier.
  • Free has no overage tier. Once its 100 calls/month are used, calls fail until the next billing cycle — paid plans degrade gracefully into overage billing, Free does not.
Worked example — INR Essential user makes 1,800,000 calls → $35 base + (1,800,000 − 1,500,000) × ₹0.00175 = ₹525 overage

USD Billing — Minimum Purchase & Rounding

Because the per-call USD rate is fractions of a cent, USD-billed accounts don't get charged the raw calculated amount directly. Two rules apply:

  • Minimum overage purchase is $1. Even if your calculated overage comes out to a few cents, the smallest amount actually billed is $1.
  • Amounts round up to the next whole dollar. A calculated overage of $0.35 rounds up to $1 — never down, never left fractional.
Worked example — USD Essential user makes 300,000 extra calls × $0.00002059 = $6.177 calculated → rounds up to $7 billed
💵
Practical implication: USD overage costs scale in $1 increments, not smooth fractional amounts. Usage dashboards or cost estimators built against this API should round up locally to match what will actually be billed, or the displayed estimate will look cheaper than the actual invoice.

4.3Per-Plan Feature Access

PlanReal-time updatesSnapshot multi-symbolRBI/Customs/DXY/HolidaysTechnical IndicatorsWebSocket
Free❌ (60s)❌❌❌❌
Basic❌ (60s)❌❌❌❌
Essential✅✅✅❌❌
Pro✅✅✅❌✅ (2 conn)
Ultimate✅✅✅✅✅ (5 conn)

Technical Indicators is Ultimate-only with no exceptions — not available even on Pro. Real-time (sub-60s) updates don't start until Essential — Free and Basic are both capped at 60-second data regardless of which endpoints they can reach.

4.4Best Practices

  • Cache responses where data freshness allows it, to conserve quota and avoid unnecessary overage charges.
  • Poll at 10+ second intervals for real-time REST data on Essential+. On Free/Basic, since updates are 60-second regardless, polling faster than 60s is pure waste.
  • For WebSocket: all-pairs uses ceil(pairs ÷ 5) per init/delta; filtered symbols use 1 token per pair (init) and per changed pair (delta). connected, subscribed, and pong are free.
  • Avoid the manual aggregates refetch unless you specifically need to force a refresh; it's a heavy operation and consumes extra calls.
  • Watch usage against the recommended maximum, not just the included amount — overage billing means no hard block, but staying under the ceiling keeps your bill predictable.
  • Free-plan users: see §4.5 below — this is the priority path for anyone starting out.

4.5Free Plan: Which Endpoint to Use, and Why It Matters

This section exists because getting Free-plan users to a good first experience is the highest-priority part of this documentation — Free is the funnel into every paid plan, and a confusing first call is the easiest way to lose a future customer before they ever see what the paid tiers can do.

Snapshot Endpoints Free-Plan Users Can Call

url
GET https://api.ibrlive.com/api/forex/snapshot?apiKey=YOUR_API_KEY
GET https://api.ibrlive.com/api/forex/snapshot/USDINR?apiKey=YOUR_API_KEY
GET https://api.ibrlive.com/api/forex/snapshot/symbols?symbols=USDINR,EURUSD&apiKey=YOUR_API_KEY

Free includes all three Snapshot variants (see §3.1): all-pairs, single-symbol, and batch/multi-symbol. Prefer single-symbol or a small batch when you only need a few pairs — all-pairs costs ceil(pairs ÷ 5) and uses quota much faster.

Why This Matters More Than It Looks Like It Should

A Free-plan developer's first instinct is usually to look for "give me just USDINR" — that is the single-symbol endpoint, and it is now available on Free. Use it for evaluation instead of pulling all ~150 pairs when you only need one.

What a Free-Plan Integration Should Actually Look Like

  1. Call the single-symbol endpoint for the pair you care about:
    bash
    curl "https://api.ibrlive.com/api/forex/snapshot/USDINR?apiKey=YOUR_API_KEY"
  2. Or request a small batch when you need a few pairs:
    bash
    curl "https://api.ibrlive.com/api/forex/snapshot/symbols?symbols=USDINR,EURUSD,GBPINR&apiKey=YOUR_API_KEY"
  3. Budget your calls carefully. Single-symbol = 1 call; batch = 1 call per pair; all-pairs = ceil(total pairs ÷ 5) — at ~150 pairs, that's 30 calls deducted from your 100/month allowance. Prefer single/batch on Free.
  4. Free is for evaluation and light integration testing. Anyone running a production live feed should upgrade to Basic or higher for larger quotas and additional endpoints.

The natural upgrade trigger: once a developer needs historical data, conversion, previous close, or more than 100 calls/month, surface Basic (35,000/month) and Essential for real-time refresh and reference rates.

NeedFree can do it?What unlocks it
Confirm API key works✅—
See live rates for evaluation/testing✅—
Get just one specific pair✅—
Multiple specific pairs in one call✅—
Poll regularly for a live production feature❌Basic at minimum; Essential for real-time refresh
Historical data, conversion, previous close, RBI historical❌Basic
RBI Latest / Customs / DXY reference rates❌Essential
📌
RBI Historical unlocks on Basic+ (see §3.10). Free users get all three Snapshot variants for evaluation; live Customs / RBI Latest / DXY need Essential+.

05Endpoint Access Matrix

A consolidated view of which plan unlocks which of the 10 endpoints, since access requirements are scattered across each endpoint's individual notes above.

EndpointFreeBasicEssentialProUltimate
Snapshot — all pairs✅✅✅✅✅
Snapshot — single pair✅✅✅✅✅
Snapshot — batch/multi-symbol✅✅✅✅✅
Snapshot WebSocket❌❌❌✅ (2 conn)✅ (5 conn)
Currency Conversion❌✅✅✅✅
Forex Aggregates❌✅✅✅✅
Previous Close❌✅✅✅✅
Indian Customs Rates❌❌✅✅✅
RBI Reference (Latest)❌❌✅✅✅
DXY Index❌❌✅✅✅
RBI Reference (Historical)❌✅✅✅✅
Forward Rate (Broken Date)❌❌❌Add-onAdd-on
Monthly Forward Rates❌❌❌Add-onAdd-on
Cash / Tom / Spot❌❌❌Add-onAdd-on
Technical Indicators❌❌❌❌✅
📌
"Access" above means the endpoint is reachable on that plan — it doesn't mean real-time data. Basic-tier access to Currency Conversion, Aggregates, and Previous Close is still capped at 60-second cache freshness, same as Free; only Essential and above get real-time (3s) data across the board.

06Error Handling

Most responses include success. On failure, success: false plus error and (usually) details:

json
{
  "success": false,
  "error": "Monthly API limit exceeded",
  "details": "Current limit: 200000, Used: 200000"
}
📌
Exception: Indian Customs, RBI Latest, RBI Historical, and DXY return payload-only JSON on success (no success field). Error responses from these endpoints still use success: false.

HTTP Status Codes

CodeMeaning
200Success
400Bad Request — invalid parameters (e.g. unsupported symbol)
401Unauthorized — missing or invalid API key
403Forbidden — plan doesn't include this feature, or plan expired
404Not Found — data unavailable, or endpoint doesn't exist
429Rate Limit Exceeded — monthly quota reached
500Internal Server Error

Common Scenarios

ScenarioStatusFix
Invalid API key401Check the key is correct, active, and in the query string
Plan doesn't include endpoint403Upgrade — e.g. Technical Indicators requires Ultimate
Free monthly quota exhausted429Free's 100 calls/month are used up — wait for next billing cycle or upgrade. No overage option on Free.
Monthly quota exceeded (paid)429Wait for reset, upgrade, or accept overage billing — paid plans don't hard-block.
Invalid symbol400Check spelling against the supported symbol list
Data not available404Aggregates may still be processing, or the symbol/timeframe combo isn't supported
WebSocket rejected on connectsocket errorCheck current_plan/required_plans in the error payload

Example Error Bodies

json
// Monthly quota exceeded (Free or paid)
{ "success": false, "error": "Monthly API limit exceeded",
  "details": "Monthly API limit exceeded. Current limit: 100, Used: 100" }

// Feature gated by plan
{ "success": false, "error": "No active subscription",
  "details": "Technical indicators are only available with Ultimate plan. Please upgrade your subscription." }

// Bad symbol
{ "success": false, "error": "Invalid symbol: INVALID",
  "availableSymbols": ["USDINR", "EURUSD", "GBPUSD"] }

// WebSocket — plan too low
{ "type": "error", "error": "WebSocket snapshot is only available on Pro and Ultimate plans",
  "current_plan": "ESSENTIAL", "required_plans": ["PRO", "ULTIMATE"] }

Recommended Client Handling (REST)

javascript
try {
  const { data } = await axios.get(url, { params });
  if ('success' in data && !data.success) throw new Error(data.error);
  return data;
} catch (err) {
  if (err.response) {
    console.error('API error:', err.response.status, err.response.data);
  } else {
    console.error('Network error:', err.message);
  }
  throw err;
}

07Code Examples

JavaScript — Aggregates

javascript
const getForexAggregates = async (symbol, time, multiply, from, to, apiKey) => {
  const response = await fetch(
    `https://api.ibrlive.com/api/aggregate/data?symbol=${symbol}&time=${time}&multiply=${multiply}&from=${from}&to=${to}&apiKey=${apiKey}`
  );
  const data = await response.json();
  if (!data.success) throw new Error(data.error);
  return data;
};

Node.js — Previous Close

javascript
const axios = require('axios');

async function getPreviousClose(symbol, apiKey) {
  try {
    const { data } = await axios.get('https://api.ibrlive.com/api/forex/previous-close', {
      params: { symbol, apiKey }
    });
    if (!data.success) throw new Error(data.error);
    return data.data;
  } catch (error) {
    if (error.response) {
      console.error('API Error:', error.response.status, error.response.data);
    } else {
      console.error('Network Error:', error.message);
    }
    throw error;
  }
}

Python — Technical Indicators

python
import requests

def get_technical_indicators(symbol, timeframe='daily', api_key='YOUR_API_KEY'):
    response = requests.get(
        "https://api.ibrlive.com/api/forex/get-technical-indicators",
        params={"symbol": symbol, "timeframe": timeframe, "apiKey": api_key}
    )
    response.raise_for_status()
    data = response.json()
    if not data['success']:
        raise Exception(data['error'])
    return data['data']

React — Polling Snapshot (REST)

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

const useForexSnapshot = (apiKey, symbols = null) => {
  const [snapshot, setSnapshot] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchSnapshot = async () => {
      try {
        const url = symbols
          ? `https://api.ibrlive.com/api/forex/snapshot/symbols?symbols=${symbols.join(',')}&apiKey=${apiKey}`
          : `https://api.ibrlive.com/api/forex/snapshot?apiKey=${apiKey}`;
        const response = await fetch(url);
        const data = await response.json();
        if (data.success) setSnapshot(data);
      } catch (error) {
        console.error('Failed to fetch snapshot:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchSnapshot();
    const interval = setInterval(fetchSnapshot, 10000); // 10s poll, matches 3s server refresh
    return () => clearInterval(interval);
  }, [apiKey, symbols]);

  return { snapshot, loading };
};

JavaScript — WebSocket Streaming Snapshot

javascript
function connectSnapshotStream(apiKey, { symbols, onUpdate, onError } = {}) {
  const url = symbols
    ? `wss://api.ibrlive.com/api/forex/ws/snapshot?api_key=${apiKey}&symbols=${symbols.join(',')}`
    : `wss://api.ibrlive.com/api/forex/ws/snapshot?api_key=${apiKey}`;

  const ws = new WebSocket(url);

  ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.type === 'init' || msg.type === 'delta') onUpdate?.(msg);
    if (msg.type === 'error') onError?.(msg);
  };

  ws.onclose = (e) => console.log('Snapshot stream closed', e.code, e.reason);
  return ws;
}

const ws = connectSnapshotStream(apiKey, {
  symbols: ['USDINR', 'EURUSD'],
  onUpdate: (msg) => console.log(msg.lastQuotes),
  onError: (msg) => console.error(msg.error)
});