Skip to main content

Stolo API authentication

Stolo API authentication is a two-step handshake. You exchange your app key and secret for a bearer token once a day, then send that token with every other request. The secret never needs to leave the place you authenticate from.

Getting your key and secret​

Your key and secret come from the API app in your Stolo account. Open the API App page (Account > API App in the Stolo app) and:

  • If you don't have an app yet, enter a name and press Create app. The key and secret are ready to copy immediately.
  • If you already have one, copy the key and the secret from there.

Each account has one app. The same page is where you regenerate the secret if it leaks, or delete the app to cut off access completely.

Get your app key and secret

Create your API app in a few seconds, or copy the credentials of the one you already have.

Open the API App page

POST /authenticate​

Exchanges an app key and secret for a token. This is the only endpoint that doesn't take a token. It isn't rate limited and isn't metered in Stolo Tokens.

Request body​

FieldTypeRequiredDescription
keystringYesYour app key, from the API App page
secretstringYesYour app secret
curl -X POST 'https://algoapi.stolo.in/v1/authenticate' \
-H 'Content-Type: application/json' \
-d '{"key":"YOUR_APP_KEY","secret":"YOUR_APP_SECRET"}'

Response​

{
"status": "success",
"message": "",
"response_meta": { "api_version": "v1", "message": "", "elapsed_time": "4.12ms" },
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 37800
}
}
FieldTypeDescription
data.tokenstringThe bearer token to send on every other call
data.expires_innumberSeconds from now until the token expires (at the next 5 AM IST)

Errors​

HTTPmessageCause
401Invalid App Key or SecretThe key doesn't exist, or the secret doesn't match it
403Active stolo-pro or Stolo Trial 15 days plan required to use this APIThe account that owns the app has no active Stolo Pro or Stolo Trial (15 days) plan
422Validation failedkey or secret is missing or empty. data lists which one

Sending the token​

Put the token in the Authorization header of every request except /authenticate:

GET /v1/analysis/option-chain?symbol=NIFTY HTTP/1.1
Host: algoapi.stolo.in
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

The Bearer prefix is optional; the bare token works too.

Token lifetime: always 5 AM IST​

A token doesn't last a fixed number of hours. It always expires at the next 5 AM IST, whenever you asked for it:

Authenticated atExpires atValid for
8:30 AM Monday5:00 AM Tuesday20.5 hours
6:30 PM Monday5:00 AM Tuesday10.5 hours
4:00 AM Tuesday5:00 AM Tuesday1 hour

So expires_in changes with the time of day. Don't hardcode 86,400. The simplest rule: authenticate once before the market opens and reuse that token for the whole session.

One token per app​

Each app has exactly one valid token at a time. Calling /authenticate again issues a new token and immediately invalidates the old one, even if it hasn't expired. Any process still holding the old token gets:

{ "status": "error", "message": "Token no longer valid, please re-authenticate", "data": null, "response_meta": { "...": "..." } }

This catches people out in two ways:

  • Authenticating on every request. Each call kills the token another request is still using. Cache the token and reuse it.
  • Several scripts on one key. Your scanner authenticates at 9:10 AM, your execution script authenticates at 9:12 AM, and the scanner starts failing with 401. Each account has one app, so authenticate in one place and share the token.

Plan checks on every request​

Holding a valid token isn't enough on its own. On every request, Stolo re-checks that the app's owner still has an active Stolo Pro or Stolo Trial (15 days) plan. If the plan lapses mid-day, the next call returns 403 with Active stolo-pro or Stolo Trial 15 days plan required to use this API even though the token is still valid. Renewing the plan fixes it immediately, no re-authentication needed.

Handling 401s in your code​

messageWhat happenedWhat to do
No auth token suppliedThe Authorization header is missing or emptySend the header
Invalid or expired tokenThe token is malformed, signed for something else, or past 5 AM ISTAuthenticate again
Token no longer valid, please re-authenticateSomeone called /authenticate with this key after you didAuthenticate again, then find the other caller

A good pattern is to re-authenticate once on a 401 and retry the request. If the retry also fails with 401, stop and alert. Two processes fighting over the same key will otherwise keep invalidating each other.

def call(method, path, data):
global token
# GET endpoints (analysis) take query params; POST endpoints take a JSON body.
fields = {"params": data} if method == "GET" else {"json": data}
res = session.request(method, BASE + path, headers={"Authorization": f"Bearer {token}"}, **fields)
if res.status_code == 401:
token = authenticate() # one retry only
res = session.request(method, BASE + path, headers={"Authorization": f"Bearer {token}"}, **fields)
return res
Keep the secret out of the browser

The app secret is effectively your account's API password. Keep it on a server or in a local environment variable, never in front-end code or a public repository. If it leaks, regenerate it on the API App page. The old secret and any token issued with it stop working immediately, and your app key stays the same.