Browse documentation
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:
- Upgrade to a paid plan. WebSocket live streams require Starter, Pro, or Scale. Copy an API key from the Drishti platform console.
- Open a connection. Connect to
wss://developers.manasija.in/v1/wswith your API key. Prefer the SDK websocket helper for reconnects and subscription replay, or follow the setup guide for a full walkthrough. - Send subscribe messages. One JSON message per product, with the symbols you want on your watchlist.
- Handle delivery envelopes. Every pushed event arrives as
{"channel": "<product>", "data": {...}}. - 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:
- 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.
- Keep handlers fast. Parse the envelope, enqueue heavy work, and return control. Slow consumers back up the connection and make reconnect storms worse.
- Respect symbol limits. Starter allows 100 active symbols account-wide; Pro allows 1,000. Scale unlocks full-market delivery with an empty
symbolsarray. - 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
wss://developers.manasija.in/v1/wsAuthenticate 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-sdkpip install drishti-sdkSee 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:
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 finishedPrefer for await when you want one loop that also sees subscribe acknowledgements and socket errors:
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:
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:
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
| Method | JavaScript / TypeScript | Python | Description |
|---|---|---|---|
| Create session | client.websocket(options?) | client.websocket(...) | Opens (or prepares) a managed WebSocket session tied to the client API key. |
| Subscribe | await 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 stream | for await (const event of ws.events()) | async for event in ws.events() | Yields subscribed, data, and error events from one loop. |
| Channel listeners | ws.on(channel, handler) / ws.onAnnouncements(handler) | on_announcements=..., on_news=..., etc. | Product-specific callbacks for data deliveries. |
| Close | await 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.
| Product | Stream | REST equivalent |
|---|---|---|
news | News updates | `GET /v1/news` |
block-deals | Block-deal updates | `GET /v1/block-deals` |
announcements | Corporate announcements | `GET /v1/announcements` |
earnings | Earnings filings | `GET /v1/earnings` |
concalls | Conference-call updates | `GET /v1/concalls` |
alerts | Market alerts | `GET /v1/alerts` |
Subscribe message
Outbound contract
{"op":"subscribe","product":"announcements","symbols":["RELIANCE","TCS"],"detailed":true}| Field | Type | Description |
|---|---|---|
op | string | Must be subscribe. |
product | string | One of news, block-deals, announcements, earnings, concalls, or alerts. |
symbols | string[] | Watchlist symbols for filtered delivery. Empty symbols requests the full feed and requires Scale entitlement. |
detailed | boolean | Optional. 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:
{"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
| Field | Type | Description |
|---|---|---|
channel | string | The product that produced the event — same value as product in your subscribe message. |
data | object | The resource payload. Shape depends on channel and your detailed setting. |
Example delivery:
{
"channel": "announcements",
"data": {
"id": "6a015e446ec560b11681e3c9",
"symbol": "RELIANCE",
"summary": "The board approved the quarterly financial results.",
"category": "Board Meeting",
"important": true
}
}Shapes by channel
| Channel | Data shape when detailed=true | Data shape when detailed=false |
|---|---|---|
news | NewsItem | NewsItem |
block-deals | BlockDealItem | BlockDealItem |
announcements | AnnouncementDetail | AnnouncementListItem |
earnings | EarningsDetail | EarningsListItem |
concalls | ConcallDetail | ConcallListItem |
alerts | Alert | Alert |
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
Alertshape and keeptype/alert_typecompatibility. Each event has canonical UTCtimestampfor the alert creation time; price alerts additionally include delayedprice.value, signedprice.change_percent, andprice.as_offor the price observation time. - Known public alert
typevalues: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)ordata.iddepending 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:
| Method | Value |
|---|---|
| Header | X-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
| Plan | WebSocket access | Symbol cap | Full feed |
|---|---|---|---|
| Sandbox | Not available | — | — |
| Starter | All products | 100 active symbols account-wide | No |
| Pro | All products | 1,000 active symbols account-wide | No |
| Scale | All products | Full market | Yes — 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://, notws://.
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
- SDK websocket helper — managed session client for TypeScript and Python.
- How to set up WebSockets — step-by-step walkthrough with a working subscriber.
- Authentication — API key setup for REST and WebSocket.
- JavaScript / TypeScript SDK — websocket session client reference.
- Python SDK — async websocket client reference.
- Pricing — compare symbol limits and plan tiers.