{"openapi":"3.0.3","info":{"title":"Convergence Radar API","version":"1.0.0","description":"Live smart-money convergence crossings, per-token convergence + risk status, and the honest measured historical context behind them (OKX.AI ASP \"Convergence Radar\"). Paid endpoint, billed 0.02 USDT per successful call via the x402 protocol (scheme \"exact\", network eip155:196 — X Layer) settled through the OKX x402 facilitator. An unpaid GET receives HTTP 402 with a machine-readable payment challenge (accepts array: scheme/price/network/payTo) in the JSON body and a WWW-Authenticate: Payment header. The client signs an EIP-3009 transfer authorization for that amount and retries the SAME request with an X-PAYMENT header carrying the signed payload; the facilitator verifies + settles it before the handler runs. Paid routes are GET-only — HEAD/POST/etc. get 405, not a free ride."},"servers":[{"url":"https://api.convergenceradar.com"}],"paths":{"/v1/crossings":{"get":{"summary":"Live smart-money convergence crossings","description":"Tokens where at least `min_conv` distinct proven smart-money wallets bought within the last `hours`, enriched with live pump-phase, historical context, and forward-paper results. Paid endpoint, billed 0.02 USDT per successful call via the x402 protocol (scheme \"exact\", network eip155:196 — X Layer) settled through the OKX x402 facilitator. An unpaid GET receives HTTP 402 with a machine-readable payment challenge (accepts array: scheme/price/network/payTo) in the JSON body and a WWW-Authenticate: Payment header. The client signs an EIP-3009 transfer authorization for that amount and retries the SAME request with an X-PAYMENT header carrying the signed payload; the facilitator verifies + settles it before the handler runs. Paid routes are GET-only — HEAD/POST/etc. get 405, not a free ride.","security":[{"x402Payment":[]}],"parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"number","minimum":0.5,"maximum":48,"default":6},"description":"Lookback window (hours) for the convergence crossing time. Clamped to [0.5, 48]; a missing/non-finite value falls back to 6."},{"name":"min_conv","in":"query","required":false,"schema":{"type":"integer","minimum":2,"maximum":20,"default":4},"description":"Minimum distinct-wallet convergence to count as a crossing. Clamped to [2, 20]; a missing/non-finite value falls back to 4."},{"name":"chains","in":"query","required":false,"schema":{"type":"string"},"description":"Comma-separated chain filter, e.g. \"base,solana\". Omit for all chains."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"as_of":{"type":"string","format":"date-time"},"params":{"type":"object","properties":{"hours":{"type":"number"},"min_conv":{"type":"integer"},"chains":{"description":"The literal string \"all\", or the applied chain-filter array.","oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]}}},"count":{"type":"integer"},"phase_note":{"type":"string"},"crossings":{"type":"array","items":{"type":"object","properties":{"contract":{"type":"string"},"chain":{"type":"string"},"ticker":{"type":"string","nullable":true},"convergence":{"type":"integer","description":"Distinct proven wallets that bought this token."},"crossed_at":{"type":"string","format":"date-time","description":"Timestamp the min_conv-th distinct wallet bought."},"age_min":{"type":"number","description":"Minutes since crossed_at."},"first_buy_at":{"type":"string","format":"date-time"},"first_buy_price":{"type":"number","nullable":true},"pct_since_first_buy":{"type":"number","nullable":true,"description":"Live % move vs first_buy_price. Computed for EVERY crossing returned (the response is capped at response_cap and fully enriched); null only when the live price lookup for that token failed or the token has no first_buy_price."},"phase":{"type":"string","enum":["fresh","running","extended","dumped","unknown"],"description":"Derived from pct_since_first_buy — see phase_note."},"historical_context":{"type":"object","nullable":true,"description":"Full measured distribution (winners AND losers) of past signals at this convergence bucket. Null when the historical snapshot failed to load at boot, and on /v1/token also when convergence is 0 (no tracked smart-money buys for that token, so no comparable bucket). IMPORTANT: the sample behind these numbers was measured on solana and base only — a bsc token receives the same figures, which is a documented limitation, not a per-chain measurement.","properties":{"bucket":{"type":"string","enum":["conv1","conv2-3","conv4+"],"description":"Convergence bucket this token fell into: 1, 2-3, or 4+ distinct wallets."},"n":{"type":"integer","description":"Sample size backing this bucket."},"median_24h_pct":{"type":"number","description":"Median price change 24h after the signal."},"win_rate_24h_pct":{"type":"number","description":"% of sampled signals that were up at 24h."},"reached_2x_pct":{"type":"number","description":"% of sampled signals whose price ever reached 2x the signal price."},"reached_3x_pct":{"type":"number","description":"% of sampled signals whose price ever reached 3x the signal price."},"worse_than_minus50_pct":{"type":"number","description":"% of sampled signals that ever traded 50%+ below the signal price."},"median_peak_pct":{"type":"number","description":"Median of each signal's own best price move (peak), not the 24h snapshot."},"methodology":{"type":"string","description":"How the sample was built — see the snapshot methodology note."},"measured_at":{"type":"string","format":"date-time","description":"When this historical snapshot was generated (NOT when this response was served)."}}},"forward_paper":{"type":"object","nullable":true,"description":"Forward (not backtested) paper-trading results, measured from OUR simulated entry rather than the token's own peak — see how_to_read. Null only if the forward-paper snapshot failed to load at boot.","properties":{"generated_at":{"type":"string","format":"date-time"},"window_start":{"type":"string","format":"date-time"},"chains":{"type":"array","items":{"type":"string"}},"note":{"type":"string"},"arms":{"type":"object","additionalProperties":{"type":"object","description":"One paper-traded exit rule's aggregate result over the forward-test window.","properties":{"rule":{"type":"string","description":"Human-readable statement of the exit rule, e.g. take-profit/stop-loss levels and max hold time."},"n":{"type":"integer","description":"Number of simulated trades behind this arm."},"mean_pct":{"type":"number"},"median_pct":{"type":"number"},"win_rate":{"type":"number","description":"Percent of simulated trades that closed positive."},"reached_2x_pct":{"type":"number"},"reached_3x_pct":{"type":"number"},"median_peak_pct":{"type":"number"},"median_entry_lag_min":{"type":"number","description":"Median minutes between the crossing and the simulated fill."}}},"description":"Keyed by exit-rule name (e.g. \"tp_sl\", \"trailing\")."},"how_to_read":{"type":"string","description":"Why this differs from historical_context's backtest reached_2x/3x — read before comparing the two."}}}}}},"disclaimer":{"type":"string","description":"Fixed legal/decision-support disclaimer, identical on every response."}}}}}},"402":{"description":"Payment required — x402 challenge (paid mode only)."},"405":{"description":"Method not allowed — /v1 routes are GET-only."},"429":{"description":"Rate limited."},"503":{"description":"Backing data store unavailable."}}}},"/v1/token":{"get":{"summary":"Convergence status + risk flags for one token","description":"Convergence, live pump-phase, historical context, forward-paper results, and risk flags for a single token. Paid endpoint, billed 0.02 USDT per successful call via the x402 protocol (scheme \"exact\", network eip155:196 — X Layer) settled through the OKX x402 facilitator. An unpaid GET receives HTTP 402 with a machine-readable payment challenge (accepts array: scheme/price/network/payTo) in the JSON body and a WWW-Authenticate: Payment header. The client signs an EIP-3009 transfer authorization for that amount and retries the SAME request with an X-PAYMENT header carrying the signed payload; the facilitator verifies + settles it before the handler runs. Paid routes are GET-only — HEAD/POST/etc. get 405, not a free ride.","security":[{"x402Payment":[]}],"parameters":[{"name":"chain","in":"query","required":true,"schema":{"type":"string"}},{"name":"address","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"as_of":{"type":"string","format":"date-time"},"token":{"type":"object","properties":{"chain":{"type":"string"},"address":{"type":"string"},"ticker":{"type":"string","nullable":true,"description":"Ticker seen in our own buy records for this token; null if we have no record of it (e.g. a token with no tracked smart-money buys yet)."}}},"convergence":{"type":"integer"},"first_smart_buy_at":{"type":"string","format":"date-time","nullable":true},"last_smart_buy_at":{"type":"string","format":"date-time","nullable":true},"pct_since_first_buy":{"type":"number","nullable":true},"phase":{"type":"string","enum":["fresh","running","extended","dumped","unknown"]},"historical_context":{"type":"object","nullable":true,"description":"Full measured distribution (winners AND losers) of past signals at this convergence bucket. Null when the historical snapshot failed to load at boot, and on /v1/token also when convergence is 0 (no tracked smart-money buys for that token, so no comparable bucket). IMPORTANT: the sample behind these numbers was measured on solana and base only — a bsc token receives the same figures, which is a documented limitation, not a per-chain measurement.","properties":{"bucket":{"type":"string","enum":["conv1","conv2-3","conv4+"],"description":"Convergence bucket this token fell into: 1, 2-3, or 4+ distinct wallets."},"n":{"type":"integer","description":"Sample size backing this bucket."},"median_24h_pct":{"type":"number","description":"Median price change 24h after the signal."},"win_rate_24h_pct":{"type":"number","description":"% of sampled signals that were up at 24h."},"reached_2x_pct":{"type":"number","description":"% of sampled signals whose price ever reached 2x the signal price."},"reached_3x_pct":{"type":"number","description":"% of sampled signals whose price ever reached 3x the signal price."},"worse_than_minus50_pct":{"type":"number","description":"% of sampled signals that ever traded 50%+ below the signal price."},"median_peak_pct":{"type":"number","description":"Median of each signal's own best price move (peak), not the 24h snapshot."},"methodology":{"type":"string","description":"How the sample was built — see the snapshot methodology note."},"measured_at":{"type":"string","format":"date-time","description":"When this historical snapshot was generated (NOT when this response was served)."}}},"forward_paper":{"type":"object","nullable":true,"description":"Forward (not backtested) paper-trading results, measured from OUR simulated entry rather than the token's own peak — see how_to_read. Null only if the forward-paper snapshot failed to load at boot.","properties":{"generated_at":{"type":"string","format":"date-time"},"window_start":{"type":"string","format":"date-time"},"chains":{"type":"array","items":{"type":"string"}},"note":{"type":"string"},"arms":{"type":"object","additionalProperties":{"type":"object","description":"One paper-traded exit rule's aggregate result over the forward-test window.","properties":{"rule":{"type":"string","description":"Human-readable statement of the exit rule, e.g. take-profit/stop-loss levels and max hold time."},"n":{"type":"integer","description":"Number of simulated trades behind this arm."},"mean_pct":{"type":"number"},"median_pct":{"type":"number"},"win_rate":{"type":"number","description":"Percent of simulated trades that closed positive."},"reached_2x_pct":{"type":"number"},"reached_3x_pct":{"type":"number"},"median_peak_pct":{"type":"number"},"median_entry_lag_min":{"type":"number","description":"Median minutes between the crossing and the simulated fill."}}},"description":"Keyed by exit-rule name (e.g. \"tp_sl\", \"trailing\")."},"how_to_read":{"type":"string","description":"Why this differs from historical_context's backtest reached_2x/3x — read before comparing the two."}}},"risk_flags":{"type":"object","nullable":true,"description":"Raw risk/concentration data from the OnchainOS advanced-info lookup. Null if the token is unknown to that lookup, the CLI call failed, or it did not finish within the 8s caller-side deadline — never an error in that case, just absence.","properties":{"risk_control_level":{"type":"number","nullable":true,"description":"Upstream OnchainOS risk control level (lower = less restrictive/lower risk tier). Passed through as-is, NOT the same as risk_summary.concern_level below."},"dev_rug_pull_token_count":{"type":"number","nullable":true,"description":"Count of prior tokens by this same dev wallet that were flagged as rug-pulled."},"dev_launched_token_count":{"type":"number","nullable":true,"description":"Count of prior tokens launched by this same dev wallet."},"bundle_holding_pct":{"type":"number","nullable":true,"description":"% of supply held by bundler (same-block sniper bot) wallets."},"sniper_holding_pct":{"type":"number","nullable":true,"description":"% of supply held by sniper wallets."},"top10_hold_pct":{"type":"number","nullable":true,"description":"% of supply held by the top 10 holder addresses."},"lp_burned_pct":{"type":"number","nullable":true,"description":"% of LP tokens burned/locked — the remainder is pullable by whoever holds it."},"token_tags":{"type":"array","items":{"type":"string"},"description":"Upstream classification tags for the token (may be empty)."}}},"disclaimer":{"type":"string","description":"Fixed legal/decision-support disclaimer, identical on every response."}}}}}},"400":{"description":"chain and/or address query params missing."},"402":{"description":"Payment required — x402 challenge (paid mode only)."},"405":{"description":"Method not allowed — /v1 routes are GET-only."},"429":{"description":"Rate limited."},"503":{"description":"Backing data store unavailable."}}}},"/v1/risk":{"get":{"summary":"Risk-focused view of one token","description":"Same risk_flags data as /v1/token, without the convergence/price payload, plus a small derived risk_summary. Reuses the exact same cached lookup /v1/token uses — not a separate data source. Paid endpoint, billed 0.02 USDT per successful call via the x402 protocol (scheme \"exact\", network eip155:196 — X Layer) settled through the OKX x402 facilitator. An unpaid GET receives HTTP 402 with a machine-readable payment challenge (accepts array: scheme/price/network/payTo) in the JSON body and a WWW-Authenticate: Payment header. The client signs an EIP-3009 transfer authorization for that amount and retries the SAME request with an X-PAYMENT header carrying the signed payload; the facilitator verifies + settles it before the handler runs. Paid routes are GET-only — HEAD/POST/etc. get 405, not a free ride.","security":[{"x402Payment":[]}],"parameters":[{"name":"chain","in":"query","required":true,"schema":{"type":"string"}},{"name":"address","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK. If risk data is unavailable for this token, risk_flags is null and risk_summary.concern_level is \"unknown\" — this route never 500s for that reason.","content":{"application/json":{"schema":{"type":"object","properties":{"as_of":{"type":"string","format":"date-time"},"token":{"type":"object","properties":{"chain":{"type":"string"},"address":{"type":"string"},"ticker":{"type":"string","nullable":true,"description":"Ticker seen in our own buy records for this token; null if we have no record of it (e.g. a token with no tracked smart-money buys yet)."}}},"risk_flags":{"type":"object","nullable":true,"description":"Raw risk/concentration data from the OnchainOS advanced-info lookup. Null if the token is unknown to that lookup, the CLI call failed, or it did not finish within the 8s caller-side deadline — never an error in that case, just absence.","properties":{"risk_control_level":{"type":"number","nullable":true,"description":"Upstream OnchainOS risk control level (lower = less restrictive/lower risk tier). Passed through as-is, NOT the same as risk_summary.concern_level below."},"dev_rug_pull_token_count":{"type":"number","nullable":true,"description":"Count of prior tokens by this same dev wallet that were flagged as rug-pulled."},"dev_launched_token_count":{"type":"number","nullable":true,"description":"Count of prior tokens launched by this same dev wallet."},"bundle_holding_pct":{"type":"number","nullable":true,"description":"% of supply held by bundler (same-block sniper bot) wallets."},"sniper_holding_pct":{"type":"number","nullable":true,"description":"% of supply held by sniper wallets."},"top10_hold_pct":{"type":"number","nullable":true,"description":"% of supply held by the top 10 holder addresses."},"lp_burned_pct":{"type":"number","nullable":true,"description":"% of LP tokens burned/locked — the remainder is pullable by whoever holds it."},"token_tags":{"type":"array","items":{"type":"string"},"description":"Upstream classification tags for the token (may be empty)."}}},"risk_summary":{"type":"object","description":"Small derived read of risk_flags — OUR heuristic, not an upstream field and not the same thing as risk_flags.risk_control_level. See disclaimer.","properties":{"concern_level":{"type":"string","enum":["unknown","low","elevated","high"],"description":"\"unknown\" means risk_flags carried no usable data at all (not \"safe\") — always check risk_flags directly before treating this as a green light."},"reasons":{"type":"array","items":{"type":"string"},"description":"Human-readable reasons behind a non-\"low\"/\"unknown\" concern_level; empty when nothing crossed a threshold."}}},"disclaimer":{"type":"string","description":"Fixed legal/decision-support disclaimer, identical on every response."}}}}}},"400":{"description":"chain and/or address query params missing."},"402":{"description":"Payment required — x402 challenge (paid mode only)."},"405":{"description":"Method not allowed — /v1 routes are GET-only."},"429":{"description":"Rate limited."}}}}},"components":{"securitySchemes":{"x402Payment":{"type":"apiKey","in":"header","name":"X-PAYMENT","description":"Paid endpoint, billed 0.02 USDT per successful call via the x402 protocol (scheme \"exact\", network eip155:196 — X Layer) settled through the OKX x402 facilitator. An unpaid GET receives HTTP 402 with a machine-readable payment challenge (accepts array: scheme/price/network/payTo) in the JSON body and a WWW-Authenticate: Payment header. The client signs an EIP-3009 transfer authorization for that amount and retries the SAME request with an X-PAYMENT header carrying the signed payload; the facilitator verifies + settles it before the handler runs. Paid routes are GET-only — HEAD/POST/etc. get 405, not a free ride."}}}}