A broker API is a permissioned doorway into the same account you already log into by hand. It does not give your program a faster exchange, a private order book or a special queue. It gives it the ability to read prices and send orders without a human touching a screen — under an authentication scheme that expires, a rate limit you can exhaust, and an order state machine that will hand you outcomes your code has to be written to expect. Most of what goes wrong in a live system goes wrong in that plumbing, not in the strategy.
What is a broker API, and what does it not give you?
Several SEBI-registered brokers in India publish a programmatic interface to a retail trading account — Zerodha, Dhan, Fyers, Angel One and Upstox among them. They are named here only as examples of who offers one; this page does not compare, rank or recommend any broker, and choosing one is your decision to take on your own terms.
What every one of them exposes is roughly the same set of capabilities: read a quote, read historical candles, subscribe to a live feed, place an order, modify or cancel an order, and read back positions, holdings, orders and funds. Names and shapes differ. The set does not.
What none of them gives you is worth stating just as plainly. No API makes you faster than the co-located institutional flow. No API removes exchange risk checks, margin requirements or circuit limits. No API lets you place an order your account could not have placed manually. And no API turns an unprofitable idea into a profitable one — it only lets you be wrong faster and without supervision.
Note — Automated order placement by a retail account sits inside SEBI's algorithmic trading framework, and the obligations there rest on you as much as on the broker. The framework topic in this module covers that separately. Nothing on this page is a statement about what you are permitted to run — check the current SEBI circulars and your broker's own terms.
How does authentication and the session lifecycle actually work?
This is the part beginners underestimate, and it is the single most common cause of a system that worked yesterday and is silent this morning.
A broker cannot simply hand your program a permanent password-equivalent, because a leaked one would be a live trading account in a stranger's hands. So the flow is almost always two-tier: a long-lived credential that identifies your application, and a short-lived token that authorises today's session and dies on its own.
- 1
Register the application
You create an app on the broker's developer console and receive an identifier and a secret. The secret is the thing an attacker wants. It belongs in an environment variable or a secrets store, never in the source file and never in a repository.
- 2
Log in through the broker's own page
The user — you — authenticates on a page the broker controls, usually with a second factor. Your program never sees the account password. That is the entire point of the design.
- 3
Exchange the redirect for a session token
The broker sends back a short-lived request token. Your program exchanges it, signed with the app secret, for the access token that every subsequent call carries.
- 4
Attach the token to every call
Usually as an authorisation header. A call without it, or with an expired one, comes back as an authentication error — not as an empty result. Your code must distinguish those two.
- 5
Expect the token to die, and plan for it
Many Indian brokers expire the session daily, commonly around the start of the trading day, and require a fresh interactive login. Some issue longer-lived tokens for specific use cases. Treat expiry as a scheduled event you handle, not an incident you discover.
Watch out — Daily expiry has a nasty property: it can land while you hold a position. The failure is not that you cannot enter — it is that you cannot exit. Any system that can open a position must be able to prove, before it opens one, that it still holds a valid session and can place the closing order.
Which parts of a broker API change, and which stay stable?
The practical consequence is architectural. Write your strategy against your own small interface — `get_quote`, `place_order`, `get_positions` — and let one adapter translate that into whatever a particular broker currently calls those things. Then a broker change, or a broker switch, is one file.
| Part of the interface | How stable is it? | What that means for your code |
|---|---|---|
| The capability set — quotes, orders, positions, funds | Very stable across brokers and years | Safe to design your own interface around. This is what you abstract. |
| Field names and payload shapes | Broker-specific, and revised between versions | Isolate them in one adapter file so a rename touches one place, not fifty. |
| Rate limits and throttling rules | Change without much notice | Never hard-code a number from a blog post. Read the broker's current docs. |
| Instrument identifiers and the master contract list | Refreshed daily; identifiers get reused over time | Download the master list every morning. Never cache an identifier across expiries. |
| Charges, plan limits and API pricing | Commercial, and changed at the broker's discretion | Out of scope for any article. Check the broker's current published terms. |
REST or WebSocket — when do you need each?
There are two fundamentally different ways to get data out of a broker, and the choice is not a preference.
A REST call is a question. Your program asks, the server answers, the connection ends. Everything that happened between two questions is invisible to you. A WebSocket is a subscription. You connect once, tell the broker which instruments you care about, and it pushes updates to you as they occur.
What does each transport suit?
Most retail systems need both. A REST call fetches the state of the world at start-up and after any reconnect; the socket keeps that state current while everything is healthy. The mistake is using only one: a poll-only system is blind between polls, and a socket-only system has no way to recover what it missed.
| REST (you ask) | WebSocket (the broker pushes) | |
|---|---|---|
| Shape | Request, response, done | One long-lived connection carrying many messages |
| Good for | Historical candles, funds, positions, holdings, order placement and modification | Live quotes, depth, and order-update streams |
| Cost of frequency | Every poll spends part of your rate budget | Subscribing costs one connection, not one call per update |
| What it misses | Everything between two polls | Everything sent while you were disconnected |
| Fails by | Timing out, or being throttled | Going quiet without an error — the connection is open, nothing is arriving |
| Reasonable use | Decisions taken on candle closes, at low frequency | Anything reacting inside a candle, and every live order-status feed |
What happens after you send an order?
An order is not an event. It is a state machine, and your code has to model every state it can land in — including the ones that are neither a clean fill nor a clean rejection.
The request returning HTTP 200 means the broker accepted the message. It does not mean anything traded. Treating the acknowledgement as a fill is the single most expensive beginner error in live systems, because a position tracker built on acknowledgements drifts away from the real one within minutes.
Why does a partial fill break naive position tracking?
Suppose your rule wants 400 shares and you send one market-adjacent limit order for the full quantity. The book takes 150 at your price, then price moves away and the rest sits unfilled. You cancel.
A system that recorded 'ordered 400, cancelled, therefore flat' is now 150 shares long and does not know it. Its next signal will size from a position of zero. Its stop logic will protect nothing. Its end-of-day reconciliation will disagree with the broker's contract note, and the disagreement will be discovered after the damage.
Net position = Σ (filled quantity × side) — never Σ (orders sent)- Filled quantity — the quantity the exchange actually traded, read from the order or trade feed, not from the placement response.
- Side — +1 for a buy, −1 for a sell.
- Orders sent — deliberately absent from the right-hand side. An order is an intention; a fill is a fact.
Example — Illustrative arithmetic with round numbers, not a real order in a real stock on a real session. The point is the accounting rule, not the quantities.
What does one complete round trip look like?
Put the pieces in order. This is the loop a live system runs, and every step in it is a place where the previous section's failure modes appear.
- 1
Establish the session
Log in, exchange the request token, hold the access token in memory. Never write it to a file that gets committed. Confirm it works with a cheap read call before doing anything else.
- 2
Load the master contract list
Download today's instrument list and map your symbols to the identifiers the broker expects. Doing this once per day, at start-up, removes an entire class of rejection.
- 3
Reconcile before you decide
Fetch positions, open orders and available funds over REST. Your in-memory state must start as a copy of the broker's, never as an assumption of flat.
- 4
Subscribe, then wait for the first tick
Open the socket, subscribe to your instruments, and do not evaluate a single rule until data has actually arrived. A subscription that silently failed looks identical to a quiet market.
- 5
Evaluate on a defined boundary
Decide on candle closes or on an explicit clock, not on every tick, unless the strategy genuinely requires it. Fewer decision points means fewer calls, fewer duplicates and a system you can reconstruct from logs.
- 6
Place with an identifier, then confirm by reading
Send the order with your own tag attached, then learn its fate from the order-update stream — falling back to a status read. The placement response is the beginning of the story, not the end of it.
- 7
Update position only from fills
Every fill message adjusts the position. Nothing else does. At the close, reconcile once more against the broker and log any disagreement as an incident to investigate before the next session.
What is different about pulling historical data?
Historical candles come over REST, and they carry their own traps that live quotes do not.
Brokers cap how much history one request may return, so a long series arrives as pages you stitch together — and stitching is where duplicated or missing candles creep in. The available depth is limited too, and it is usually shorter for finer intervals than for daily bars. Most importantly, the series you receive may or may not be adjusted for splits, bonuses and other corporate actions, and an unadjusted series contains price jumps that were never trades. Market Data, Corporate Actions and Bias covers that specifically.
Pro tip — Fetch history once, store it locally, and update incrementally. Re-downloading the same five years on every run wastes your rate budget, makes start-up slow, and means a broker outage takes your research offline as well as your trading.
How do rate limits and throttling actually bite?
Every broker caps how often you may call, typically as a per-second ceiling with separate, tighter ceilings for order-related endpoints than for read endpoints. Exceed it and you get a throttling error rather than data.
The numbers are broker-specific and revised — do not take any figure you read in an article, including this one, as current. Read your broker's own documentation and design to whatever it says today. What generalises is the behaviour, not the number.
- Throttling arrives at the worst moment. Volatility is exactly when your loop tries to do the most and when the broker is serving the most callers.
- A throttled order request is not a placed order. But a throttled response to a status check tells you nothing about an order that may already be live.
- Retrying immediately makes it worse. Back off — wait, then wait longer — and cap the number of attempts.
- Never retry an order placement blindly. A timed-out request may have succeeded at the exchange. Query the order book by your own client-side order identifier first, then decide.
- Poll status on a schedule, not in a tight loop. Subscribe to the order-update stream and use REST only to reconcile.
- Batch what can be batched. One quote call for forty instruments is one call; forty calls for one instrument each is forty.
Watch out — Idempotency is the defence. Generate your own unique identifier per intended order and attach it if the broker supports it. Without one, you cannot distinguish 'my request never arrived' from 'my request arrived and the response was lost' — and those two require opposite responses.
What is sandbox mode good for, and what does it hide?
Most brokers offer a paper or sandbox environment. It is genuinely useful for one thing and misleading about several.
Use it to prove your plumbing: that authentication works, that your payloads are shaped correctly, that your order state machine handles a rejection, that your reconnect logic runs. That is real value, and it costs nothing.
The honest ladder is therefore sandbox for correctness, then the smallest live size you can trade for realism, then size. Skipping the middle rung is how systems that passed every test lose money for reasons nobody wrote a test for. That move from a validated model to live orders is covered in From Backtest to Live Trading.
| What sandbox tests honestly | What it cannot tell you |
|---|---|
| Whether your request payload is valid | Whether you would have been filled at that price |
| Whether your token and session handling work | How much slippage a real book would impose |
| Whether you handle a rejection without crashing | How the order queue behaves at an opening or a circuit |
| Whether your reconnect and reconciliation run | Whether a real feed would have stalled at that moment |
| Whether your logging captures enough to debug | How you behave when real money is moving against you |
What actually goes wrong in production?
These are the failure modes that show up in real systems, in rough order of how often they cause damage. Every one of them is a plumbing failure, not a strategy failure.
- The token expired mid-session
- Reads keep working from cache, or fail quietly, and the first thing you notice is that an exit never went out. Detect authentication errors as a distinct class, refresh, and if refresh is impossible, alert loudly and stop opening anything new.
- The socket is connected but silent
- TCP holds the connection open while nothing arrives. Your last-known price freezes and your logic acts on a stale number. The fix is a heartbeat: if no message has arrived for longer than the market's quietest realistic gap, treat the feed as dead and reconnect.
- The reconnect gap
- A pushed stream sends what happens while you are attached. Everything during a 40-second reconnect is simply gone. After every reconnect, re-fetch positions, orders and funds over REST before acting on a single tick.
- Partial fills accumulating into a phantom position
- Covered above. Reconcile against the broker's own position and order book at start-up, after every reconnect, and at least once near the close.
- Duplicate orders from a retry
- A request times out, your code resends, both arrive. You are now twice the intended size with half the intended risk budget. Idempotency keys and a mandatory status check before any resend.
- A stale instrument identifier
- Contract identifiers change and are reused, most visibly around derivative expiries. An order routed on yesterday's identifier can be rejected, or worse, accepted for an instrument you did not mean. Refresh the master list daily.
- The clock drifted
- Candle boundaries, session windows and square-off timers all depend on your machine's time being right. Run NTP. A few seconds of drift near a session boundary produces decisions nobody can reconstruct afterwards.
What does a defensible integration look like?
Before any of this touches real money
- Secrets live in environment variables or a secrets manager — never in code, never committed, and rotated if they were ever pasted anywhere.
- The session is validated at start-up and the system refuses to open a position it could not currently close.
- One adapter file holds every broker-specific field name; the strategy never sees them.
- Position and order state are reconciled against the broker at start-up, after every reconnect and before the close.
- Every order carries a client-side identifier, and no placement is ever retried without a status check first.
- The feed has a heartbeat, and a stale feed halts new decisions rather than trading a frozen price.
- Rate-limit errors trigger exponential back-off with a cap, not an immediate retry.
- Every request, response and state transition is logged with a timestamp — you cannot debug a live session you did not record.
- A kill switch exists that flattens or halts, and you have tested it during market hours, not just read the code.
Note — This page is education, not advice, and it is not a recommendation of any broker or any automated system. Automating order placement adds engineering risk on top of market risk, and the losses from a plumbing bug are as real as the losses from a bad idea.
Key points
Pro tip — Before your system is allowed to place its first order of the day, make it run one self-check: is the session valid, does the broker's reported position match mine, is the master contract list from today, and has a tick arrived in the last few seconds? If any answer is no, it logs and stands down. Almost every expensive live-trading story starts with a system that skipped this and traded on a stale assumption.
Frequently asked questions
Which brokers in India offer a trading API?
Several SEBI-registered brokers publish one, including Zerodha, Dhan, Fyers, Angel One and Upstox. We do not rank or recommend brokers, and access terms, charges and technical limits differ and change — check each broker's own current documentation and terms before building anything against it.
Do I need a paid subscription to use a broker API in India?
Commercial terms vary by broker and change at their discretion, so any figure quoted in an article is likely to be stale. Look at the broker's current published terms directly. Note that data access and order-placement access are sometimes billed separately.
What is the difference between REST and WebSocket for market data?
REST is request-and-response: your program asks and gets one answer, and everything between two requests is invisible to it. A WebSocket is a persistent subscription the broker pushes updates down as they happen. Use REST for historical candles, account state and order placement; use a WebSocket for live prices and order updates. Most systems need both, because REST is also how you recover state after a socket drops.
Why does my broker API token expire every day?
Because a permanent token would be a permanent key to a live trading account. Most Indian brokers require a fresh interactive login, typically at the start of the trading day, which means your system must handle expiry as a planned event. The dangerous case is expiry while a position is open — the risk is not that you cannot enter, it is that you cannot exit.
Does an order API response mean my order was executed?
No. A successful response means the broker accepted the message. The order can still be rejected by risk checks or the exchange, sit unfilled, fill partially, or be cancelled with part of the quantity already traded. Your position must be computed as the running sum of fills read from the order or trade feed, never from placement responses.
What happens if I hit the broker's API rate limit?
You get a throttling error instead of data, and it usually arrives during volatility — exactly when your system is trying hardest and the broker is busiest. Back off exponentially rather than retrying immediately, batch quote requests, and prefer a pushed order-update stream over polling status. The specific limits are broker-specific and revised, so read the current documentation rather than a number from an article.
Is paper trading through a broker sandbox enough before going live?
It is enough to prove your plumbing — authentication, payload shapes, rejection handling, reconnect logic. It cannot tell you whether you would have been filled, what slippage a real order book would have imposed, or how the queue behaves at an opening or a circuit. Sandbox for correctness, then the smallest live size for realism, then size.