NineFifteenAM

Pillar guide · updated monthly

How to place your first order with the Kite Connect API in Python

6 min readBy NineFifteenAM

Place, check and cancel your first order with Zerodha's Kite Connect API in Python, after rehearsing it in a paper mode that sends nothing to the exchange.

Short answer

Install the kiteconnect library, log in to get the day's access token, whitelist a static IP for your developer account, and call kite.place_order() with the exchange, symbol, side, quantity, product and order type. The call returns an order ID, not a fill, so always check the order's status afterwards. Use limit orders to start: market orders placed through the API must carry market protection or they are rejected. Run everything in a paper mode first that logs what it would have sent.

Placing an order through Kite Connect is one function call. Knowing whether it actually filled is where most first scripts go wrong. By the end of this guide you'll have placed, checked and cancelled one real order, after rehearsing it in a paper mode that sends nothing.

Kite Connect has no public sandbox. Every order the API sends is real. That's why the paper mode comes first.

Before you start

You need Why
A Kite Connect app (API key and secret) Identifies your code. Free on the Personal plan.
Today's access token Expires at 6 AM every day. Getting the API key and refreshing the token covers it.
A whitelisted static IP Order requests from any other IP are rejected. Add it under Profile → IP Whitelist in the developer console. You can add up to two, and change them once a week.
The Connect plan (₹500/month) Needed for the paper mode below, which calls kite.ltp() for live prices. On the free plan, pass the price in by hand instead.

Install the library:

pip install kiteconnect

Step 1: Connect with today's token

from kiteconnect import KiteConnect

kite = KiteConnect(api_key="YOUR_API_KEY")
kite.set_access_token("TODAYS_ACCESS_TOKEN")

print(kite.profile()["user_name"])  # quick check that the token works

Keep the key, secret and token out of your code in real use. Environment variables or a file outside your repository are the usual options.

Step 2: Know the order parameters

These are the fields place_order() needs, from the Kite Connect orders documentation:

Parameter Common values What it means
variety regular, amo A normal order, or an after-market order queued for the next session
exchange NSE, BSE, NFO Cash market, or futures and options (NFO)
tradingsymbol INFY, NIFTY26OCT25000CE Exact symbol from the instruments list
transaction_type BUY, SELL Side
quantity 1 Shares, or units for F&O (a multiple of the lot size)
product CNC, MIS, NRML Delivery, intraday, or carry-forward F&O
order_type LIMIT, MARKET, SL, SL-M How the order is priced
price 1450.5 Your limit price (for LIMIT and SL)
trigger_price 1440 Trigger for stop-loss orders
validity DAY, IOC How long the order stays open
tag first-order Your own label, up to 20 characters, handy for matching orders to your logs
market_protection -1 or a percentage Required on MARKET and SL-M orders sent through the API

Start with LIMIT orders. Since the SEBI retail algo rules came in, market orders placed through the API must carry market protection, and an order without it is rejected with a message along the lines of "Market orders without market protection are not allowed via API". Some versions of the Python library on PyPI shipped without the market_protection argument, so a limit order is also the simplest way to avoid that problem.

Step 3: Build a paper mode first

The idea is simple: one function that everything in your code calls to place an order. In paper mode it records what it would have sent, with a simulated fill at the current price. In live mode it sends the order.

import datetime as dt
import json
import uuid

PAPER = True  # flip to False only when you're ready


def place(kite, symbol, side, qty, price, exchange="NSE", product="CNC", tag="first-order"):
    order = dict(
        variety=kite.VARIETY_REGULAR,
        exchange=exchange,
        tradingsymbol=symbol,
        transaction_type=side,
        quantity=qty,
        product=product,
        order_type=kite.ORDER_TYPE_LIMIT,
        price=price,
        validity=kite.VALIDITY_DAY,
        tag=tag,
    )

    if PAPER:
        ltp = kite.ltp([f"{exchange}:{symbol}"])[f"{exchange}:{symbol}"]["last_price"]
        # A buy limit fills only if the market is at or below your price, and vice versa.
        fills = (side == "BUY" and ltp <= price) or (side == "SELL" and ltp >= price)
        record = {
            "time": dt.datetime.now().isoformat(timespec="seconds"),
            "mode": "paper",
            "order_id": "PAPER-" + uuid.uuid4().hex[:8],
            "order": order,
            "ltp": ltp,
            "status": "COMPLETE" if fills else "OPEN",
            "fill_price": ltp if fills else None,
        }
        print(json.dumps(record, indent=2))
        return record["order_id"]

    order_id = kite.place_order(**order)
    print("sent live order", order_id)
    return order_id

Run it a few times in paper mode:

place(kite, "INFY", "BUY", 1, price=1400.0)

INFY here is only a placeholder for any liquid symbol.

