Browse documentation
Integrations

WebSocket streams

Instead of polling REST endpoints for fresh filings, earnings, news, concalls, and alerts, open a single WebSocket connection and subscribe to the products you care about. Drishti pushes structured events the moment they are available — useful for watchlist monitors, research desks, and agent workflows that need to react quickly.

How it works

Five steps to get from zero to receiving events:

  1. Upgrade to a paid plan. WebSocket live streams require Starter, Pro, or Scale. Copy an API key from the Drishti platform console.
  2. Open a connection. Connect to wss://developers.manasija.in/v1/ws with your API key. Prefer the SDK websocket helper for reconnects and subscription replay, or follow the setup guide for a full walkthrough.
  3. Send subscribe messages. One JSON message per product, with the symbols you want on your watchlist.
  4. Handle delivery envelopes. Every pushed event arrives as {"channel": "<product>", "data": {...}}.
  5. Go live. Walk through the production checklist before routing customer-facing flows through your handler.

Production checklist

Before relying on WebSocket streams for production-critical flows, work through each of these:

  1. Use the SDK session client when you can. The JavaScript / TypeScript SDK and Python SDK reconnect automatically and replay subscriptions after every drop. Raw sockets require you to resubscribe manually.
  2. Keep handlers fast. Parse the envelope, enqueue heavy work, and return control. Slow consumers back up the connection and make reconnect storms worse.
  3. Respect symbol limits. Starter allows 100 active symbols account-wide; Pro allows 1,000. Scale unlocks full-market delivery with an empty symbols array.
  4. Keep your API key out of client bundles. Browser clients must pass the key in the query string, which is visible in DevTools. Prefer a backend proxy for production user-facing apps.

Endpoint

text
wss://developers.manasija.in/v1/ws

Authenticate with the same API key you use for REST. Server clients can send X-API-Key; browser clients typically use ?api_key=<key>. See Authentication.

SDK websocket helper

Use client.websocket() from the official SDK instead of managing raw sockets yourself. The session client connects in the background, sends subscribe frames for you, replays every subscription after reconnect, and keeps retrying until you call close().

Install

pnpm add drishti-sdk
bash
pip install drishti-sdk

See the JavaScript / TypeScript SDK and Python SDK pages for full package details.

JavaScript / TypeScript

Create a session from any DrishtiClient instance, subscribe to one or more products, then handle events with callbacks or an async iterator:

ts
import { DrishtiClient } from "drishti-sdk"

const client = new DrishtiClient({ apiKey: process.env.DRISHTI_API_KEY! })
const ws = client.websocket({
  reconnectInitialDelayMs: 1000,
  reconnectMaxDelayMs: 30000,
  onReconnectAttempt: (attempt, delayMs, reason) => {
    console.log("reconnect", { attempt, delayMs, reason })
  },
  onAnnouncements: (announcement) => {
    console.log("announcement", announcement.symbol, announcement.summary)
  },
})

await ws.subscribe({ product: "announcements", symbols: ["RELIANCE", "TCS"], detailed: true })
// callbacks fire as events arrive; call await ws.close() when finished

Prefer for await when you want one loop that also sees subscribe acknowledgements and socket errors:

ts
const ws = client.websocket()

await ws.subscribe({ product: "announcements", symbols: ["RELIANCE"], detailed: false })

for await (const event of ws.events()) {
  if (event.kind === "subscribed") {
    console.log(event.product, event.tier)
    continue
  }
  if (event.kind === "data") console.log(event.channel, event.data)
  if (event.kind === "error") console.error(event.message)
}

Channel listeners are also available via ws.on("announcements", handler) and product-specific helpers such as ws.onAnnouncements(handler), ws.onNews(handler), ws.onBlockDeals(handler), and ws.onAlerts(handler).

Python

The Python helper is async-first. The session connects on the first subscribe, events, or async with call:

python
import asyncio
import os
from drishti_sdk import DrishtiClient

async def main() -> None:
    client = DrishtiClient(api_key=os.environ["DRISHTI_API_KEY"])
    async with client.websocket(
        reconnect_initial_delay=1.0,
        reconnect_max_delay=30.0,
        on_announcements=lambda row: print(
            "announcement", row.get("symbol"), row.get("summary")
        ),
    ) as ws:
        ack = await ws.subscribe("announcements", symbols=["RELIANCE", "TCS"], detailed=True)
        print("subscribed", ack.product, ack.tier)
        await asyncio.Event().wait()

asyncio.run(main())

Use async for event in ws.events() when you want subscribe acknowledgements and delivery events in one stream:

python
async with client.websocket() as ws:
    await ws.subscribe("announcements", symbols=["RELIANCE"], detailed=False)
    async for event in ws.events():
        if event.kind == "subscribed":
            print(event.product, event.tier)
            continue
        if event.kind == "data":
            print(event.channel, event.data)
        if event.kind == "error":
            print(event.message)

Session API

MethodJavaScript / TypeScriptPythonDescription
Create sessionclient.websocket(options?)client.websocket(...)Opens (or prepares) a managed WebSocket session tied to the client API key.
Subscribeawait ws.subscribe({ product, symbols, detailed? })await ws.subscribe(product, symbols=..., detailed=...)Sends the subscribe frame and returns the server acknowledgement (tier, symbols, full_feed, detailed).
Event streamfor await (const event of ws.events())async for event in ws.events()Yields subscribed, data, and error events from one loop.
Channel listenersws.on(channel, handler) / ws.onAnnouncements(handler)on_announcements=..., on_news=..., etc.Product-specific callbacks for data deliveries.
Closeawait ws.close()async with exit / await ws.close()Stops reconnect attempts and closes the socket.

Products

