Developers
API reference
REST over HTTPS, JSON only. Read the signal feed, provider directory and aggregate performance; approved providers can publish and close attributed signals. A public sandbox key means you can make a real request before creating an account.
Quickstart
This works right now — the sandbox key below is public and requires no account.
curl
curl -H "Authorization: Bearer tofan_sandbox_demo" \
"https://vhzdqlzyvuemieieenys.supabase.co/functions/v1/public-api/signals?status=active"Python
pip install requests
from tofan import TofanClient
client = TofanClient() # defaults to the sandbox key
for s in client.signals(status="closed"):
print(s.pair, s.direction, s.result, s.pips_result)Market data straight into pandas
import io, pandas as pd
from tofan import TofanClient
client = TofanClient(api_key="tofan_...")
df = pd.read_csv(io.StringIO(client.candles_csv("EURUSD", "1d")))
df["candle_time"] = pd.to_datetime(df["candle_time"])
print(df[["candle_time", "close", "rsi_14", "ema_50"]].tail())JavaScript
const res = await fetch("https://vhzdqlzyvuemieieenys.supabase.co/functions/v1/public-api/signals?status=active", {
headers: { Authorization: "Bearer tofan_sandbox_demo" },
});
const { signals } = await res.json();Try it
Live requests against the production API using the sandbox key. Nothing here is mocked — if these stop working, this page is wrong.
Authentication
Every request needs a bearer token. Issue keys from Dashboard → Security → Developer. Only a SHA-256 hash of your key is stored, so a database leak yields no usable credentials — which also means a lost key cannot be recovered, only replaced.
Header
Authorization: Bearer tofan_your_key_hereread scope
The three GET endpoints. Available on any account.
publish scope
POST endpoints. Issued only to approved signal providers, because what a publish key writes carries that provider's attribution.
Sandbox
tofan_sandbox_demo is a public read-only key returning three fixed sample signals and two sample providers. Query parameters are genuinely applied to the fixtures, so what you build against the sandbox behaves the same live.
Publish calls with the sandbox key are validated exactly like real ones and echoed back with sandbox: true, but write nothing.
Rate limits
60 requests per minute per key by default. Exceeding it returns 429 with a Retry-After header and retry_after_seconds in the body. The Python SDK retries automatically.
Endpoints
Errors
| Status | Meaning | What to do |
|---|---|---|
| 401 | Key missing, malformed, revoked or unknown. | Check the Authorization header format: Bearer tofan_… |
| 403 | Key is valid but lacks the scope this call needs. | Publish scope is issued only to approved providers. |
| 404 | No matching resource, or it is not yours. | Closing a signal only works on your own active signals. |
| 429 | Rate limit exceeded. | Wait for Retry-After seconds. The SDK does this for you. |
| 500 | Unexpected server error. | Retry once; if it persists, check /status. |
Python SDK
Typed models, automatic 429 retry, and typed exceptions so you can tell a bad key from an exhausted quota without parsing strings. Only dependency is requests.
Errors are typed
from tofan import TofanClient, PermissionError_, RateLimitError
client = TofanClient(api_key="tofan_...")
try:
client.publish_signal("EURUSD", "BUY", 1.0842, stop_loss=1.0798)
except PermissionError_:
print("this key is read-only")
except RateLimitError as e:
print(f"slow down; retry in {e.retry_after}s")Component health for these endpoints is on the status page; feed coverage is on the infrastructure page.