Getting started
Five minutes from a key to your first client, login link and order. Everything below is copy-paste ready in nine languages.
#Which API do I need?
Partner API
You are a broker, white-label or introducing partner. Your backend manages clients, accounts, money and sign-in for many users. Keys are created by the CRM owner under Settings › API & Webhooks.
Trading API
You are a trader or build for one client. The client creates a key in the trader (API access, Pro mode) and trades their own accounts: quotes, orders, positions, history, WebSocket, FIX.
https://api.your-brand.com. Replace it with the API host of your Octolit installation - your account manager gives it to you, and GET /api/external/v1/me confirms it. Always HTTPS, always JSON.
#Partner API in 5 minutes
-
Create a key
In the Octolit CRM open Settings › API & Webhooks, switch the API on, then API keys › New key. Pick only the scopes you need, set an IP allow-list and an expiry. The key is shown once. Per brand, Brand settings has the switches Partner API, Single sign-on and Trading webhooks.
shellexport OCTOLIT_PARTNER_KEY="pk_live_..." # never commit it -
Check the key
GET /meanswers with your company, the key's scopes, the brands it can see and the current rate limit.GET /api/external/v1/mecurl "https://api.your-brand.com/api/external/v1/me" \ -H "X-Api-Key: $OCTOLIT_PARTNER_KEY"const res = await fetch("https://api.your-brand.com/api/external/v1/me", { method: "GET", headers: { "X-Api-Key": process.env.OCTOLIT_PARTNER_KEY, }, }); if (!res.ok) throw new Error(`GET failed: ${res.status} ${await res.text()}`); const data = await res.json(); console.log(data);import os, requests r = requests.request( "GET", "https://api.your-brand.com/api/external/v1/me", headers={"X-Api-Key": os.environ["OCTOLIT_PARTNER_KEY"]}, timeout=10, ) r.raise_for_status() print(r.json())<?php $ch = curl_init("https://api.your-brand.com/api/external/v1/me"); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Api-Key: " . getenv("OCTOLIT_PARTNER_KEY"), ], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); print_r($data);using var http = new HttpClient(); using var req = new HttpRequestMessage(HttpMethod.Get, "https://api.your-brand.com/api/external/v1/me"); req.Headers.Add("X-Api-Key", Environment.GetEnvironmentVariable("OCTOLIT_PARTNER_KEY")); using var res = await http.SendAsync(req); res.EnsureSuccessStatusCode(); Console.WriteLine(await res.Content.ReadAsStringAsync());var client = HttpClient.newHttpClient(); var req = HttpRequest.newBuilder(URI.create("https://api.your-brand.com/api/external/v1/me")) .header("X-Api-Key", System.getenv("OCTOLIT_PARTNER_KEY")) .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.statusCode() + " " + res.body());var body io.Reader req, err := http.NewRequest("GET", "https://api.your-brand.com/api/external/v1/me", body) if err != nil { log.Fatal(err) } req.Header.Set("X-Api-Key", os.Getenv("OCTOLIT_PARTNER_KEY")) res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() out, _ := io.ReadAll(res.Body) fmt.Println(res.StatusCode, string(out))var req = URLRequest(url: URL(string: "https://api.your-brand.com/api/external/v1/me")!) req.httpMethod = "GET" req.setValue(ProcessInfo.processInfo.environment["OCTOLIT_PARTNER_KEY"], forHTTPHeaderField: "X-Api-Key") let (data, response) = try await URLSession.shared.data(for: req) print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))val client = OkHttpClient() val req = Request.Builder() .url("https://api.your-brand.com/api/external/v1/me") .header("X-Api-Key", System.getenv("OCTOLIT_PARTNER_KEY")) .get() .build() client.newCall(req).execute().use { res -> println("${res.code} ${res.body?.string()}") }200 OK{ "key": { "id": 1042, "name": "Main", "prefix": "pk_live_3f", "scopes": [ "clients:read" ], "ip_allowlist": [ "string" ], "status": "active", "expires_at": "2026-11-11T09:31:00Z", "created_at": "2026-11-11T09:30:00.000000Z", "last_used_at": "2026-11-11T09:29:58Z" }, "company_id": 10, "requests_per_minute": 120, "server_time": "2026-11-11T09:30:00.000000Z" } -
Create a client by your own id
PUT /users/{external_id}is idempotent: the sameexternal_idalways maps to the same client. Send only the fields you know;brand_idis fixed after creation.PUT /api/external/v1/users/cust_10042curl -X PUT "https://api.your-brand.com/api/external/v1/users/cust_10042" \ -H "X-Api-Key: $OCTOLIT_PARTNER_KEY" \ -H "Content-Type: application/json" \ -d '{ "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" }'const res = await fetch("https://api.your-brand.com/api/external/v1/users/cust_10042", { method: "PUT", headers: { "X-Api-Key": process.env.OCTOLIT_PARTNER_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" }), }); if (!res.ok) throw new Error(`PUT failed: ${res.status} ${await res.text()}`); const data = await res.json(); console.log(data);import os, requests r = requests.request( "PUT", "https://api.your-brand.com/api/external/v1/users/cust_10042", headers={"X-Api-Key": os.environ["OCTOLIT_PARTNER_KEY"]}, json={ "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE", }, timeout=10, ) r.raise_for_status() print(r.json())<?php $ch = curl_init("https://api.your-brand.com/api/external/v1/users/cust_10042"); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "PUT", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Api-Key: " . getenv("OCTOLIT_PARTNER_KEY"), "Content-Type: " . "application/json", ], CURLOPT_POSTFIELDS => json_encode([ "brand_id" => 13, "email" => "anna@example.com", "first_name" => "Anna", "last_name" => "Lindqvist", "country" => "SE", ]), ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); print_r($data);using var http = new HttpClient(); using var req = new HttpRequestMessage(HttpMethod.Put, "https://api.your-brand.com/api/external/v1/users/cust_10042"); req.Headers.Add("X-Api-Key", Environment.GetEnvironmentVariable("OCTOLIT_PARTNER_KEY")); req.Content = new StringContent(""" { "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" } """, Encoding.UTF8, "application/json"); using var res = await http.SendAsync(req); res.EnsureSuccessStatusCode(); Console.WriteLine(await res.Content.ReadAsStringAsync());var client = HttpClient.newHttpClient(); var req = HttpRequest.newBuilder(URI.create("https://api.your-brand.com/api/external/v1/users/cust_10042")) .header("X-Api-Key", System.getenv("OCTOLIT_PARTNER_KEY")) .header("Content-Type", "application/json") .method("PUT", HttpRequest.BodyPublishers.ofString(""" { "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" } """)) .build(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.statusCode() + " " + res.body());body := strings.NewReader(`{ "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" }`) req, err := http.NewRequest("PUT", "https://api.your-brand.com/api/external/v1/users/cust_10042", body) if err != nil { log.Fatal(err) } req.Header.Set("X-Api-Key", os.Getenv("OCTOLIT_PARTNER_KEY")) req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() out, _ := io.ReadAll(res.Body) fmt.Println(res.StatusCode, string(out))var req = URLRequest(url: URL(string: "https://api.your-brand.com/api/external/v1/users/cust_10042")!) req.httpMethod = "PUT" req.setValue(ProcessInfo.processInfo.environment["OCTOLIT_PARTNER_KEY"], forHTTPHeaderField: "X-Api-Key") req.setValue("application/json", forHTTPHeaderField: "Content-Type") req.httpBody = """ { "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" } """.data(using: .utf8) let (data, response) = try await URLSession.shared.data(for: req) print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))val client = OkHttpClient() val req = Request.Builder() .url("https://api.your-brand.com/api/external/v1/users/cust_10042") .header("X-Api-Key", System.getenv("OCTOLIT_PARTNER_KEY")) .method("PUT", """{ "brand_id": 13, "email": "anna@example.com", "first_name": "Anna", "last_name": "Lindqvist", "country": "SE" }""".toRequestBody("application/json".toMediaType())) .build() client.newCall(req).execute().use { res -> println("${res.code} ${res.body?.string()}") } -
Send the user into the trader
Ask for a one-time login link and redirect the browser to
login_url. The link works once and expires in minutes. Prefer JWT single sign-on when your platform already has a session.POST /api/external/v1/users/cust_10042/ssocurl -X POST "https://api.your-brand.com/api/external/v1/users/cust_10042/sso" \ -H "X-Api-Key: $OCTOLIT_PARTNER_KEY" \ -H "Content-Type: application/json" \ -d '{ "target": "trader" }'const res = await fetch("https://api.your-brand.com/api/external/v1/users/cust_10042/sso", { method: "POST", headers: { "X-Api-Key": process.env.OCTOLIT_PARTNER_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ "target": "trader" }), }); if (!res.ok) throw new Error(`POST failed: ${res.status} ${await res.text()}`); const data = await res.json(); console.log(data);import os, requests r = requests.request( "POST", "https://api.your-brand.com/api/external/v1/users/cust_10042/sso", headers={"X-Api-Key": os.environ["OCTOLIT_PARTNER_KEY"]}, json={ "target": "trader", }, timeout=10, ) r.raise_for_status() print(r.json())<?php $ch = curl_init("https://api.your-brand.com/api/external/v1/users/cust_10042/sso"); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-Api-Key: " . getenv("OCTOLIT_PARTNER_KEY"), "Content-Type: " . "application/json", ], CURLOPT_POSTFIELDS => json_encode([ "target" => "trader", ]), ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); print_r($data);using var http = new HttpClient(); using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.your-brand.com/api/external/v1/users/cust_10042/sso"); req.Headers.Add("X-Api-Key", Environment.GetEnvironmentVariable("OCTOLIT_PARTNER_KEY")); req.Content = new StringContent(""" { "target": "trader" } """, Encoding.UTF8, "application/json"); using var res = await http.SendAsync(req); res.EnsureSuccessStatusCode(); Console.WriteLine(await res.Content.ReadAsStringAsync());var client = HttpClient.newHttpClient(); var req = HttpRequest.newBuilder(URI.create("https://api.your-brand.com/api/external/v1/users/cust_10042/sso")) .header("X-Api-Key", System.getenv("OCTOLIT_PARTNER_KEY")) .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString(""" { "target": "trader" } """)) .build(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.statusCode() + " " + res.body());body := strings.NewReader(`{ "target": "trader" }`) req, err := http.NewRequest("POST", "https://api.your-brand.com/api/external/v1/users/cust_10042/sso", body) if err != nil { log.Fatal(err) } req.Header.Set("X-Api-Key", os.Getenv("OCTOLIT_PARTNER_KEY")) req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() out, _ := io.ReadAll(res.Body) fmt.Println(res.StatusCode, string(out))var req = URLRequest(url: URL(string: "https://api.your-brand.com/api/external/v1/users/cust_10042/sso")!) req.httpMethod = "POST" req.setValue(ProcessInfo.processInfo.environment["OCTOLIT_PARTNER_KEY"], forHTTPHeaderField: "X-Api-Key") req.setValue("application/json", forHTTPHeaderField: "Content-Type") req.httpBody = """ { "target": "trader" } """.data(using: .utf8) let (data, response) = try await URLSession.shared.data(for: req) print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))val client = OkHttpClient() val req = Request.Builder() .url("https://api.your-brand.com/api/external/v1/users/cust_10042/sso") .header("X-Api-Key", System.getenv("OCTOLIT_PARTNER_KEY")) .method("POST", """{ "target": "trader" }""".toRequestBody("application/json".toMediaType())) .build() client.newCall(req).execute().use { res -> println("${res.code} ${res.body?.string()}") } -
Subscribe to events
Settings › API & Webhooks › Webhooks › New endpoint: your HTTPS URL and the events. Press Send test event and verify the signature before you trust a payload.
#Trading API in 5 minutes
-
Create a key in the trader
Your broker switches the Trading API on for your brand. In the trader open API access (Pro mode) and create a key: read-only or with the
tradescope, optional IP allow-list and expiry. Keys start withqk_and are shown once.shellexport OCTOLIT_API_KEY="qk_..." -
Read your account
GET /api/open/v1/accountcurl "https://api.your-brand.com/api/open/v1/account" \ -H "X-API-Key: $OCTOLIT_API_KEY"const res = await fetch("https://api.your-brand.com/api/open/v1/account", { method: "GET", headers: { "X-API-Key": process.env.OCTOLIT_API_KEY, }, }); if (!res.ok) throw new Error(`GET failed: ${res.status} ${await res.text()}`); const data = await res.json(); console.log(data);import os, requests r = requests.request( "GET", "https://api.your-brand.com/api/open/v1/account", headers={"X-API-Key": os.environ["OCTOLIT_API_KEY"]}, timeout=10, ) r.raise_for_status() print(r.json())<?php $ch = curl_init("https://api.your-brand.com/api/open/v1/account"); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "GET", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-API-Key: " . getenv("OCTOLIT_API_KEY"), ], ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); print_r($data);using var http = new HttpClient(); using var req = new HttpRequestMessage(HttpMethod.Get, "https://api.your-brand.com/api/open/v1/account"); req.Headers.Add("X-API-Key", Environment.GetEnvironmentVariable("OCTOLIT_API_KEY")); using var res = await http.SendAsync(req); res.EnsureSuccessStatusCode(); Console.WriteLine(await res.Content.ReadAsStringAsync());var client = HttpClient.newHttpClient(); var req = HttpRequest.newBuilder(URI.create("https://api.your-brand.com/api/open/v1/account")) .header("X-API-Key", System.getenv("OCTOLIT_API_KEY")) .method("GET", HttpRequest.BodyPublishers.noBody()) .build(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.statusCode() + " " + res.body());var body io.Reader req, err := http.NewRequest("GET", "https://api.your-brand.com/api/open/v1/account", body) if err != nil { log.Fatal(err) } req.Header.Set("X-API-Key", os.Getenv("OCTOLIT_API_KEY")) res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() out, _ := io.ReadAll(res.Body) fmt.Println(res.StatusCode, string(out))var req = URLRequest(url: URL(string: "https://api.your-brand.com/api/open/v1/account")!) req.httpMethod = "GET" req.setValue(ProcessInfo.processInfo.environment["OCTOLIT_API_KEY"], forHTTPHeaderField: "X-API-Key") let (data, response) = try await URLSession.shared.data(for: req) print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))val client = OkHttpClient() val req = Request.Builder() .url("https://api.your-brand.com/api/open/v1/account") .header("X-API-Key", System.getenv("OCTOLIT_API_KEY")) .get() .build() client.newCall(req).execute().use { res -> println("${res.code} ${res.body?.string()}") }200 OK{ "client_id": 1042, "key": { "id": 1042, "name": "Main", "prefix": "pk_live_3f", "scopes": [ "read" ], "trading_account_ids": [ 55 ], "ip_allowlist": [ "string" ], "expires_at": "2026-11-11T09:31:00Z", "created_at": "2026-11-11T09:30:00.000000Z" }, "trading_account_ids": [ 55 ], "limits": { "requests_per_min": 1200, "client_requests_per_min": 1, "orders_per_sec": 10, "account_orders_per_sec": 1, "max_keys": 5 }, "websocket": true, "trading_stopped": true, "server_time": "2026-11-11T09:30:00.000000Z" } -
Place a market order
Orders need the
tradescope and aclient_order_idof your own. Send the same id again and you get the same order back (200 replayed), never a second fill. Quantity is inlotsorunits.POST /api/open/v1/orderscurl -X POST "https://api.your-brand.com/api/open/v1/orders" \ -H "X-API-Key: $OCTOLIT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 }'const res = await fetch("https://api.your-brand.com/api/open/v1/orders", { method: "POST", headers: { "X-API-Key": process.env.OCTOLIT_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 }), }); if (!res.ok) throw new Error(`POST failed: ${res.status} ${await res.text()}`); const data = await res.json(); console.log(data);import os, requests r = requests.request( "POST", "https://api.your-brand.com/api/open/v1/orders", headers={"X-API-Key": os.environ["OCTOLIT_API_KEY"]}, json={ "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1, }, timeout=10, ) r.raise_for_status() print(r.json())<?php $ch = curl_init("https://api.your-brand.com/api/open/v1/orders"); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => "POST", CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "X-API-Key: " . getenv("OCTOLIT_API_KEY"), "Content-Type: " . "application/json", ], CURLOPT_POSTFIELDS => json_encode([ "client_order_id" => "ord-2026-0001", "trading_account_id" => 55, "symbol" => "EURUSD", "side" => "buy", "type" => "market", "lots" => 0.1, ]), ]); $data = json_decode(curl_exec($ch), true); curl_close($ch); print_r($data);using var http = new HttpClient(); using var req = new HttpRequestMessage(HttpMethod.Post, "https://api.your-brand.com/api/open/v1/orders"); req.Headers.Add("X-API-Key", Environment.GetEnvironmentVariable("OCTOLIT_API_KEY")); req.Content = new StringContent(""" { "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 } """, Encoding.UTF8, "application/json"); using var res = await http.SendAsync(req); res.EnsureSuccessStatusCode(); Console.WriteLine(await res.Content.ReadAsStringAsync());var client = HttpClient.newHttpClient(); var req = HttpRequest.newBuilder(URI.create("https://api.your-brand.com/api/open/v1/orders")) .header("X-API-Key", System.getenv("OCTOLIT_API_KEY")) .header("Content-Type", "application/json") .method("POST", HttpRequest.BodyPublishers.ofString(""" { "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 } """)) .build(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); System.out.println(res.statusCode() + " " + res.body());body := strings.NewReader(`{ "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 }`) req, err := http.NewRequest("POST", "https://api.your-brand.com/api/open/v1/orders", body) if err != nil { log.Fatal(err) } req.Header.Set("X-API-Key", os.Getenv("OCTOLIT_API_KEY")) req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { log.Fatal(err) } defer res.Body.Close() out, _ := io.ReadAll(res.Body) fmt.Println(res.StatusCode, string(out))var req = URLRequest(url: URL(string: "https://api.your-brand.com/api/open/v1/orders")!) req.httpMethod = "POST" req.setValue(ProcessInfo.processInfo.environment["OCTOLIT_API_KEY"], forHTTPHeaderField: "X-API-Key") req.setValue("application/json", forHTTPHeaderField: "Content-Type") req.httpBody = """ { "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 } """.data(using: .utf8) let (data, response) = try await URLSession.shared.data(for: req) print((response as! HTTPURLResponse).statusCode, String(decoding: data, as: UTF8.self))val client = OkHttpClient() val req = Request.Builder() .url("https://api.your-brand.com/api/open/v1/orders") .header("X-API-Key", System.getenv("OCTOLIT_API_KEY")) .method("POST", """{ "client_order_id": "ord-2026-0001", "trading_account_id": 55, "symbol": "EURUSD", "side": "buy", "type": "market", "lots": 0.1 }""".toRequestBody("application/json".toMediaType())) .build() client.newCall(req).execute().use { res -> println("${res.code} ${res.body?.string()}") } -
Stream prices
POST /stream_ticketgives a 60-second ticket; openwss://api.your-brand.com/rt/v1/ws?ticket=…andsubscribeto up to 100 symbols. WebSocket reference →