Zerodha Kite Connect API with Python: a Real Tutorial
The short answer
The Kite Connect API lets a Python program authenticate once a day, read market data, and place, modify, and cancel orders through Zerodha using the official kiteconnect client. You exchange an API key and secret for a daily access token through a login handshake, then call place_order for trades and stream live prices over the KiteTicker WebSocket. Since the SEBI framework dated 4 February 2025, automated orders above an order-frequency threshold count as algorithmic and must be tagged with an exchange algo ID through your broker.
A working Kite Connect integration is a small amount of code around one hard truth: the API will do exactly what you tell it, instantly, with real money, whether or not you meant it. This tutorial walks the full pipeline as code, developer setup and the auth handshake, instruments and market data, orders and their real states, the live tick stream, and the risk layer you have to build yourself. It ends where most tutorials do not begin: the SEBI algorithmic-trading rules that decide whether your script is even allowed to run as it grows.
Everything below uses the official Python client, installed with a single command. Keep the current Kite Connect documentation open alongside it, because rate limits, endpoint access packs, and the exact token lifetime are set by Zerodha and the exchanges and can change without changing this article.
pip install kiteconnect
The authentication handshake
Kite Connect does not accept a username and password from your code. It uses a browser login handshake that ends in a short-lived token, and it is the part first-time developers get wrong most often. There are three secrets in play and they are not interchangeable. The API key publicly identifies your app. The API secret proves you are its registered developer and is shown once at creation, so save it then. The access token is the daily session key that actually authorises trading calls.
The flow is a sequence. You generate a login URL and send the user to it. They log in on Zerodha's own page, which is where two-factor authentication happens, and Kite redirects back to your app with a one-time request_token in the query string. You then exchange that request token for an access token. Under the hood the client builds a SHA-256 checksum of the API key, the request token, and the API secret concatenated together, and posts it so Zerodha can verify the exchange came from you. In Python the client does the checksum for you inside generate_session.
generate_session. The token you receive is good for one trading day, which is why a live system needs a login step every morning.In code the handshake is short. The one part you must supply outside the snippet is capturing the request_token that Kite appends to your redirect URL, which in local development is often a loopback address you read from the browser.
from kiteconnect import KiteConnect
kite = KiteConnect(api_key="your_api_key")
# 1. Send the user to this URL in a browser.
print(kite.login_url())
# 2. Kite redirects to your redirect URL with ?request_token=...
# Capture that value, then exchange it (the client builds the
# SHA-256 checksum of api_key + request_token + api_secret for you):
data = kite.generate_session("request_token_from_redirect",
api_secret="your_api_secret")
access_token = data["access_token"]
kite.set_access_token(access_token) # signs every later call
Instruments and market data
Kite identifies every tradable contract by a numeric instrument_token, not by its trading symbol. The market-data and streaming endpoints speak in these tokens, so the first thing a real system does is download the instrument master with instruments(), which returns the full dump of symbols, tokens, exchanges, expiry, and lot size. You cache it once a day and look up the token for whatever you intend to trade. Symbols and tokens are refreshed by the exchange, so treat the dump as a daily artefact rather than a constant.
For prices you have two lanes. Snapshot reads over REST answer "what is it now": ltp() for the last traded price, ohlc() for the day's open, high, low, and close, and quote() for the fuller picture including depth. Historical candles come from historical_data(), which takes an instrument token, a date range, and an interval such as minute or day, and is the backbone of any backtest. Historical access is a paid add-on on the developer console and is separate from the basic connect subscription, so confirm your app is entitled before your backtest silently returns nothing.
# Look up a token from the daily instrument dump.
dump = kite.instruments("NSE")
token = next(i["instrument_token"] for i in dump
if i["tradingsymbol"] == "YOUR_SYMBOL")
# Snapshot reads (REST).
print(kite.ltp([f"NSE:YOUR_SYMBOL"])) # last traded price
print(kite.ohlc([f"NSE:YOUR_SYMBOL"])) # day OHLC
# Historical candles for a backtest (requires the historical-data pack).
candles = kite.historical_data(
instrument_token=token,
from_date="2026-06-01 09:15:00",
to_date="2026-06-30 15:30:00",
interval="minute",
)
That candle dataframe is where a strategy is actually decided, long before an order is ever sent. Turning raw candles into a tested edge is a discipline in itself, and the pandas backtesting walkthrough covers how to do it without fooling yourself with lookahead. That upstream research work is exactly what the method we teach is built around: the API is only the delivery mechanism for a decision you already trust.
Placing and managing orders
An order in Kite Connect is a set of enumerated choices, and the client exposes each as a constant so you do not hardcode strings. You pass a variety (the order class, for example a regular order), an exchange, a tradingsymbol, a transaction_type (buy or sell), a quantity, a product that decides how the position is treated, an order_type that decides how it is priced, and a validity. The parameters below are the ones you touch daily.
| Parameter | Common values | What it decides |
|---|---|---|
| variety | VARIETY_REGULAR, VARIETY_AMO, VARIETY_ICEBERG | The order class. Regular is the everyday order; AMO is after-market; iceberg slices a large order. |
| product | PRODUCT_MIS, PRODUCT_CNC, PRODUCT_NRML | MIS is intraday and auto-squared before close. CNC is delivery for equity. NRML carries derivatives positions. |
| order_type | ORDER_TYPE_MARKET, ORDER_TYPE_LIMIT, ORDER_TYPE_SL, ORDER_TYPE_SLM | Market fills now at the best price. Limit rests at your price. SL and SL-M are stop-triggered limit and market orders. |
| validity | VALIDITY_DAY, VALIDITY_IOC, VALIDITY_TTL | Day rests until close. IOC fills what it can immediately then cancels. TTL lives for a set number of minutes. |
# tradingsymbol is a placeholder. This is not advice to trade any instrument.
order_id = kite.place_order(
variety=kite.VARIETY_REGULAR,
exchange=kite.EXCHANGE_NSE,
tradingsymbol="YOUR_SYMBOL",
transaction_type=kite.TRANSACTION_TYPE_BUY,
quantity=1,
product=kite.PRODUCT_MIS, # intraday
order_type=kite.ORDER_TYPE_LIMIT,
price=your_limit_price, # a number you set
validity=kite.VALIDITY_DAY,
tag="strategy_v1", # your own label for reconciliation
)
Here is the single most important sentence in this tutorial: the returned order_id is not a fill. It confirms only that Zerodha's order management system accepted your request for processing. From there the order walks through a lifecycle, and each of those states is a different reality for your position. Treating "I got an order_id" as "I am in the trade" is how people end up with positions they did not know existed, or with duplicate orders after a timeout.
kite.order_history(order_id) returns the full state trail; kite.orders() lists the working set, kite.trades() the fills, and kite.positions() and kite.holdings() your book. For low latency, register the order postback so Zerodha pushes each state change to you instead of polling.Modifying and cancelling follow the same shape. kite.modify_order(variety, order_id, price=new_price) changes a resting order in place; kite.cancel_order(variety, order_id) pulls it. The tag you attached at placement earns its keep here: after a network timeout you can query for that tag and learn whether the order actually reached the exchange, instead of guessing and firing a duplicate.
Streaming live ticks with KiteTicker
REST reads are snapshots. To react to the market as it moves you need the push feed, and Kite delivers it over a WebSocket exposed as the KiteTicker class. You construct it with the API key and today's access token, register callbacks, subscribe to a list of instrument tokens, and pick a mode. LTP mode sends only the last price and is the lightest. Quote mode adds open, high, low, close, and volume. Full mode adds five levels of order-book depth. You choose the smallest mode that your strategy actually uses, because bandwidth and parsing cost scale with it.
from kiteconnect import KiteTicker
kws = KiteTicker("your_api_key", access_token)
def on_connect(ws, response):
ws.subscribe([token]) # instrument token, an int
ws.set_mode(ws.MODE_FULL, [token]) # LTP, QUOTE, or FULL
def on_ticks(ws, ticks):
for t in ticks:
handle_tick(t) # your strategy logic
def on_close(ws, code, reason):
# The socket WILL drop. Pause strategies and let reconnect run.
pause_all_strategies()
kws.on_connect = on_connect
kws.on_ticks = on_ticks
kws.on_close = on_close
kws.connect(threaded=True)
The scoop: SEBI's algo rules now sit on top of your code
This is the section that dates every generic Kite tutorial. Placing orders programmatically in India is no longer purely a technical question. SEBI issued a framework titled Safer participation of retail investors in Algorithmic trading on 4 February 2025, and it draws a bright line around exactly the kind of automated order flow this tutorial produces. The implementation timeline was extended through a September 2025 circular, with reporting pointing to full go-live around 1 April 2026. Because the phasing has already moved once, treat any single date as verify-before-relying and check the current SEBI and exchange circulars.
The core mechanic is a frequency line. Orders placed through a broker API are treated as algorithmic once they cross an order-per-second threshold, reported to be in the region of ten orders per second per client, at which point each order must carry a unique exchange-assigned algo ID. Below that line, an occasional API user placing manual-speed orders is generally not caught; above it, the flow is an algorithm in the regulator's eyes and must be registered and tagged. The exact number is set by the exchanges, so confirm it rather than hardcoding it into your risk logic.
Two more pieces matter for a developer. First, access hardening: the framework pushes brokers toward client-specific API keys, static or whitelisted IP addresses, and mandatory two-factor authentication, which is one reason the daily login handshake above cannot be shortcut. Second, the classification of the strategy itself. A white-box algo has transparent, reproducible logic, a readable Python strategy is usually this kind, while a black-box algo hides its logic and carries heavier scrutiny and documentation. The table below summarises the realities you should design around, every figure flagged as something to confirm against current circulars.
| Reality | What it means for your code | Status |
|---|---|---|
| Daily access token | Regenerate the token every trading day before the open; a stale token fails the first call. | Set by Zerodha; verify lifetime in the docs. |
| Order-rate threshold | Cross it and each order needs a unique exchange algo ID, tagged through the broker. | Reported near ten per second per client; exchange-set, verify. |
| Broker as principal | Your algo is empanelled and onboarded through the broker, not registered directly with the exchange. | Framework dated 4 Feb 2025; phased go-live, verify current date. |
| Access hardening | Expect client-specific keys, static or whitelisted IPs, and enforced two-factor login. | Per SEBI framework; confirm your broker's implementation. |
| Per-endpoint rate limits | Order, quote, and historical calls are capped separately; a breach is rejected, not queued. | Published by Zerodha; treat any number as verify-before-relying. |
The risk and kill-switch layer you build yourself
Nothing in the client stops your program from doing something catastrophic. The API is deliberately neutral, so the guardrails are yours to write, and this is the layer that separates a script from a system. Its whole purpose is to survive the failure modes that are unique to automation: a token that expired mid-session, a WebSocket feeding old prices, a rate-limit rejection mistaken for a transient blip, and above all a retry that turns one intended order into several real ones.
At minimum, a live retail setup wraps every outbound call in a token-bucket rate limiter per endpoint category, so it backs off instead of tripping limits. It refuses to retry any write, place, modify, or cancel, without first reading the current state, because a blind retry after a timeout is the fastest way to double a position. It carries a hard cap on orders per minute and on total exposure that the strategy cannot override. And it has a kill switch: a single, non-overridable control that halts all new orders and, if configured, flattens open positions, triggered either by a monitored loss limit or by a human.
# The smallest useful guard: a manual, non-overridable kill switch.
class KillSwitch:
def __init__(self):
self._tripped = False
def trip(self, reason):
self._tripped = True
log.critical("KILL SWITCH: %s", reason)
def guard(self):
if self._tripped:
raise RuntimeError("kill switch engaged, orders blocked")
kill = KillSwitch()
def safe_place(**params):
kill.guard() # blocks if engaged
limiter.acquire("orders") # per-endpoint token bucket
return kite.place_order(**params) # only now touch the broker
Where this sits in a real workflow
Put the pieces in order and the pipeline is coherent: authenticate for the day, load the instrument dump, pull historical candles to drive a strategy you have already tested, place orders through the guarded wrapper, confirm every outcome by reading state back, stream live ticks over KiteTicker to react, and register the whole thing as an algo with your broker once its order rate warrants it. The API is a few dozen method calls. The engineering is everything wrapped around them, and the regulation now sits on top of both.
If you are building this to learn rather than to reach a specific target overnight, sequence it: paper-trade the logic, add the risk layer before real capital, and read the current circulars before you scale order rate. That progression, research first, execution second, compliance throughout, is the spine of the broader algorithmic-trading path in India and of how to start algo trading here without skipping the steps that protect your account.
Frequently asked questions
How does Kite Connect authentication work in Python?
+You register an app to get an API key and secret, then call login_url() and send the user there. After login, Kite redirects back with a request_token in the query string. You pass that token and your secret to generate_session(), which the client uses to build a SHA-256 checksum of api_key plus request_token plus api_secret, POST it, and return a fresh access_token. You set that token with set_access_token(), and it signs every later request until it expires the next morning.
How long does a Kite Connect access token last?
+An access token is a single-day session token. Zerodha documents it as valid until the start of the next trading day, after which it is invalidated and any call using it returns a token error. A live system therefore needs a login step every morning before the market opens, either run by hand or automated with a scripted two-factor login. Treat token regeneration as a daily prerequisite, not an occasional refresh, and verify the current expiry behaviour against the official documentation.
What does place_order return and does it mean the order filled?
+place_order returns an order_id, which only confirms that the order management system accepted your request for processing. It is not a fill and not even an exchange acknowledgement. The order then moves through states such as validation pending, open, and finally complete, cancelled, or rejected. You must confirm the outcome separately by reading order_history(order_id) or by listening to the order postback stream. Assuming a returned order_id means execution is the classic beginner mistake.
Do I need SEBI algo registration to trade through the Kite API?
+Under the SEBI framework dated 4 February 2025, automated orders placed through a broker API above an order-frequency threshold are treated as algorithmic and must be tagged with a unique exchange algo ID, registered through the broker. Reporting put the threshold near ten orders per second per client, but the exact number and go-live are exchange and broker set, so verify current limits before relying on them. Your broker is the principal who empanels and tags the algo; you cannot register directly with the exchange.
What is the difference between a white-box and a black-box algo under the rules?
+The framework distinguishes algos by whether their logic is transparent to the user. A white-box or execution algo has fully visible, reproducible logic, such as a simple time-sliced or price-limit execution, and carries a lighter registration path. A black-box algo hides its logic and faces stricter scrutiny and additional documentation obligations. A retail developer writing an open, readable strategy in Python is normally building the white-box kind, but the classification and its obligations are set by the exchange and broker.
How do I get live tick data from Kite Connect?
+Live ticks come from the KiteTicker WebSocket, not the REST endpoints. You create a KiteTicker with your API key and access token, attach on_connect and on_ticks callbacks, subscribe to a list of instrument tokens, and choose a mode. LTP mode sends only the last price, quote mode adds open, high, low, close and volume, and full mode adds five levels of market depth. The stream can drop, so you must handle disconnects, resubscribe on reconnect, and reconcile state before you trust it again.
How do I place, modify, and cancel orders with the Python client?
+You call place_order with a variety, exchange, tradingsymbol, transaction_type, quantity, product, order_type, and validity, and it returns an order_id. To change a resting order you call modify_order with the same variety and that order_id plus the fields you want to update, such as price or quantity. To pull an order you call cancel_order with the variety and order_id. You inspect the working set with orders(), the fills with trades(), and your book with positions() and holdings().
Why does API trading add operational risk over manual trading?
+Because code fires without hesitation. A manual trader who sees a wrong price pauses; a loop that misreads a tick or catches an error and retries can place many wrong orders in seconds. The failure modes are software failure modes: a stale token, a dropped WebSocket feeding old prices, a rate-limit rejection mistaken for a network blip, or a retry that duplicates a live order. This is why a self-built risk layer, a hard order cap, and a kill switch matter more than the strategy itself.
What are the Kite Connect rate limits and how do I stay inside them?
+Kite Connect applies per-endpoint request limits, with order placement, quote reads, and historical reads each capped separately, and exceeding a limit returns a rejection rather than a queue. Published numbers change, so treat any specific figure as current-verify and read the official documentation before trusting it. In practice you wrap outbound calls in a token-bucket limiter per endpoint category, back off on a rejection instead of hammering, and never retry a write blindly, since a duplicate order is worse than a delayed one.
Where the facts come from
- SEBI, Safer participation of retail investors in Algorithmic trading (4 February 2025). The circular that treats API orders above a frequency threshold as algorithmic and requires unique exchange algo IDs, broker empanelment, and hardened API access. sebi.gov.in
- SEBI, Extension of timeline for the algo trading framework (September 2025). Establishes that the implementation was phased and pushed out, which is why the go-live date should be verified against current circulars. sebi.gov.in
- Kite Connect v3 API documentation. The authoritative reference for the auth handshake, endpoints, order parameters, and current rate limits. kite.trade/docs/connect/v3
- pykiteconnect, the official Python client. Source and reference for KiteConnect and KiteTicker method names, constants, and behaviour used throughout this tutorial. github.com/zerodha/pykiteconnect
Related guides
Ready to go deeper than this article?
Bharath Shiksha is a 30-volume curriculum across 6 stages, from chart reading at ₹14,999 through research-to-production and live deployment, or the full bundle at ₹1,49,999. Every volume has a companion worksheet, a gate quiz, and a 7-day money-back guarantee. Start with a free diagnostic to see where you sit.
Take the free diagnostic →