Send one subscribe message per product. Re-subscribing to the same product replaces that product's subscription on the active connection.

ProductStreamREST equivalent
newsNews updates`GET /v1/news`
block-dealsBlock-deal updates`GET /v1/block-deals`
announcementsCorporate announcements`GET /v1/announcements`
earningsEarnings filings`GET /v1/earnings`
concallsConference-call updates`GET /v1/concalls`
alertsMarket alerts`GET /v1/alerts`

Subscribe message

Outbound contract

json
{"op":"subscribe","product":"announcements","symbols":["RELIANCE","TCS"],"detailed":true}
FieldTypeDescription
opstringMust be subscribe.
productstringOne of news, block-deals, announcements, earnings, concalls, or alerts.
symbolsstring[]Watchlist symbols for filtered delivery. Empty symbols requests the full feed and requires Scale entitlement.
detailedbooleanOptional. Defaults to true. Controls summary vs detail payload shape on supported products.

Subscription acknowledgement

After a successful subscribe, the server replies with the accepted tier, normalized symbol list, full_feed flag, and final detailed mode:

json
{"status":"subscribed","product":"announcements","tier":"starter_100","full_feed":false,"symbols":["RELIANCE","TCS"],"detailed":true}

Failed subscriptions return an error envelope on the socket instead of status: subscribed. Common causes: missing websocket entitlement, symbol cap exceeded, or an unknown product name.

Delivery envelope

Every pushed event uses the same top-level shape. The data object mirrors the REST list or detail schema for that product.

Envelope

FieldTypeDescription
channelstringThe product that produced the event — same value as product in your subscribe message.
dataobjectThe resource payload. Shape depends on channel and your detailed setting.

Example delivery:

json
{
  "channel": "announcements",
  "data": {
    "id": "6a015e446ec560b11681e3c9",
    "symbol": "RELIANCE",
    "summary": "The board approved the quarterly financial results.",
    "category": "Board Meeting",
    "important": true
  }
}

Shapes by channel

ChannelData shape when detailed=trueData shape when detailed=false
newsNewsItemNewsItem
block-dealsBlockDealItemBlockDealItem
announcementsAnnouncementDetailAnnouncementListItem
earningsEarningsDetailEarningsListItem
concallsConcallDetailConcallListItem
alertsAlertAlert

Notes:

  • News does not split into summary vs detail on WebSocket delivery.
  • Block deals mirror the REST block-deal item shape.
  • Announcements, earnings, and concalls mirror the REST list/detail shapes for the same product.
  • Announcement WebSocket events never include attachment URLs or R2 keys. Earnings events may include attachment_url.
  • Alerts use the public Alert shape and keep type / alert_type compatibility. Each event has canonical UTC timestamp for the alert creation time; price alerts additionally include delayed price.value, signed price.change_percent, and price.as_of for the price observation time.
  • Known public alert type values: 52w_high, 52w_low, earnings, high_growth_concalls, price_alert, rvol_alert, volume_alert.

Summary vs detail on the same symbol

A single symbol can produce multiple events over time — for example an earnings intimation followed days later by the full results filing. Both events share the same symbol but carry different data.id values and payload richness.

Three reasonable ways to handle this in your handler:

  • Process every event — emit a downstream signal for each delivery. Use when latency matters more than deduplication.
  • Keep the richest record — when detailed=true, overwrite an earlier summary-only row once the full filing arrives.
  • Dedupe by business key — for once-per-filing semantics, key on (symbol, category, filing date) or data.id depending on your product rules.

Examples by product

Product examples

Loading websocket examples...

Authentication

Use the same Drishti API key as REST. The upgrade handshake accepts:

MethodValue
HeaderX-API-Key: <key>
Query string?api_key=<key>

WebSocket product access is evaluated separately from REST scopes. A key with REST access but no websocket entitlement is rejected at connect or subscribe time with 403.

Reconnection and delivery semantics

WebSocket connections can drop because of network interruptions, proxy timeouts, or server-side lifecycle events. Subscriptions are bound to the active connection — if the socket disconnects, you must open a new connection and send subscribe messages again to resume delivery.

There is no server-side replay buffer. Events published while the service is down are not backfilled over the socket — use REST list endpoints to catch up after an outage.

Symbol limits

PlanWebSocket accessSymbol capFull feed
SandboxNot available——
StarterAll products100 active symbols account-wideNo
ProAll products1,000 active symbols account-wideNo
ScaleAll productsFull marketYes — send empty symbols

Active symbols are counted account-wide across every open connection and product subscription.

Security

  • Treat API keys like passwords. Never commit them to git. Store them in a secret manager and rotate from the platform console if they leak.
  • Prefer server-side subscribers. Query-string keys in browser clients are visible to anyone with DevTools access.
  • Use TLS. Production clients must connect to wss://, not ws://.

Limits

  • One subscribe message per product on a connection. A second subscribe for the same product replaces the previous one.
  • No REST credits are charged for WebSocket delivery on paid plans.
  • Sandbox plans cannot open live WebSocket streams. Upgrade to Starter or above.

Troubleshooting

Connection closes immediately with `401` or `403`. Confirm the API key is valid, the account is on a paid plan, and the key has websocket entitlement. Check Get account profile for enabled products.

Subscribe returns an error instead of `status: subscribed`. You may have exceeded the symbol cap, requested a full feed without Scale, or passed an invalid product name. The error message on the socket includes the reason.

No events arrive after a successful subscribe. Markets are quiet between filings. Confirm your symbols are correct and that you are subscribed to the right product. Use REST list endpoints to verify recent data exists for those symbols.

Events stop after a deploy. Subscriptions do not survive disconnects on raw sockets. If you are not using the SDK, resubscribe after every reconnect.

Next steps