Skip to content
Back to App

Authentication

The TopStep Simulator API uses bearer token authentication. You generate an API key in the TestMax web app, exchange it for a token via the Auth/loginKey endpoint, and then include that token in every subsequent request.

Authentication flow

  1. Generate an API key

    Log into test-max.com and navigate to Settings > API Access (a Pro feature). Generate your key and copy it immediately — it will not be shown again. Each account has a single API key; generating a new one replaces the old key.

  2. Exchange the API key for a token

    Call POST Auth/loginKey with your email address and API key. The response contains a bearer token.

  3. Include the token in all requests

    Pass the token in the Authorization header:

    Authorization: Bearer <your-token>
  4. Refresh or validate as needed

    Tokens expire after 24 hours. Use POST Auth/validate to exchange a valid token for a fresh one, and POST Auth/logout to invalidate a token when done.


POST Auth/loginKey

Authenticate with your email address and API key to receive a bearer token.

URL: POST /api/topstep-sim/Auth/loginKey

Request body

{
"userName": "your@email.com",
"apiKey": "your-api-key-here"
}
FieldTypeRequiredDescription
userNamestringYesYour TestMax account email address
apiKeystringYesThe API key generated in Settings

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null,
"token": "sim_4f8a2b1c9d3e..."
}
FieldTypeDescription
tokenstringBearer token to use in subsequent requests. Valid for 24 hours.

Example

import urllib.request
import json
API_URL = "https://api.test-max.com/api/topstep-sim"
# Step 1: Authenticate
login_data = json.dumps({
"userName": "your@email.com",
"apiKey": "your-api-key-here"
}).encode()
req = urllib.request.Request(
f"{API_URL}/Auth/loginKey",
data=login_data,
headers={"Content-Type": "application/json"}
)
resp = json.loads(urllib.request.urlopen(req).read())
if resp["success"]:
token = resp["token"]
print(f"Authenticated. Token: {token[:20]}...")
else:
print(f"Login failed: {resp['errorMessage']}")

Error responses

ScenarioerrorCodeerrorMessage
Invalid, missing, or revoked credentials3"Invalid credentials"
Account is not on a Pro plan9"Pro subscription required for TopStep Simulator API"
Too many login attemptsHTTP 429"Too many requests" (with a Retry-After header)

All credential failures — wrong key, unknown email, unverified email, or a disabled account — return the same "Invalid credentials" response, so the endpoint cannot be used to probe which accounts exist.


POST Auth/validate

Validate an existing token. On success the old token is rotated: the response carries a fresh token in the newToken field, and you should use it for all subsequent requests.

URL: POST /api/topstep-sim/Auth/validate

Request headers

Authorization: Bearer <your-token>
Content-Type: application/json

Request body

{}

An empty JSON body is required.

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null,
"newToken": "sim_7c2d9e0f1a4b..."
}
FieldTypeDescription
newTokenstringA fresh token replacing the one you sent. Valid for 24 hours.

If the token you sent is invalid or expired, the response is {"success": false, "errorCode": 1, "errorMessage": "Invalid session", "newToken": null} — re-authenticate with Auth/loginKey.

Example

req = urllib.request.Request(
f"{API_URL}/Auth/validate",
data=b"{}",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
)
resp = json.loads(urllib.request.urlopen(req).read())
if resp["success"]:
token = resp["newToken"] # The old token is rotated — use the new one
print("Token renewed")
else:
print("Token expired — re-authenticate")

POST Auth/logout

Invalidate a token. After logout, the token can no longer be used for any API calls.

URL: POST /api/topstep-sim/Auth/logout

Request headers

Authorization: Bearer <your-token>
Content-Type: application/json

Request body

{}

Response

{
"success": true,
"errorCode": 0,
"errorMessage": null
}

Example

req = urllib.request.Request(
f"{API_URL}/Auth/logout",
data=b"{}",
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {token}"
}
)
resp = json.loads(urllib.request.urlopen(req).read())
print("Logged out" if resp["success"] else "Logout failed")

GET Status/ping

Health check endpoint. Returns a simple response indicating the API is operational. No authentication required.

URL: GET /api/topstep-sim/Status/ping

Response

A plain-text body (not JSON):

pong

Example

Terminal window
curl https://api.test-max.com/api/topstep-sim/Status/ping

Using the token in your scripts

Once authenticated, include the token in every request:

import urllib.request
import json
API_URL = "https://api.test-max.com/api/topstep-sim"
TOKEN = "your-token-here"
def api(path, body=None):
"""Call any TopStep Simulator API endpoint."""
data = json.dumps(body).encode() if body else None
req = urllib.request.Request(
f"{API_URL}/{path}",
data=data,
headers={
"Content-Type": "application/json",
"Authorization": f"Bearer {TOKEN}"
}
)
return json.loads(urllib.request.urlopen(req).read())
# Now use it for any endpoint
accounts = api("Account/search", {"onlyActiveAccounts": True})
contracts = api("Contract/search", {"searchText": "NQ"})

Security best practices

  • Never hardcode API keys in your scripts. Use environment variables: os.environ["TESTMAX_API_KEY"]
  • Do not commit tokens or keys to version control. Add them to .gitignore or use a .env file
  • Rotate your key periodically in Settings > API Access — generating a new key replaces and revokes the old one immediately
  • Log out when done by calling Auth/logout to invalidate tokens after a script completes