← HOME

GHOST // PAPER BOT APIFRIENDS' BOTS · SAME LAB · FAKE MONEY

PAPER ONLY · NO EXCHANGE KEYS

Anyone can create an account on the website or in the iPhone app. No invite code. Mint a key in Settings on your dashboard. It is shown once, stored as a hash, and can trade only that account. Send it as Authorization: Bearer gst_…. A browser session cookie does nothing here.

60 REQUESTS / MIN / KEYOPEN UNTIL YOU CLOSEPAPER LEVERAGE · 1×–100×CROSS OR ISOLATED

RULES THE BUG WILL ENFORCE

GET /api/v1/signal

Shared crowd signal. Bull percent, last call, and the BTC price. No account data.

curl -s \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  https://your-dashboard.example/api/v1/signal

GET /api/v1/account

Your paper balance, open trades, and up to 100 history rows. An ADMIN GRANT row is a paper adjustment, not a trade, and its pnl is null. Performance is the wallet versus deposited capital: starting balance plus net grants.

curl -s \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  https://your-dashboard.example/api/v1/account

POST /api/v1/reload

Paper-key reload. JSON body: {"balance":250}. This ignores the desk plan. The number is $0 to $10,000, and the account can do this once per 24 hours. It is written to the public reload log and tracker and counted on the high score badges. It sets the paper cash. History and open positions stay. They are not closed and they are not hidden. A second reload inside 24 hours is refused and the wallet stays put. Desk refills in Settings follow Free, Basic, and Expert.

POST /api/v1/subscription/apple

Reserved for an App Store receipt. It is not active. A signed-in key gets apple receipt verification is not active yet and the plan does not change. The receipt is not stored. A body may name the non-consumable ghostlab.expert.lifetime. That product is recognized as Lifetime and still does not grant the plan. The iOS app does not call this route. A signed-in desk session posts the StoreKit 2 transaction to POST /api/subscription/apple, and App Store Server Notifications Version 2 post to POST /api/apple/notifications. Neither stores the signed payload. Steps for the three products are in docs/APP_STORE_IAP_SETUP.md.

curl -s -X POST \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  -H "Content-Type: application/json" \
  -d '{"balance":250}' \
  https://your-dashboard.example/api/v1/reload

POST /api/v1/trades

Open one paper position. Same as POST /api/v1/positions. JSON body: {"side":"LONG","stake":10,"leverage":5,"margin_mode":"cross","bull_pct":67.9}. Leave leverage and margin out and you get 1× cross. SHORT and isolated work the same way. It does not expire. bull_pct is the crowd bull percent of the sample that opened the trade, a number from 0 to 100. The desk stores that number on the position. Leave it out and the trade keeps the last pushed crowd percent, which is the previous cycle when you open before the push.

curl -s \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  -H "Content-Type: application/json" \
  -d '{"side":"LONG","stake":10,"bull_pct":67.9}' \
  https://your-dashboard.example/api/v1/trades

GET /api/v1/positions

Your open positions, with the live mark and unrealized upnl. Unrealized P&L is not in the balance until you close.

curl -s \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  https://your-dashboard.example/api/v1/positions

POST /api/v1/positions/{id}/close

Close one of your open positions at the current BTCUSDT price. The realized P&L lands in the paper balance. Someone else's id is rejected.

curl -s -X POST \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  https://your-dashboard.example/api/v1/positions/1/close

GET /api/v1/trades/{id}

One of your trades, open or already closed. Someone else's id is a 404.

curl -s \
  -H "Authorization: Bearer gst_paste_the_key_here" \
  https://your-dashboard.example/api/v1/trades/1

PYTHON

Stdlib only. Replace the host and paste the key you minted.

import json, urllib.request
KEY = "gst_paste_the_key_here"
BASE = "https://your-dashboard.example"

def call(method, path, body=None):
    data = None if body is None else json.dumps(body).encode()
    req = urllib.request.Request(
        BASE + path, data=data, method=method,
        headers={"Authorization": "Bearer " + KEY, "Content-Type": "application/json"})
    with urllib.request.urlopen(req) as res:
        return json.load(res)

print(call("GET", "/api/v1/signal"))
print(call("GET", "/api/v1/account"))
trade = call("POST", "/api/v1/positions", {"side": "LONG", "stake": 10, "leverage": 5, "margin_mode": "cross", "bull_pct": 67.9})
print(call("GET", "/api/v1/positions"))
print(call("POST", "/api/v1/positions/" + str(trade["id"]) + "/close"))
print(call("GET", "/api/v1/trades/" + str(trade["id"])))
PAPER MONEY ONLY: no real funds, no prizes, nothing is owed
log insign uphomeprivacysupportterms