# Live Market Data Feed — Integration Guide

Real-time streaming market data over Server-Sent Events (SSE). Drop-in JavaScript
client, works in any modern browser, no WebSocket handshake needed.

---

## 1. What you'll get from us

Before you can integrate, we'll send you three things:

| Item | Example |
|---|---|
| **Endpoint URL** | `https://mkt-ticker-data-production.up.railway.app` |
| **API token** | `VocI0nJDg4IyFWuzPw-T3e2uDqbGNj2Y` *(unique per partner)* |
| **Whitelisted origins** | e.g. `https://yourapp.com`, `https://staging.yourapp.com` |

> **Important:** the token only works from origins we've whitelisted for you.
> Tell us every domain/subdomain (prod + staging) where your pages will run.
> CORS preflight will block any other origin with a `403 Forbidden`.

---

## 2. Quickest integration (drop-in script, ~10 lines of HTML)

```html
<script src="https://mkt-ticker-data-production.up.railway.app/velora-feed-client.js"></script>
<script>
  const feed = new VeloraFeed({
    endpoint: 'https://mkt-ticker-data-production.up.railway.app',
    token:    'YOUR_TOKEN_HERE',
    subs: [
      [19, 2101],  // BTC/USD
      [19, 2102],  // ETH/USD
      [3, 2],      // EUR/USD
      [2, 26000],  // NIFTY 50
      [1, 2885],   // RELIANCE (NSE)
    ],
  });

  feed.on('tick', (t) => {
    console.log(t.symbol, t.ltp, `${t.changePct.toFixed(2)}%`);
    // Example: update a DOM element
    document.getElementById('price-' + t.key)?.replaceChildren(t.ltp.toFixed(t.priceDecimals));
  });

  feed.on('status', (s) => console.log('connection:', s.status));
  feed.start();
</script>
```

That's it. You'll start getting live ticks within a second of `feed.start()`.

**Live demo page you can inspect for reference:**
https://mkt-ticker-data-production.up.railway.app/demo.html

---

## 3. Subscribe format

Every subscription is a `[exchangeId, instrumentToken]` pair.

### Exchange IDs

| ID | Segment | Examples |
|---|---|---|
| **1** | NSE Cash Market (equities) | RELIANCE, TCS, INFY, SBIN |
| **2** | NSE F&O + Indices | NIFTY 50, BANKNIFTY, NIFTY FUT |
| **3** | CDS — Forex, US Stocks, Indices, Metals, Energy | EUR/USD, AAPL, S&P 500, XAUUSD |
| **4** | MCX Commodity | GOLD, SILVER, CRUDE OIL |
| **19** | DCSX Crypto (USD pairs) | BTC/USD, ETH/USD, SOL/USD |

### Common instrument tokens

**Crypto (Exchange 19)**

| Token | Symbol |
|---|---|
| 2101 | BTC/USD |
| 2102 | ETH/USD |
| 2103 | SOL/USD |
| 2104 | XRP/USD |
| 2105 | DOGE/USD |
| 2106 | ADA/USD |
| 2107 | BNB/USD |
| 2108 | AVAX/USD |
| 2109 | LTC/USD |
| 2110 | BCH/USD |

**Forex (Exchange 3)**

| Token | Symbol |
|---|---|
| 1 | AUD/USD |
| 2 | EUR/USD |
| 3 | GBP/USD |
| 7 | USD/JPY |
| 29 | XAU/USD (Gold) |
| 30 | XAG/USD (Silver) |

**US Stocks (Exchange 3)**

| Token | Symbol |
|---|---|
| 1001 | AAPL |
| 1010 | AMZN |
| 1038 | GOOGL |
| 1057 | META |
| 1061 | MSFT |
| 1066 | NVDA |
| 1081 | TSLA |

**Global Indices (Exchange 3)**

| Token | Symbol |
|---|---|
| 41 | US30 (Dow Jones) |
| 42 | UT100 (NASDAQ) |
| 43 | US500 (S&P 500) |
| 51 | JP225 (Nikkei) |

**NSE Stocks (Exchange 1)**

| Token | Symbol |
|---|---|
| 2885 | RELIANCE |
| 11536 | TCS |
| 1594 | INFY |
| 3045 | SBIN |
| 4963 | ICICIBANK |
| 10604 | BHARTIARTL |

**NSE F&O + Indices (Exchange 2)**

| Token | Symbol |
|---|---|
| 26000 | NIFTY 50 (spot) |
| 26009 | BANKNIFTY (spot) |
| 62326 | BANKNIFTY FUT |
| 62329 | NIFTY FUT |
| 62327 | FINNIFTY FUT |

For the full list, query the instruments API (see section 5).

---

## 4. Tick payload

Each tick you receive looks like this:

```json
{
  "key": "19_2101",
  "exchange": 19,
  "token": 2101,
  "symbol": "BTCUSD",
  "category": "CRYPTO",
  "ltp": 77539.9,
  "change": 512.3,
  "changePct": 0.66,
  "bid": 77538.5,
  "ask": 77541.2,
  "high": 77800.0,
  "low": 76500.0,
  "ltq": 0.12,
  "openInterest": 0,
  "ltt": 1745324500,
  "priceDecimals": 1,
  "ts": 1745324512345
}
```

