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
-
Generate an API key
Log into testmax.io and navigate to Settings > API Keys. Click Generate New Key. Copy the key immediately — it will not be shown again.
-
Exchange the API key for a token
Call
POST Auth/loginKeywith your email address and API key. The response contains a bearer token. -
Include the token in all requests
Pass the token in the
Authorizationheader:Authorization: Bearer <your-token> -
Refresh or validate as needed
Use
POST Auth/validateto check if a token is still valid or to refresh it. UsePOST Auth/logoutto 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"}| Field | Type | Required | Description |
|---|---|---|---|
userName | string | Yes | Your TestMax account email address |
apiKey | string | Yes | The API key generated in Settings |
Response
{ "success": true, "errorCode": 0, "errorMessage": null, "token": "eyJhbGciOiJIUzI1NiIs..."}| Field | Type | Description |
|---|---|---|
token | string | Bearer token to use in subsequent requests |
Example
import urllib.requestimport json
API_URL = "https://api.test-max.com/api/topstep-sim"
# Step 1: Authenticatelogin_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']}")curl -X POST https://api.test-max.com/api/topstep-sim/Auth/loginKey \ -H "Content-Type: application/json" \ -d '{ "userName": "your@email.com", "apiKey": "your-api-key-here" }'const response = await fetch( "https://api.test-max.com/api/topstep-sim/Auth/loginKey", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userName: "your@email.com", apiKey: "your-api-key-here", }), });
const data = await response.json();
if (data.success) { console.log("Token:", data.token);} else { console.error("Login failed:", data.errorMessage);}Error responses
| Scenario | errorCode | errorMessage |
|---|---|---|
| Invalid API key | 1 | "Invalid credentials" |
| Missing fields | 1 | "userName and apiKey are required" |
| Account disabled | 1 | "Account is disabled" |
POST Auth/validate
Validate an existing token. Returns the same token if valid, or a refreshed token if the original is close to expiration.
URL: POST /api/topstep-sim/Auth/validate
Request headers
Authorization: Bearer <your-token>Content-Type: application/jsonRequest body
{}An empty JSON body is required.
Response
{ "success": true, "errorCode": 0, "errorMessage": null, "token": "eyJhbGciOiJIUzI1NiIs..."}| Field | Type | Description |
|---|---|---|
token | string | The validated (or refreshed) token |
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["token"] # Use the refreshed token print("Token is valid")else: print("Token expired — re-authenticate")curl -X POST https://api.test-max.com/api/topstep-sim/Auth/validate \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{}'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/jsonRequest 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")curl -X POST https://api.test-max.com/api/topstep-sim/Auth/logout \ -H "Content-Type: application/json" \ -H "Authorization: Bearer YOUR_TOKEN" \ -d '{}'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
{ "success": true, "errorCode": 0, "errorMessage": null}Example
curl https://api.test-max.com/api/topstep-sim/Status/pingUsing the token in your scripts
Once authenticated, include the token in every request:
import urllib.requestimport 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 endpointaccounts = 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
.gitignoreor use a.envfile - Rotate keys periodically in Settings > API Keys. Old keys can be revoked at any time
- Log out when done by calling
Auth/logoutto invalidate tokens after a script completes - Use one key per integration so you can revoke access to a single script without affecting others