Open SAHI web, click your profile avatar (bottom left) → API Dashboard → Create API key.
Enter a Name, e.g. Trading bot.
Choose the Access: Full access (orders + market data) or Market data (data only).
Choose the Key type. Regular: you click Approve in the dashboard every trading day. TOTP: a code from an authenticator app approves it, so a scheduled bot runs without you.
Regular: click Create API key. TOTP: click Continue, scan the QR with Google Authenticator (or copy the Setup key), enter the 6-digit code, then Create API key. Save the setup key with your other secrets. You have 10 minutes; nothing is created until the code is accepted.
Copy the API key (pk_…) and API secret (sahi_sk_…) into your secret store. Tick I have saved my credentials → Done. The secret is shown only once.
Good to know: you can hold up to 5 keys. Deleting a key stops every token minted from it at once.
On the machine that will place orders, find its public IP:
terminal
curl https://checkip.amazonaws.com
In the API Dashboard, click Add static IP, enter it as the Primary IP address, click Save IP address, check the review screen and Confirm & Lock for 7 days. Secondary is optional: a backup line, not a second bot.
Good to know: use a fixed IP (cloud VM or static broadband); home and mobile IPs change. One IP belongs to one SAHI account. A slot stays locked for 7 days even if you delete the IP.
Install from PyPI (Python 3.9 or newer; use pip3 if pip is not found). TOTP keys need sahiapi 0.3.0 or newer. Add pyotp if your bot runs unattended.
terminal
pip install sahiapi pyotp
Save this as hello.py, replace the placeholders, run python3 hello.py.
hello.py · Regular key
from sahiapi import SahiAPI
api = SahiAPI.from_credentials(
key_id="pk_...",
secret="sahi_sk_...",
)
print(api.get_profile())
hello.py · TOTP key
import pyotp
from sahiapi import SahiAPI
api = SahiAPI.from_credentials(
key_id="pk_...",
secret="sahi_sk_...",
totp=pyotp.TOTP("YOUR_SETUP_KEY").now(), # or type the 6 digits from your app: totp="042917"
)
print(api.get_profile())
You should see your profile. The token lasts until 6 AM IST, so sign in once a day. If you see SahiKeyNotApprovedException → approve the key (Step 5). SahiAuthenticationException → wrong key id or secret. SahiInvalidTotpException → wrong code; check the machine's clock.
Exchange your key for an access token (valid until 6 AM IST). Minting uses apis.sahi.com; every other call uses direct.sahi.com.
terminal · Regular key
curl -X POST https://apis.sahi.com/api/v1/apikeys/token \
-H "Content-Type: application/json" \
-d '{"key_id":"pk_your_key_id","secret":"sahi_sk_your_secret","totp":"042917"}'
# totp = the 6 digits your authenticator app shows right now (as a string)
Put the access_token value in a variable and send it on every call:
terminal
You should see your profile. Mint once a day. If you see 403 Forbidden on mint → approve the key (Step 5). 401 Unauthorized → wrong key id or secret. 401 InvalidTotp → wrong code; check the machine's clock.
Prices are in paise (divide by 100); quantities are in units.
Find your instrument. Market data uses instrument_id; orders use exchange_segment + symbol. Both come from the scrip master, which the SDK downloads for you.
hello.py · continued
curl -O https://assets.sahi.com/external/instruments.csv # rebuilt daily
grep ',RELIANCE,' instruments.csv | grep ',NSE,NSE,' # first column is the id → 12027
Get its last traded price.hello.py · continued
quote = api.get_quotes(instrument_id)["data"][str(instrument_id)] # keyed by the id as a string
print(quote["last_trade_price"] / 100, "INR")
Place your first order during market hours (09:15–15:30 IST). This is a real order: a limit buy of 1 share at the bottom of the day's price band, so it rests unfilled. The script cancels it if it has not filled.Cancel it with the last command.hello.py · continued
import time
price = quote["dpr_lower"] # paise; bottom of the day's band
if api.get_funds()["available"]["stocks_delivery"] < price:
raise SystemExit("not enough funds for one share")
result = api.place_order(
exchange_segment=SahiAPI.EXCHANGE_SEGMENT_NSE,
symbol="RELIANCE",
txn_type=SahiAPI.TXN_TYPE_BUY,
qty=1,
order_type=SahiAPI.ORDER_TYPE_LIMIT,
product=SahiAPI.PRODUCT_DELIVERY,
validity=SahiAPI.VALIDITY_DAY,
price=price,
)
order_id = result["order_ids"][0]
time.sleep(1) # the order takes a moment to reach the book
status = api.get_order_detail(order_id)["status"]
print(status) # Open, or Rejected with rejection_reason
if status in (SahiAPI.ORDER_STATUS_OPEN, SahiAPI.ORDER_STATUS_OPEN_PARTIAL):
api.cancel_order(order_id) # not filled yet
terminal
# a) Day's price band (paise): dpr_lower / dpr_upper in the quote
curl "https://direct.sahi.com/v1/marketdata/quotes?i=12027" -H "Authorization: Bearer $TOKEN"
# b) Limit buy, 1 share, at dpr_lower (replace the price)
curl -X POST https://direct.sahi.com/v1/orders \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"exchange_segment":"NSE","symbol":"RELIANCE","txn_type":"B","qty":1,
"order_type":"LMT","product":"C","validity":"DAY","price":249000}'
# → {"order_ids":["2610…"]}# c) Check it (status: Open, or Rejected + rejection_reason), then cancel it
curl https://direct.sahi.com/v1/orders/ORDER_ID -H "Authorization: Bearer $TOKEN"
curl -X DELETE https://direct.sahi.com/v1/orders/ORDER_ID -H "Authorization: Bearer $TOKEN"
An order id means accepted, not placed: check status. SahiIpNotAllowedException403 IP_NOT_ALLOWED → your IP isn't registered (Step 2).
View your positions and orders.hello.py · continued
for p in api.get_positions()["positions"]:
print(p["instrument_id"], p["net_qty"], p["net_avg_price"] / 100, p["realised_pnl"] / 100)
for o in api.get_order_list()["orders"]: # today's order book
print(o["order_id"], o["symbol"], o["status"], o["filled_qty"])
terminal
curl https://direct.sahi.com/v1/positions -H "Authorization: Bearer $TOKEN" # net_qty, net_avg_price, realised_pnl
curl https://direct.sahi.com/v1/orders -H "Authorization: Bearer $TOKEN" # today's order book
Also: api.get_holdings(), api.modify_order(), and SahiFeed for live ticks. See the SDK docs.Also: GET /v1/holdings, PUT /v1/orders/{id} to modify, and the WebSocket streams for live ticks. See the API reference.
Regular key: open the API Dashboard after 6 AM IST. The key shows Expired; click Approve and it changes to Resets 6 AM tomorrow. A key created today is already approved.TOTP key: nothing to do here; it shows Active. The code you send when signing in approves it.
Sign in once (Step 3) and reuse the token until 6 AM IST.
If orders fail with 403 IP_NOT_ALLOWED, your public IP has changed. The slot is locked for 7 days, so add the new IP as Secondary, or write to developers@sahi.com.
Approve a Regular key · Expired → Approve → Resets 6 AM tomorrow