| Field | Meaning |
|---|---|
| `key` | Unique identifier, `<exchange>_<token>` |
| `ltp` | Last traded price (already divided — use as-is) |
| `change` | Price change since previous close |
| `changePct` | Percentage change |
| `bid` / `ask` | Best bid / ask price |
| `high` / `low` | Intraday high / low |
| `ltq` | Last traded quantity |
| `ltt` | Last trade time (epoch seconds) |
| `priceDecimals` | How many decimal places to display |
| `ts` | Our server timestamp (epoch ms) |

---

## 5. Discovering instruments programmatically

```
GET https://mkt-ticker-data-production.up.railway.app/api/public/instruments
    ?token=YOUR_TOKEN
    &category=CRYPTO          (optional — filter by segment)
    &q=BTC                    (optional — substring match on symbol/name)
    &limit=200                (optional — default 500)
```

Response:

```json
{
  "total": 10,
  "categories": ["CRYPTO", "FOREX", "USSTOCK", ...],
  "items": [
    {
      "token": 2101,
      "exchange": 19,
      "symbol": "BTCUSD",
      "name": "Bitcoin / USD",
      "category": "CRYPTO",
      "priceDecimals": 2,
      "qtyDecimals": 2
    },
    ...
  ]
}
```

The `categories` array lists only segments your token is allowed to access.

---

## 6. Events emitted by the client

```js
feed.on('hello', (info) => {
  // Sent once on connect. Tells you which subs were accepted/denied.
  console.log(info);
  // { client: "Your Name", allowedSegments: [...], subscribed: 5, denied: [] }
});

feed.on('status', (s) => {
  // Upstream connection state: "open", "closed", "connecting"
  console.log(s.status);
});

feed.on('snapshot', (ticks) => {
  // Bulk payload sent on connect with the last known value for every instrument
  // you subscribed to. Useful to populate your UI immediately.
  ticks.forEach(updateRow);
});

feed.on('tick', (tick) => {
  // Streamed continuously as prices change.
  updateRow(tick);
});

feed.on('error', (err) => {
  // Connection error or server-side message.
  console.error(err);
});
```

---

## 7. Using without the SDK (plain EventSource)

If you prefer native browser APIs:

```js
const url = new URL('https://mkt-ticker-data-production.up.railway.app/api/public/stream');
url.searchParams.set('token', 'YOUR_TOKEN');
url.searchParams.set('subs', '19:2101,19:2102,3:2,2:26000');

const es = new EventSource(url);
es.addEventListener('tick', (msg) => {
  const tick = JSON.parse(msg.data);
  console.log(tick.symbol, tick.ltp);
});
```

---

## 8. Framework examples

### React (hook)

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

function useLiveTicker(subs, token) {
  const [ticks, setTicks] = useState({});
  useEffect(() => {
    const feed = new VeloraFeed({
      endpoint: 'https://mkt-ticker-data-production.up.railway.app',
      token,
      subs,
    });
    feed.on('snapshot', (list) => {
      setTicks((cur) => ({ ...cur, ...Object.fromEntries(list.map(t => [t.key, t])) }));
    });
    feed.on('tick', (t) => setTicks((cur) => ({ ...cur, [t.key]: t })));
    feed.start();
    return () => feed.stop();
  }, [JSON.stringify(subs), token]);
  return ticks;
}

// usage:
const ticks = useLiveTicker([[19,2101],[2,26000]], 'YOUR_TOKEN');
return <div>BTC: {ticks['19_2101']?.ltp}</div>;
```

### Vue 3

```vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
const ticks = ref({});
let feed;
onMounted(() => {
  feed = new VeloraFeed({
    endpoint: 'https://mkt-ticker-data-production.up.railway.app',
    token: 'YOUR_TOKEN',
    subs: [[19,2101],[19,2102]],
  });
  feed.on('tick', (t) => (ticks.value = { ...ticks.value, [t.key]: t }));
  feed.start();
});
onUnmounted(() => feed?.stop());
</script>

<template>
  <div v-for="t in ticks" :key="t.key">{{ t.symbol }}: {{ t.ltp }}</div>
</template>
```

---

## 9. Rate limits & policies

| Rule | Limit |
|---|---|
| Max subscriptions per connection | **200** (default; can be raised on request) |
| Max concurrent connections per token | No hard cap; be sensible |
| Reconnect on drop | Automatic; client reconnects after network loss |
| Allowed segments | Configured per-token (we'll share your list) |

---

## 10. Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| `401 Unauthorized` | Missing/invalid token | Check the token string; no quotes/whitespace |
| `403 Forbidden` | Origin not whitelisted | Send us the exact origin shown in devtools Network tab |
| `429 Too Many Requests` | Over subscription cap | Reduce subs or ask for a higher limit |
| No ticks flowing, status "open" | Subscribed to segment not allowed for your token | Check the `hello` event's `denied` array |
| CORS errors in devtools | Browser blocks before hitting our server | Whitelist issue — contact us with your origin |

## 11. Browser compatibility

Works in all modern browsers (Chrome, Edge, Firefox, Safari). SSE is supported
natively; no polyfill needed. IE 11 is not supported.

---

## 12. Contact

- **Endpoint:** https://mkt-ticker-data-production.up.railway.app
- **Demo:** https://mkt-ticker-data-production.up.railway.app/demo.html
- **Issues / new origins / limit increases:** contact your account manager

Happy trading!