Look at what it prints. Is the symbol right? The quantity? The product? Would a buy at that price fill right now? Most mistakes show up here, where they cost nothing.

A paper fill at the last traded price is kinder than reality. A real order meets the other side of the order book, and on a fast-moving option that gap can be large. More on that in paper trading vs live trading.

Step 4: Send one real order

When the paper output looks right, set PAPER = False and place the smallest possible order. For a first test, a limit price a little away from the market is useful: the order will sit open, which lets you practise checking and cancelling it without buying anything.

from kiteconnect import exceptions as kex

try:
    order_id = place(kite, "INFY", "BUY", 1, price=1300.0)
except kex.InputException as e:
    print("bad parameters:", e)       # wrong symbol, quantity, price, etc.
except kex.TokenException as e:
    print("token expired, log in again:", e)
except kex.NetworkException as e:
    print("network or rate limit:", e)  # don't blindly retry an order
except kex.OrderException as e:
    print("order rejected:", e)

If any exception fired, stop here and look at the order book in Kite before going further. The steps below assume you have an order_id.

One warning on retries: if the call times out, the order may still have reached Zerodha. Check the order book before sending it again, or you can end up with two orders.

Step 5: Check what actually happened

place_order() returns an order ID. That means Zerodha accepted the request, nothing more. The order can still be rejected by margin or risk checks, sit open, or fill in parts.

history = kite.order_history(order_id)
latest = history[-1]
print(latest["status"], latest.get("status_message"))
print("filled", latest["filled_quantity"], "of", latest["quantity"], "at", latest["average_price"])

The statuses you'll see most:

Status Meaning
OPEN Waiting at the exchange
COMPLETE Fully filled
REJECTED Refused; status_message says why
CANCELLED Cancelled by you or by the system
TRIGGER PENDING A stop-loss order waiting for its trigger

For a running system, polling is the slow way. The Kite websocket also sends order updates as they happen, which is how most bots track fills.

Step 6: Cancel it

kite.cancel_order(variety=kite.VARIETY_REGULAR, order_id=order_id)
print(kite.order_history(order_id)[-1]["status"])  # CANCELLED

You've now placed, checked and cancelled a real order through the API. Everything else in automated trading is built on these three calls.

Limits worth knowing on day one

The full list of costs and limits is in Zerodha Kite Connect: what it costs and whether it's worth it.

Stay safe

Sources

This guide explains how a broker API works, for information only. It is not investment advice or a recommendation to buy or sell any security. I am not registered with SEBI as an investment adviser or research analyst.

Questions people ask me

Do I need the paid Kite Connect plan to place orders?

No. The free Personal plan lets you place, modify and cancel orders and read your positions and holdings. You need the ₹500/month Connect plan only for live prices and historical data, which a paper mode usually needs to simulate fills.

Why was my API order rejected with an IP error?

Order requests must come from a static IP address you have whitelisted in your Kite Connect developer profile. Requests from any other IP are rejected. Reading data, positions and the order book works from any IP.

Why is my market order rejected through the API?

Market orders, including SL-M orders, sent through the API need market protection, which caps how far from the current price the order can fill. Set the market_protection parameter or use a limit order. Some versions of the Python library on PyPI did not yet include the parameter, so check your version.

Does place_order mean my order was filled?

No. It only means Zerodha accepted the request and gave it an order ID. The order can still be rejected by risk checks or the exchange, sit open, or fill in parts. Check its status with order_history() or listen for order updates on the websocket.

Does Zerodha have a sandbox or test environment for Kite Connect?

There is no public sandbox for Kite Connect, so every order you send is real. That is why it's worth building a paper mode into your own code first.

How do I place an options order through Kite Connect?

Use exchange NFO, the exact trading symbol from the instruments list (for example a Nifty weekly option), product NRML or MIS, and a quantity in multiples of the lot size, which is 65 for Nifty. Everything else works the same as a stock order.

zerodhakite connectpythonplace orderpaper tradinggetting started
N

NineFifteenAM

One trader building an options bot for Indian index markets since early 2026. I write down how it is built, what broke, and what it cost — no tips, no calls, no returns.

Related

27 Sept 2026
Zerodha Kite Connect: get your API key and refresh the token dailyA short, practical guide to getting a Kite Connect API key and handling the access token that expires every morning.
Guides
29 Sept 2026
Zerodha Kite Connect: what it costs and whether it's worth itWhat Kite Connect costs in 2026, what the free and ₹500 plans include, the rate and data limits you'll hit, and who the paid plan is worth it for.
Guides
29 Sept 2026
How to backtest an intraday strategy without fooling yourselfThe three ways a backtest lies: lookahead bias, ignored costs and overfitting. With pandas code, a coin-flip simulation, and a 68% backtest that won 20% live.
Guides