Documentation
Volatility regime API for crypto. REST + WebSocket. Base URL: https://api.amaneki.com/v1
Quickstart
curl https://api.amaneki.com/v1/regime/btcusdt
No key needed for the free tier (60 req/min per IP). For higher limits, persistent key, and webhook alerts, get a paid key — pricing.
Rate limits in HA: the service runs on two Fly machines behind round-robin routing, each with its own in-memory counter. Within a single minute the effective limit you'll observe is the per-tier cap as a floor, not a hard ceiling (burst-dependent; a short burst that hits both machines can clear ~1.3–1.5× the advertised rpm before throttling engages). Plan budgets against the advertised value; treat the over-allowance as coincidental headroom, not a contract.
New to the API? Walk through the 10-minute quickstart (curl → Python SDK → Discord webhook) before scanning this reference.
Prefer a live sandbox? Interactive API reference — Scalar, rendered from the same /openapi.json you'd feed to openapi-generator, Stainless, or Speakeasy to auto-build a typed client.
Clients
Three examples of the same call — pick your language:
curl -H "Authorization: Bearer ak_..." \ https://api.amaneki.com/v1/regime/btcusdt?timeframe=15m
# Python (pip install amaneki)
from amaneki import Client
c = Client(api_key="ak_...")
print(c.get_regime("btcusdt", timeframe="15m"))
// JavaScript / TypeScript — plain fetch
const r = await fetch(
"https://api.amaneki.com/v1/regime/btcusdt?timeframe=15m",
{ headers: { Authorization: "Bearer ak_..." } }
);
console.log(await r.json());
// Go
req, _ := http.NewRequest("GET",
"https://api.amaneki.com/v1/regime/btcusdt?timeframe=15m", nil)
req.Header.Set("Authorization", "Bearer ak_...")
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)
Authentication
Send your key as a Bearer token:
curl -H "Authorization: Bearer ak_..." https://api.amaneki.com/v1/regime/btcusdt
Or as a header:
curl -H "X-API-Key: ak_..." https://api.amaneki.com/v1/regime/btcusdt
Use cases
Five ways customers have used the API. The endpoint reference below is organised by category; this section is the inverse — organised by the problem you're solving.
- Trade-entry confirmation —
GET /v1/regime/{sym}+GET /v1/consensus/{sym}+GET /v1/regime/{sym}/top-down?match=high - Stress-regime monitoring —
GET /v1/correlation/market+GET /v1/funding/{sym}+GET /v1/consensus/{sym} - Backtest feed for your own strategy —
GET /v1/regime/{sym}/history?from_ms=...&to_ms=...returns the full Postgres archive in one call - Vol-target position sizing —
GET /v1/sizing/{sym}?target_vol=0.20(raw calculation, not advice) - Bot / Discord alerts —
WS /v1/streamorPOST /v1/webhookswithformat: "discord"
Endpoints — Regime
GET /v1/regime/{symbol}
Current regime for one (symbol, timeframe).
| Param | Default | Notes |
|---|---|---|
timeframe | 1m | One of 1m, 5m, 15m, 1h, 4h, 1d |
{
"symbol": "btcusdt",
"timeframe": "1m",
"regime": "normal",
"z_vol": -0.83,
"realized_vol": 0.23,
"baseline_vol": 0.29,
"close": 74915.42,
"last_update_ms": 1776324240000,
"seconds_in_state": 18420,
"last_transition": null
}
GET /v1/regime/{symbol}/custom
Re-run the FSM against the in-memory feature window with caller-supplied thresholds. Stateless; doesn't affect the broadcast stream or the preset detector.
curl "https://api.amaneki.com/v1/regime/btcusdt/custom?high_enter=2.5&low_enter=-2.0&enter_k=3"
| Param | Default | Notes |
|---|---|---|
timeframe | 1m | |
high_enter | — | z-score to enter high |
low_enter | — | z-score to enter low (negative) |
enter_k | — | consecutive bars required |
GET /v1/regime/{symbol}/history
Past regime transitions. Without from_ms/to_ms, returns the in-memory ring buffer (~last 1024 transitions since process start). With either, queries Postgres for the full archive.
curl "https://api.amaneki.com/v1/regime/btcusdt/history?timeframe=15m&limit=200"
| Param | Default |
|---|---|
timeframe | 1m |
limit | 100 (max 1024) |
from_ms | — |
to_ms | — |
GET /v1/regime/{symbol}/matrix
3×3 transition probability matrix (rows: from-regime, cols: to-regime) over the archive window. Diagonal reports persistence.
curl "https://api.amaneki.com/v1/regime/btcusdt/matrix?timeframe=15m&lookback_days=30"
GET /v1/regime/{symbol}/durations
Empirical duration distribution per regime (seconds spent before exiting). Returns median/mean/p25/p75/p95 per regime label.
curl "https://api.amaneki.com/v1/regime/btcusdt/durations?timeframe=15m"
GET /v1/regime/{symbol}/state_at
Regime label at an arbitrary millisecond timestamp. Resolves by scanning the transition archive.
curl "https://api.amaneki.com/v1/regime/btcusdt/state_at?timeframe=15m&ts_ms=1776324240000"
GET /v1/regime/{symbol}/explain
Why the FSM is in its current state: which threshold crossed, which counter tripped, how many bars since the last flip. Useful for debugging "why didn't this transition fire?"
curl "https://api.amaneki.com/v1/regime/btcusdt/explain?timeframe=15m"
GET /v1/regime/{symbol}/conditional-returns
Empirical next-bar log-return distribution conditioned on the current regime. Mean, std, quantiles (p05/p25/p75/p95), samples, and baseline (unconditional distribution) so callers can quantify how much the regime label shifts the distribution.
curl "https://api.amaneki.com/v1/regime/btcusdt/conditional-returns?timeframe=15m"
Use this for attribution ("given the regime just flipped to HIGH, what's the next-bar return distribution historically?"), not as a point forecast. No model of direction — the mean is usually small and not a trading signal.
GET /v1/regime/{symbol}/forecast — deprecated
Alias of /conditional-returns kept for existing clients. Response body is identical; the response carries Deprecation: true, Sunset: Sat, 30 Jan 2027 00:00:00 GMT, and Link: …/conditional-returns; rel="successor-version". Migrate before 2027-01-30.
curl -i "https://api.amaneki.com/v1/regime/btcusdt/forecast?timeframe=15m"
GET /v1/regime/{symbol}/top-down
Multi-timeframe regime alignment. Returns whether the regime label agrees across the chain from_tf → … → to_tf, which TFs aligned, and the full per-timeframe dictionary. Use for Dow-theory / MTF-confluence entries without hitting /regime/{sym} N times.
curl "https://api.amaneki.com/v1/regime/btcusdt/top-down?match=high&from_tf=1d&to_tf=15m"
| Param | Default | Notes |
|---|---|---|
match | high | which regime must align: low | normal | high |
from_tf | 1d | slowest TF in the chain |
to_tf | 15m | fastest TF in the chain |
GET /v1/regime/{symbol}/stories
Human-readable narrative of recent regime transitions for the symbol. Designed for chat bots, LLM tool-calls, and daily summary emails — one sentence per transition, most recent first.
curl "https://api.amaneki.com/v1/regime/btcusdt/stories?days=7&timeframe=15m"
| Param | Default | Notes |
|---|---|---|
days | 7 | 1-90 |
timeframe | 15m | |
limit | 50 | 1-200 |
GET /v1/regime/{symbol}/matrix
Bar-level transition probability matrix over lookback_days, reconstructed from the postgres event archive (falls back to in-memory ring when the archive is empty for that series). Diagonal = stay-in-state probability, off-diagonal = per-bar switch probability.
curl "https://api.amaneki.com/v1/regime/btcusdt/matrix?timeframe=15m&lookback_days=90"
GET /v1/regime/{symbol}/durations
Distribution of regime run-lengths in bars. Summary stats (mean, median, p90, max, samples) per state over lookback_days, postgres-backed.
curl "https://api.amaneki.com/v1/regime/btcusdt/durations?timeframe=15m&lookback_days=90"
GET /v1/regime/{symbol}/impact
Realized return distribution following transitions into a target regime, at fixed horizons (1h, 4h, 24h). For each past transition, price at t+h is compared to price at t. Returns sample_size plus horizons with median, mean, std, p05/p25/p75/p95.
Gets more useful over time: every new transition adds a sample. On a fresh symbol or a rare target regime, sample_size can be 0. Always check the field before trusting the stats.
curl "https://api.amaneki.com/v1/regime/btcusdt/impact?to=high&timeframe=15m&lookback_days=60"
| Param | Default | Notes |
|---|---|---|
to | high | low | normal | high |
timeframe | 1m | |
lookback_days | 30 | 1-365 |
GET /v1/regime/lead-lag
Do transitions in leader precede matching transitions in follower? For each leader event into the target regime, scans forward up to max_lag_minutes for a follower event of the same kind. Returns hit_rate plus median/mean/p25/p75 of the matched lags in minutes.
Data-accumulation-based. A 7-day lookback on a quiet pair will match almost nothing. Prefer lookback_days ≥ 60 and read matched before trusting hit_rate.
curl "https://api.amaneki.com/v1/regime/lead-lag?leader=btcusdt&follower=ethusdt&to=high&timeframe=15m&lookback_days=60&max_lag_minutes=60"
| Param | Default | Notes |
|---|---|---|
leader | — | required |
follower | — | required |
to | high | low | normal | high |
timeframe | 1m | |
lookback_days | 60 | 1-365 |
max_lag_minutes | 60 | 1-1440 |
Endpoints — Consensus & Market Context
GET /v1/consensus/{symbol}
Majority vote across Binance, Coinbase and Bybit. Each venue computes its own regime from its own klines; consensus reports which venues agreed. Useful for catching single-venue wicks.
curl "https://api.amaneki.com/v1/consensus/btcusdt?timeframe=15m"
GET /v1/consensus/{symbol}/multi-tf
Pro Plus only. Cross-venue consensus evaluated on every supported timeframe in a single call. Use this to check whether a signal is isolated to one TF or confirmed top-down.
curl -H "Authorization: Bearer ak_..." \ "https://api.amaneki.com/v1/consensus/btcusdt/multi-tf"
GET /v1/correlation/market
Mean pairwise Pearson correlation across every tracked symbol at the given timeframe, over the last window bars. Stateless regime label (tight ≥ 0.8, dispersed ≤ 0.3, mixed in between).
curl "https://api.amaneki.com/v1/correlation/market?timeframe=15m&window=60"
GET /v1/correlation/{symbol}
Beta of the symbol's log-returns against a reference (default BTC) plus correlation to each peer.
curl "https://api.amaneki.com/v1/correlation/ethusdt?timeframe=15m"
GET /v1/iv-gap/{symbol}
Realized vs implied vol for BTC or ETH. RV is our annualized 1-minute vol; IV is the Deribit DVOL (30-day option-implied). Gap = IV − RV. Negative gap means spot is realizing faster than options imply.
Coverage: BTC and ETH only. Deribit publishes DVOL (a 30-day implied-vol index) for those two; other symbols return 404 with a Problem Details body explaining the limit.
curl "https://api.amaneki.com/v1/iv-gap/btcusdt"
GET /v1/funding/{symbol}
Current perpetual funding rate and recent history. Source: the symbol's primary venue.
curl "https://api.amaneki.com/v1/funding/btcusdt"
GET /v1/sizing/{symbol}
Vol-targeted position size helper. Given a target annualized portfolio vol and an equity figure, returns the notional implied by the symbol's current realized vol.
curl "https://api.amaneki.com/v1/sizing/btcusdt?timeframe=15m&target_vol=0.20&equity=100000"
GET /v1/badge/{symbol}.svg
Shields.io-style SVG badge of the current regime. Drop into a README or dashboard.
<img src="https://api.amaneki.com/v1/badge/btcusdt.svg?timeframe=15m" />
POST /v1/backtest
Replay a simple rule against the in-memory feature ring (~1024 bars per series). Returns per-trade detail + summary stats. Requires an API key.
curl -X POST https://api.amaneki.com/v1/backtest \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{"symbol":"btcusdt","timeframe":"15m","rule":"long_low_exit_normal"}'
Rules: long_low_exit_normal, short_high_exit_normal, avoid_high. Optional thresholds overrides the preset.
GET /v1/symbols, /v1/timeframes, /v1/presets
Lists. Public, no key needed.
curl https://api.amaneki.com/v1/symbols
WS /v1/stream
Push every regime transition. Browsers can pass the key via query string (no custom headers): wss://api.amaneki.com/v1/stream?api_key=ak_...
{
"type": "regime_transition",
"symbol": "BTCUSDT",
"timeframe": "5m",
"ts_ms": 1776324300000,
"from": "normal",
"to": "high",
"z_vol": 3.21,
"close": 74900.12
}
Endpoints — Account
POST /v1/feedback
Submit a verdict on a past transition. Used to surface false-positive patterns back into calibration.
curl -X POST https://api.amaneki.com/v1/feedback \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{"symbol":"btcusdt","timeframe":"15m","ts_ms":1776324300000,"verdict":"false_positive","note":"wick"}'
GET /v1/feedback
List feedback submitted by this key.
curl -H "Authorization: Bearer ak_..." https://api.amaneki.com/v1/feedback
POST /v1/me/rotate-key
Issue a new key and invalidate the current one. The response is the only place the new secret is shown.
curl -X POST -H "Authorization: Bearer ak_..." \ https://api.amaneki.com/v1/me/rotate-key
GET /v1/me/events
Audit events scoped to this key: issued, rotated, rate-limit hits, webhook deliveries.
curl -H "Authorization: Bearer ak_..." https://api.amaneki.com/v1/me/events
GET /v1/me/usage
Per-endpoint request counts for the current billing period.
curl -H "Authorization: Bearer ak_..." https://api.amaneki.com/v1/me/usage
GET /v1/me/allowlist, PUT /v1/me/allowlist
Pro Plus. Restrict this key to a subset of symbols. PUT with {"symbols": ["btcusdt","ethusdt"]}; empty list means "all tracked symbols".
curl -X PUT https://api.amaneki.com/v1/me/allowlist \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{"symbols":["btcusdt","ethusdt"]}'
GET/PUT/DELETE /v1/presets/custom
Save named threshold presets on your account. PUT body: {"name":"tight","high_enter":2.0,"low_enter":-1.8,"enter_k":3,...}. GET returns your saved presets; DELETE with ?name=tight removes one.
curl -X PUT https://api.amaneki.com/v1/presets/custom \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{"name":"tight","high_enter":2.0,"low_enter":-1.8,"enter_k":3}'
Endpoints — Webhooks (Hobby and higher)
Per-tier subscription caps: Hobby 1 webhook, Pro 5, Pro Plus unlimited. POST beyond the cap returns 403.
POST /v1/webhooks
Register an outbound webhook. Optional filters: symbols, timeframes, to_regimes.
curl -X POST https://api.amaneki.com/v1/webhooks \
-H "Authorization: Bearer ak_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://your.app/regime",
"symbols": ["btcusdt", "ethusdt"],
"timeframes": ["5m", "15m"],
"to_regimes": ["high"],
"batch_window_seconds": 0,
"format": "json"
}'
| Field | Default | Notes |
|---|---|---|
url | — | required. Discord webhook URLs are auto-detected and formatted |
symbols | all | |
timeframes | all | |
to_regimes | all | low | normal | high |
batch_window_seconds | 0 | 0-3600. Coalesce events inside this window into one delivery |
format | json | json | discord |
Response includes a one-time signing_secret. Each delivery carries an HMAC-SHA256 signature in X-Amaneki-Signature: t=<unix>,v1=<hex> over {t}.{body}.
GET /v1/webhooks
List subscriptions registered by this key.
curl -H "Authorization: Bearer ak_..." https://api.amaneki.com/v1/webhooks
DELETE /v1/webhooks/{id}
Remove a subscription. Returns 204 on success.
curl -X DELETE -H "Authorization: Bearer ak_..." \ https://api.amaneki.com/v1/webhooks/wh_01HXYZ...
Endpoints — Sandbox
POST /v1/sandbox/key
Issue a 24-hour trial API key with Pro-Plus feature access (webhooks, custom presets, backtest, multi-timeframe consensus, symbol allowlist) but Free-tier rate limit (60 rpm). One key per source IP per 24 hours. Optional email lands the caller on the Paid-checkout notification list.
curl -X POST https://api.amaneki.com/v1/sandbox/key \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]"}' # email optional
The key expires on the first auth after the 24-hour mark (lazily revoked). For evaluating paid features before checkout opens.
GET /v1/regime/{symbol}/history.csv
Same data as /history, streamed as CSV for pandas / polars / spreadsheets. Accepts the same timeframe, limit, from_ms, to_ms params; X-Amaneki-Source and X-Amaneki-Count headers echo where the rows came from (memory vs postgres) and how many shipped.
curl -H "Authorization: Bearer ak_..." \ "https://api.amaneki.com/v1/regime/btcusdt/history.csv?timeframe=15m&from_ms=$(date -v-30d +%s)000" \ -o btc-15m-30d.csv
Endpoints — Billing (Paddle)
POST /v1/billing/paddle/checkout
Create a Paddle hosted-checkout URL. Response includes url; redirect the user there. Paddle is our Merchant of Record, so billing, taxes, and invoicing flow through their platform — your server only needs the two calls on this page plus the webhook verification.
curl -X POST https://api.amaneki.com/v1/billing/paddle/checkout \
-H "Content-Type: application/json" \
-d '{"tier":"pro","billing_cycle":"monthly","email":"[email protected]"}'
| Field | Notes |
|---|---|
tier | hobby | pro | pro_plus |
billing_cycle | monthly | annual |
email | optional; prefills Paddle checkout |
Trial is fixed at 14 days (configured on the Paddle price). trial_days in the request body is ignored.
GET /v1/billing/paddle/key?transaction_id=...
Retrieve the provisioned API key for a completed checkout. One-shot: the key is only returned on first fetch. Call this from your success page (Paddle appends _ptxn=<id> to the redirect, which you pass as transaction_id).
curl "https://api.amaneki.com/v1/billing/paddle/key?transaction_id=txn_..."
POST /v1/billing/paddle/webhook
Paddle → Amaneki notification destination. Verified by the Paddle-Signature header. Not for customer use.
Endpoints — Infra
GET /v1/health
Liveness. Returns 200 if the process is up.
curl https://api.amaneki.com/v1/health
GET /v1/health/deep
Readiness. Pings the database, the Binance feed, and confirms at least one series has ticked in the last 60 seconds.
curl https://api.amaneki.com/v1/health/deep
GET /v1/metrics
Prometheus text format. Token-gated; for operators, not customers.
Errors
| Code | Meaning |
|---|---|
| 400 | Bad input (invalid symbol, malformed body) |
| 401 | Missing or invalid API key |
| 404 | Symbol or timeframe not tracked |
| 429 | Rate limit exceeded. Retry-After header tells you how many seconds to wait |
| 503 | Database unavailable (transient) |
Python SDK
pip install amaneki
Published to PyPI as amaneki. Full install + codegen docs at /sdk.
from amaneki import Client
c = Client(api_key="ak_...")
snap = c.get_regime("btcusdt", timeframe="5m")
print(snap.regime, snap.z_vol, snap.seconds_in_state)
cs = c.get_consensus("btcusdt", timeframe="15m")
print(cs.consensus, f"{cs.agreed}/{cs.available}")
r = c.run_backtest("btcusdt", timeframe="15m", rule="long_low_exit_normal")
print(r.n_trades, r.total_return)
for t in c.get_history("btcusdt", from_ms=1776000000000):
print(t.ts_ms, t.from_regime, "→", t.to_regime)
Calibration
Each symbol is calibrated independently against 180 days of its own 1-minute klines — 2,304 threshold combinations, Pareto-front selection on the (F1, alerts/day) plane. Detection lag median ~20 minutes regardless of symbol.
Macro-F1 against the smoothed percentile ground truth, by symbol and preset:
| Symbol | conservative | balanced | aggressive | alerts/day (balanced) |
|---|---|---|---|---|
| BTC | 0.37 | 0.39 | 0.41 | 5.6 |
| ETH | 0.37 | 0.39 | 0.41 | 5.6 |
| SOL | 0.39 | 0.43 | 0.44 | 5.0 |
| XRP | 0.40 | 0.42 | 0.43 | 5.2 |
| BNB | 0.38 | 0.41 | 0.42 | 5.0 |
| DOGE | 0.40 | 0.43 | 0.43 | 5.1 |
| ADA | 0.41 | 0.44 | 0.44 | 5.2 |
| AVAX | 0.41 | 0.44 | 0.45 | 5.1 |
| POL | 0.39 | 0.42 | 0.44 | 5.9 |
| LINK | 0.41 | 0.45 | 0.45 | 5.0 |
Honest caveats: regime detection against a smoothed percentile ground truth is a noisy problem. Every symbol lands in the 0.37-0.45 band at the balanced preset. Anyone advertising F1 > 0.9 for a regime task is leaking future information into the labels.
Status
amaneki.com/status shows live health.