How I Connected My Application to the Kite API

A working walkthrough of the Kite Connect handshake — app registration, login flow, session generation, and your first live calls.

The first time I opened Zerodha's Kite Connect docs, the login flow felt like more ceremony than it needed to be — an app key, a secret, a redirect, a checksum, a token exchange, all before you can even ask "what's in my portfolio?" Once I actually wired it end to end, though, it turned out to be a handful of well-defined steps, each with one job. Here's the exact path I took, with the code for every action along the way.

01Register an app on the developer console

Everything starts at the Kite Connect developer console. You'll need an active Kite Connect subscription tied to your Zerodha account. Create a new app and fill in:

  • Redirect URL — where Zerodha sends the user back after login (this can be a local URL like http://localhost:5000/callback while you're developing).
  • App type — usually "Connect" for a personal trading app.

Once approved, you get two values you'll use constantly: an API key and an API secret. Treat the secret like a password — it never leaves your server.

02Install the SDK

Zerodha maintains an official Python SDK that wraps the raw REST endpoints, so I skipped hand-rolling HTTP calls.

pip install kiteconnect

03Build the login URL

Kite Connect uses a browser-based login — your app can't just POST a username and password. Instead, you generate a login URL, send the user to it, and Zerodha handles authentication on their end.

from kiteconnect import KiteConnect

kite = KiteConnect(api_key="your_api_key")
print(kite.login_url())

Opening that URL prompts the familiar Zerodha login + two-factor screen. This is also the step where, if you're building for yourself rather than end users, you'll just open it in your own browser once per session.

04Capture the request token from the redirect

After a successful login, Zerodha redirects the browser to the Redirect URL you registered, appending a request_token as a query parameter:

http://localhost:5000/callback?request_token=abc123xyz&action=login&status=success

If your redirect URL is a real server route, a minimal Flask handler is enough to grab it:

from flask import Flask, request

app = Flask(__name__)

@app.route("/callback")
def callback():
    request_token = request.args.get("request_token")
    # hand this off to the session-generation step
    return f"Received token: {request_token}"
Note: the request token is short-lived — it's only valid for a few minutes and can only be exchanged once, so this step and the next one should happen back to back.

05Exchange the request token for an access token

This is the actual handshake — trading the temporary request token, along with your API secret, for a longer-lived access token that authorizes every subsequent call.

data = kite.generate_session(
    request_token,
    api_secret="your_api_secret"
)

access_token = data["access_token"]
kite.set_access_token(access_token)

Under the hood, the SDK computes a SHA-256 checksum of the API key, request token, and secret, and posts it to Zerodha's token endpoint — so you never have to build that yourself.

06Store the access token so you're not logging in every run

The access token is valid until the next trading day's early-morning reset, so I cache it instead of regenerating a session on every script run.

import os

os.environ["KITE_ACCESS_TOKEN"] = access_token

# on the next run
kite.set_access_token(os.environ["KITE_ACCESS_TOKEN"])

For anything beyond a personal script, swap the environment variable for a small encrypted store or secrets manager rather than a plaintext file.

07Make your first authenticated call

With the access token set, the client is live. A profile check is the simplest way to confirm the whole chain worked:

profile = kite.profile()
print(profile["user_name"], profile["email"])

08Pull real portfolio data

From here, the rest of the SDK opens up — holdings, positions, and order history all follow the same pattern of one method call returning structured JSON.

holdings = kite.holdings()
for h in holdings:
    print(h["tradingsymbol"], h["quantity"], h["average_price"])

positions = kite.positions()
print(positions["net"])

09Placing an order

Order placement uses the same authenticated client, but it's the one call where a typo has real consequences, so I always test with a small quantity first.

order_id = kite.place_order(
    variety=kite.VARIETY_REGULAR,
    exchange=kite.EXCHANGE_NSE,
    tradingsymbol="INFY",
    transaction_type=kite.TRANSACTION_TYPE_BUY,
    quantity=1,
    order_type=kite.ORDER_TYPE_MARKET,
    product=kite.PRODUCT_CNC
)
print("Order placed, id:", order_id)
Careful: this hits the live market once your app is out of sandbox mode. Confirm product, exchange, and transaction_type match your intent before running it against a real account.

Gotchas I ran into

  • Daily re-authentication — the access token expires around the market's early-morning reset, so any scheduled script needs a way to refresh the session rather than assuming yesterday's token still works.
  • Rate limits — Kite Connect enforces per-second and per-day request caps; batching quote lookups instead of looping one symbol at a time avoids hitting them.
  • Redirect URL mismatches — the URL you registered on the developer console has to match exactly (including trailing slashes) with what your app uses, or the login redirect silently fails.

Once the session handshake is automated, the rest of Kite Connect is genuinely pleasant to build on — the SDK's method names map closely to what you'd expect, and the JSON responses are clean enough to drop straight into a pandas DataFrame if you're doing any analysis on top.