{"openapi": "3.1.0", "info": {"title": "NUSA TERMINAL API", "version": "1.0.0", "description": "The HTTP API behind NUSA TERMINAL.\n\nAuthentication is a session cookie, not an API key: POST to /api/auth/login, keep the cookie, send it back. There is no separate machine credential yet.\n\nNothing here is investment advice. Signals are calculations over technical rules, and every figure the API returns about past performance is simulated unless it says otherwise."}, "servers": [{"url": "https://www.nusaterminal.com"}], "tags": ["Account", "Automation", "Backtests", "Billing", "Market data", "Service", "Signals"], "components": {"securitySchemes": {"sessionCookie": {"type": "apiKey", "in": "cookie", "name": "nusa_sess"}}}, "paths": {"/api/health": {"get": {"tags": ["Service"], "summary": "Liveness. Poll this from a watchdog.", "description": "Tiny and unauthenticated on purpose: a watchdog that needs a credential stops working the day the credential expires.\n\nAccess: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true, "uptime_s": 37821, "started": 1788913578}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/markets": {"get": {"tags": ["Service"], "summary": "The five markets and everything that differs between them.", "description": "Labels, size units, cost model, leverage limits, whether the market can be shorted, and the direction words it uses (futures LONG/SHORT, everything else BUY/SELL).\n\nAccess: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true, "markets": {"futures": {"label": "FUTURES", "side_labels": {"long": "LONG", "short": "SHORT"}}}}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/strategies": {"get": {"tags": ["Service"], "summary": "The ten strategies, with what each suits and fails at.", "description": "Access: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"strategies": [{"id": "confluence", "name": "Confluence, 5 rules"}]}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/strategy": {"get": {"tags": ["Service"], "summary": "The full rule specification for one strategy.", "description": "Access: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "id", "in": "query", "required": false, "description": "strategy id, e.g. macd_momentum", "schema": {"type": "string", "default": "confluence"}}, {"name": "market", "in": "query", "required": false, "description": "market the rules are described for", "schema": {"type": "string", "default": "spot"}}]}}, "/api/public/tape": {"get": {"tags": ["Market data"], "summary": "The ticker strip used by the landing page.", "description": "Access: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"rows": [{"symbol": "BTCUSDT", "price": 79120.0, "pct": -0.55}]}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/board": {"get": {"tags": ["Market data"], "summary": "A whole board of prices at once.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "group", "in": "query", "required": false, "description": "WORLD, CRYPTO, IDX, US, FX", "schema": {"type": "string", "default": "WORLD"}}], "security": [{"sessionCookie": []}]}}, "/api/quote": {"get": {"tags": ["Market data"], "summary": "Candles and the current quote for one symbol.", "description": "Ranges 15m to 5y. The 1s range is crypto only, and several ranges are Pro; a trial gets 403 with an `upgrade` field.\n\nAccess: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "symbol", "in": "query", "required": false, "description": "e.g. BTCUSDT, BBCA.JK, EUR_USD", "schema": {"type": "string", "default": "BTCUSDT"}}, {"name": "range", "in": "query", "required": false, "description": "1s 15m 1h 4h 1d 5d 1mo 3mo 6mo 1y 5y", "schema": {"type": "string", "default": "1d"}}], "security": [{"sessionCookie": []}]}}, "/api/depth": {"get": {"tags": ["Market data"], "summary": "Order book depth. Crypto only.", "description": "Access: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "symbol", "in": "query", "required": false, "description": "a Binance spot pair", "schema": {"type": "string", "default": "BTCUSDT"}}], "security": [{"sessionCookie": []}]}}, "/api/movers": {"get": {"tags": ["Market data"], "summary": "Biggest 24-hour movers on Binance.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "security": [{"sessionCookie": []}]}}, "/api/search": {"get": {"tags": ["Market data"], "summary": "Find a symbol by name.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "q", "in": "query", "required": false, "description": "free text, e.g. telkom", "schema": {"type": "string", "default": "telkom"}}], "security": [{"sessionCookie": []}]}}, "/api/news": {"get": {"tags": ["Market data"], "summary": "Headlines for a symbol, or the general feed.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "symbol", "in": "query", "required": false, "description": "optional; omit for general market news", "schema": {"type": "string", "default": ""}}], "security": [{"sessionCookie": []}]}}, "/api/overnight": {"get": {"tags": ["Market data"], "summary": "Overnight Radar: how the reference markets moved since the Jakarta close, weighted into one bias figure.", "description": "The weights are hand-chosen, not fitted. The figure is indicative and the response says so.\n\nAccess: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "security": [{"sessionCookie": []}]}}, "/api/signal": {"get": {"tags": ["Signals"], "summary": "The technical signal for one symbol, with the rules that fired and the levels derived from ATR.", "description": "A trial sees the signal and the rule breakdown but not the entry, stop and target levels. This is a calculation over rules, not a forecast, and it has not been backtested by itself - the response carries that disclaimer.\n\nAccess: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true, "side": "long", "label": "LONG", "score": 4, "levels": {"entry": 79120, "stop": 77900, "tp1": 80340}}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "symbol", "in": "query", "required": false, "description": "instrument", "schema": {"type": "string", "default": "BTCUSDT"}}, {"name": "range", "in": "query", "required": false, "description": "chart horizon", "schema": {"type": "string", "default": "4h"}}, {"name": "market", "in": "query", "required": false, "description": "optional; overrides the guess made from the symbol, which matters because the direction words differ per market", "schema": {"type": "string", "default": "futures"}}], "security": [{"sessionCookie": []}]}}, "/api/scan": {"get": {"tags": ["Signals"], "summary": "Scan a whole board and return only what passes the threshold.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "group", "in": "query", "required": false, "description": "board to scan", "schema": {"type": "string", "default": "CRYPTO"}}, {"name": "range", "in": "query", "required": false, "description": "chart horizon", "schema": {"type": "string", "default": "4h"}}], "security": [{"sessionCookie": []}]}}, "/api/backtest": {"get": {"tags": ["Backtests"], "summary": "Replay the rules bar by bar over one symbol.", "description": "Signals are computed from bars 0..i and the position opens at the OPEN of bar i+1, so nothing acts on a price it could not have known. A bar that touches both stop and target counts as a stop.\n\nAccess: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "symbol", "in": "query", "required": false, "description": "instrument", "schema": {"type": "string", "default": "BTCUSDT"}}, {"name": "range", "in": "query", "required": false, "description": "how far back", "schema": {"type": "string", "default": "1y"}}], "security": [{"sessionCookie": []}]}}, "/api/backtest/board": {"get": {"tags": ["Backtests"], "summary": "The same, across a whole board.", "description": "Access: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "group", "in": "query", "required": false, "description": "board", "schema": {"type": "string", "default": "IDX"}}, {"name": "range", "in": "query", "required": false, "description": "how far back", "schema": {"type": "string", "default": "1y"}}], "security": [{"sessionCookie": []}]}}, "/api/backtest/submit": {"post": {"tags": ["Backtests"], "summary": "Submit a result computed on the customer's own machine.", "description": "Backtests run on the customer's computer; only the result comes here. Plan limits are enforced on this endpoint, so a result outside the plan is refused after it was computed.\n\nAccess: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"email": "you@example.com", "key": "NUSA-XXXX-XXXX-XXXX-XXXX", "result": {"symbol": "BTCUSDT", "trades": 262, "avg_r": -0.151}}}}}, "security": [{"sessionCookie": []}]}}, "/api/backtest/upload": {"post": {"tags": ["Backtests"], "summary": "Upload a JSON file of results saved offline.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"results": [{"symbol": "BTCUSDT", "trades": 262}]}}}}, "security": [{"sessionCookie": []}]}}, "/api/backtest/history": {"get": {"tags": ["Backtests"], "summary": "Stored results. Add ?id= for one result in full.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "id", "in": "query", "required": false, "description": "optional result id", "schema": {"type": "string", "default": ""}}], "security": [{"sessionCookie": []}]}}, "/api/backtest/suggest": {"get": {"tags": ["Backtests"], "summary": "Symbols worth testing next, from your own history.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "security": [{"sessionCookie": []}]}}, "/api/evidence": {"get": {"tags": ["Backtests"], "summary": "What your stored backtests support, per market.", "description": "Deduplicated, never pooled across markets, and corrected for selection: a strategy is only 'supported' if it beats the plain EMA baseline by a margin. This is what the automation engine consults before it will arm.\n\nAccess: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "market", "in": "query", "required": false, "description": "spot futures forex stock idx", "schema": {"type": "string", "default": "futures"}}], "security": [{"sessionCookie": []}]}}, "/api/auto/status": {"get": {"tags": ["Automation"], "summary": "Everything about one market's automation account.", "description": "Capital, risk, symbols, strategy, venue, open positions, the recent log, the evidence verdict, and whether the broker keys are stored and unlocked. Each market is a separate account.\n\nAccess: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "market", "in": "query", "required": false, "description": "which market", "schema": {"type": "string", "default": "futures"}}], "security": [{"sessionCookie": []}]}}, "/api/auto": {"post": {"tags": ["Automation"], "summary": "Every automation action, chosen by the `act` field.", "description": "act: config, arm, venue, keys, unlock, forget, close, kill, plan, apply_plan, balance, sync_capital, add, remove. `arm` refuses when your own backtests show the chosen strategy losing in that market - that refusal is the point of the feature, not a fault.\n\nAccess: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"act": "arm", "market": "futures", "on": true}}}}, "security": [{"sessionCookie": []}]}}, "/api/analyze": {"get": {"tags": ["Automation"], "summary": "An AI explanation of a signal or of a market's evidence.", "description": "The model is given figures this server already computed and asked to explain them. It is never asked what the market will do, and it cannot see prices. You choose a subject; you cannot send a prompt.\n\nAccess: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "parameters": [{"name": "subject", "in": "query", "required": false, "description": "signal or evidence", "schema": {"type": "string", "default": "evidence"}}, {"name": "market", "in": "query", "required": false, "description": "for subject=evidence", "schema": {"type": "string", "default": "futures"}}, {"name": "symbol", "in": "query", "required": false, "description": "for subject=signal", "schema": {"type": "string", "default": "BTCUSDT"}}, {"name": "range", "in": "query", "required": false, "description": "for subject=signal", "schema": {"type": "string", "default": "4h"}}], "security": [{"sessionCookie": []}]}}, "/api/auth/register": {"post": {"tags": ["Account"], "summary": "Create an account. Starts on the trial plan.", "description": "Access: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"email": "you@example.com", "password": "at least 8 characters", "name": "Your Name"}}}}}}, "/api/auth/login": {"post": {"tags": ["Account"], "summary": "Sign in. Sets the session cookie every other call needs.", "description": "Access: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"email": "you@example.com", "password": "\u2026"}}}}}}, "/api/auth/logout": {"post": {"tags": ["Account"], "summary": "End the session.", "description": "Public because clearing a cookie that is not there is harmless, and refusing it would only make a signed-out client handle an error it cannot act on.\n\nAccess: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/auth/reset/request": {"post": {"tags": ["Account"], "summary": "Ask for a password reset link.", "description": "The reply is identical whether or not the address is registered - telling the difference would let anyone test for customer addresses.\n\nAccess: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"email": "you@example.com"}}}}}}, "/api/auth/reset/confirm": {"post": {"tags": ["Account"], "summary": "Set a new password with the emailed token.", "description": "Changing the password deletes the stored broker API keys: they are encrypted under the old one and cannot be reopened.\n\nAccess: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"token": "\u2026", "password": "\u2026"}}}}}}, "/api/profile": {"get": {"tags": ["Account"], "summary": "Account, plan, and trading performance per venue.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "security": [{"sessionCookie": []}]}}, "/api/entitlements/me": {"get": {"tags": ["Account"], "summary": "What this plan allows: quotas, markets, strategies.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "security": [{"sessionCookie": []}]}}, "/api/license/status": {"get": {"tags": ["Account"], "summary": "Licence state for this session or device.", "description": "Access: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/team": {"post": {"tags": ["Account"], "summary": "Team members who receive backtest results by email.", "description": "Access: Pro plan", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"act": "add", "email": "colleague@example.com"}}}}, "security": [{"sessionCookie": []}]}}, "/api/payment/offer": {"get": {"tags": ["Billing"], "summary": "Plans for sale, the networks accepted, and your invoices.", "description": "Public: the plan catalogue and the receiving wallet address are already on the pricing page, and a wallet nobody can read is a wallet nobody can pay. The `invoices` array is scoped to the session, so an anonymous caller gets an empty one - your invoices are never visible to anyone else.\n\nAccess: public", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true, "plans": [{"id": "pro1y", "usd": 3000}], "networks": [{"id": "tron", "label": "TRON (TRC20)"}], "invoices": []}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}}}, "/api/payment/start": {"post": {"tags": ["Billing"], "summary": "Create an invoice: an address and an amount.", "description": "Access: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"plan": "pro1y", "network": "tron"}}}}, "security": [{"sessionCookie": []}]}}, "/api/payment/claim": {"post": {"tags": ["Billing"], "summary": "Submit the transaction id. Verified on-chain, then the plan activates.", "description": "The transaction is checked against the address the invoice named, not the address currently configured - so changing the receiving wallet never invalidates an invoice already issued.\n\nAccess: signed in", "responses": {"200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}}, "401": {"description": "not signed in"}, "403": {"description": "plan does not allow this"}}, "requestBody": {"required": true, "content": {"application/json": {"example": {"id": 4, "txid": "\u2026"}}}}, "security": [{"sessionCookie": []}]}}}}