Cookbook
API Cookbook
Practical, copy-paste recipes for wiring the Smart Money API into a bot. Recipes 1–6 call GET /v1/confirm and act on action, confidence, and size_multiplier; send your key in the X-API-Key header. Recipes 7–9 need no key at all — around 80 endpoints are public. See the full docs.
Recipe 1
Confirm before entry (Python)
The canonical loop. Before your strategy opens a position, ask the API whether market structure agrees. Only enter when action == "CONFIRM".
import requests
API_KEY = "sm_your_key"
BASE = "https://api.smartmoneyapi.com/v1"
def confirm(symbol, direction):
r = requests.get(
f"{BASE}/confirm",
params={"symbol": symbol, "direction": direction},
headers={"X-API-Key": API_KEY},
timeout=5,
)
r.raise_for_status()
return r.json()
sig = confirm("BTC", "long")
if sig["action"] == "CONFIRM":
place_order("BTC", "long")
else:
print("skip:", sig["reasons"])
{
"symbol": "BTC",
"direction": "long",
"action": "CONFIRM",
"confidence": "HIGH",
"composite": 0.74,
"size_mult": 1.5,
"reasons": ["Funding positive across venues", "Whales 67% long"]
}
Recipe 2
Gate a Freqtrade signal
Override confirm_trade_entry so Freqtrade only takes entries the API confirms. Fail open on API errors so a timeout never blocks all trading.
import requests
from freqtrade.strategy import IStrategy
class SmartMoneyStrategy(IStrategy):
SM_KEY = "sm_your_key"
SM_BASE = "https://api.smartmoneyapi.com/v1"
def confirm_trade_entry(self, pair, order_type, amount, rate,
time_in_force, current_time, entry_tag, **kwargs):
symbol = pair.split("/")[0]
if symbol not in ("BTC", "ETH", "SOL"):
return True
try:
r = requests.get(
f"{self.SM_BASE}/confirm",
params={"symbol": symbol, "direction": "long"},
headers={"X-API-Key": self.SM_KEY},
timeout=3,
).json()
return r.get("action") == "CONFIRM"
except Exception:
return True
Recipe 3
Size by size_multiplier
Let conviction set position size. Multiply your base size by size_mult (0.0–1.5) so HIGH-confidence trades get more capital and weak ones get less.
BASE_SIZE_USD = 1000
sig = confirm("ETH", "long")
mult = sig.get("size_mult", 0.0)
size = BASE_SIZE_USD * mult
if size > 0:
place_order("ETH", "long", size_usd=size)
print(f"entered ${size:.0f} (mult {mult})")
A size_mult of 0.0 means do not enter — same outcome as a SKIP. Treat anything below your own floor as a skip.
Recipe 4
Skip on SKIP / reduce on REDUCE
Handle all three actions explicitly. CONFIRM enters full size, REDUCE enters at the (smaller) multiplier, SKIP stands aside.
sig = confirm(symbol, direction)
action = sig["action"]
if action == "CONFIRM":
place_order(symbol, direction, BASE_SIZE_USD * sig["size_mult"])
elif action == "REDUCE":
place_order(symbol, direction, BASE_SIZE_USD * sig["size_mult"])
else:
log(f"skip {symbol} {direction}: {sig['reasons']}")
Recipe 5
Handle 402 / 429
A 402 means the symbol or endpoint needs a higher plan; a 429 means you hit a rate limit. Treat 429/5xx as transient (back off), 402/401/403 as terminal (fix plan or key).
import time, requests
def confirm_safe(symbol, direction, retries=3):
for attempt in range(retries):
r = requests.get(
f"{BASE}/confirm",
params={"symbol": symbol, "direction": direction},
headers={"X-API-Key": API_KEY}, timeout=5,
)
if r.status_code == 200:
return r.json()
if r.status_code in (401, 402, 403):
raise RuntimeError(r.json())
if r.status_code == 429:
reset = int(r.headers.get("X-RateLimit-Reset", 2))
time.sleep(min(reset, 2 ** attempt))
continue
time.sleep(2 ** attempt)
return None
Recipe 6
Use with a coding agent
Hand Claude Code, Codex, or Cursor the machine-readable references and let it wire the integration. Point it at /llms.txt for the overview and the OpenAPI spec for exact shapes.
Read https://smartmoneyapi.com/llms.txt -- it is the complete
endpoint list, tier limits, and the unit rules (funding is quoted
per venue settlement interval; liquidations cover five CEX venues).
Then add a pre-trade check to my bot: call GET /v1/confirm with my
X-API-Key, and skip any entry unless action == "CONFIRM". Scale
size by size_multiplier.
Resources: /llms.txt (plain-text summary) · openapi.json (the live, always-current machine-readable contract) · the two public GitHub repos.
Recipe 7
Read the liquidation heatmap (no key)
The liquidation tape is public. It is built from five CEX force-order streams — binance, okx, bybit, bitget, bitmex. Every response carries an exchanges object listing the venues that actually backed that response, so you can tell a quiet market apart from a coverage gap. Read it. Retained history is about 14 days, not years.
import requests
BASE = "https://api.smartmoneyapi.com/v1"
hm = requests.get(f"{BASE}/liquidations/heatmap",
params={"symbol": "BTC"}, timeout=10).json()
print(hm["exchanges"])
if "binance" not in hm["exchanges"]:
print("warning: largest venue by notional is absent from this sample")
for c in hm["clusters"][:5]:
print(f"{c['price']:>10,.0f} ${c['notional']:>12,.0f} "
f"{c['dominant_side']:>5} n={c['count']}")
{
"symbol": "BTC", "window_minutes": 240,
"exchanges": {"binance": 466, "okx": 502, "bybit": 1198,
"bitget": 307, "bitmex": 6},
"totals": {"long_liq_notional": 15854782.4,
"short_liq_notional": 26115646.15, "count": 2479},
"clusters": [{"price": 79584.48, "notional": 4767649.09,
"count": 99, "dominant_side": "short"}]
}
Recipe 8
Compare funding on a common 8h basis
Perp funding is quoted per settlement interval, and the interval is not the same everywhere: Binance, Bybit and OKX settle every 8 hours, Hyperliquid every hour. A Hyperliquid rate is therefore about one eighth the size of an 8h rate for the same economic cost. Comparing the raw numbers ranks venues wrongly and inverts the direction of a funding trade. /v1/derivatives/funding-arb already normalises before choosing its legs; the raw funding field on the heatmap and screener is still each venue's native rate.
INTERVAL_H = {"binance": 8, "bybit": 8, "okx": 8, "hyperliquid": 1}
def per_8h(rate, venue):
return rate * (8 / INTERVAL_H.get(venue.lower(), 8))
fh = requests.get(f"{BASE}/derivatives/funding-heatmap", timeout=10).json()
btc = next(r for r in fh["heatmap"] if r["symbol"] == "BTC")
norm = {v: per_8h(d["funding"], v) for v, d in btc["exchanges"].items()}
long_leg = min(norm, key=norm.get)
short_leg = max(norm, key=norm.get)
print(long_leg, short_leg, round(norm[short_leg] - norm[long_leg], 8))
Recipe 9
Read your limits instead of hardcoding them
GET /v1/plans is public and is the single source of truth for quotas, prices, symbol universe and features. Pace your client from it rather than from a number copied out of a docs page — those drift, this does not. There is no delayed-data tier: delay_seconds is 0 on every plan including Free.
plans = requests.get(f"{BASE}/plans", timeout=10).json()["tiers"]
free = plans["free"]
print(free["daily_calls"])
print(free["requests_per_minute"])
print(free["allowed_symbols"])
print(free["delay_seconds"])
min_interval = 60.0 / free["requests_per_minute"]
The two public repositories
Both are on GitHub, both are readable without an account or a key, and between them they let you evaluate the API before you buy it — point an OpenAPI generator at the contract, or read the client source to see exactly what gets sent and returned.
tashiardit/smartmoneyapi-docs — the OpenAPI document for the product surface plus a written reference and worked examples. Use it to generate a client in any language, or to hand a coding agent a machine-readable contract instead of prose.
tashiardit/smartmoneyapi-python — the official Python client, an alternative to the raw requests calls used in these recipes. It reads your key from SMARTMONEY_API_KEY, sends it as X-API-Key, and wraps the endpoints as methods.
The repository copy of the spec is a published snapshot and can lag between updates. https://api.smartmoneyapi.com/openapi.json is regenerated from the router and is always current — if the two ever disagree, the live one is right.
Ready to gate your first trade?
Grab a free key and read the full endpoint reference.
Decision support, not execution advice. Not financial advice. Cryptocurrency trading involves substantial risk of loss.