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.

Need a key first? Sign up free, copy it from your dashboard, and replace sm_your_key below.

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".

Python
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") # your execution else: print("skip:", sig["reasons"])
Response
{ "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.

Python — Freqtrade
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 # fail open on API error
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.

Python
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.

Python
sig = confirm(symbol, direction) action = sig["action"] if action == "CONFIRM": place_order(symbol, direction, BASE_SIZE_USD * sig["size_mult"]) elif action == "REDUCE": # structure is mixed — enter smaller, tighten stop place_order(symbol, direction, BASE_SIZE_USD * sig["size_mult"]) else: # SKIP 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).

Python
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()) # terminal: fix key/plan 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) # 5xx / transient 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.

Prompt
# Paste into Claude Code / Cursor / Codex 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.

Python
import requests BASE = "https://api.smartmoneyapi.com/v1" hm = requests.get(f"{BASE}/liquidations/heatmap", params={"symbol": "BTC"}, timeout=10).json() # Coverage first. A venue missing here was not silent -- it was not sampled. print(hm["exchanges"]) # {'binance': 466, 'okx': 502, 'bybit': 1198, ...} if "binance" not in hm["exchanges"]: print("warning: largest venue by notional is absent from this sample") # Where forced selling actually clustered, by price level. for c in hm["clusters"][:5]: print(f"{c['price']:>10,.0f} ${c['notional']:>12,.0f} " f"{c['dominant_side']:>5} n={c['count']}")
Response (trimmed)
{ "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.

Python
# Settlement interval in hours, per venue. Unknown venues are 8h by # convention -- add anything new here rather than guessing. 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) # pay the least / get paid short_leg = max(norm, key=norm.get) # collect the most print(long_leg, short_leg, round(norm[short_leg] - norm[long_leg], 8))
Why it matters
# BTC, live sample: # raw binance 0.0001 bybit -0.00002095 hyperliquid 0.0000125 # per 8h binance 0.0001 bybit -0.00002095 hyperliquid 0.0001 # # Raw, Hyperliquid looks like the middle venue and a cheap place to be long. # Normalised it is tied for the MOST expensive. Same numbers, opposite trade.
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.

Python
plans = requests.get(f"{BASE}/plans", timeout=10).json()["tiers"] free = plans["free"] print(free["daily_calls"]) # 100 print(free["requests_per_minute"]) # 2 print(free["allowed_symbols"]) # ['BTC', 'ETH', 'SOL'] print(free["delay_seconds"]) # 0 -- real-time on every tier min_interval = 60.0 / free["requests_per_minute"] # self-pace

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.