API Documentation

    MemeScout API

    Integrate real-time radar signals into your trading tools, bots, and applications.

    Quick Start

    1

    Get your API key

    Go to your Account Settings and generate an API key. API access requires Chad tier.

    2

    Add the Authorization header

    Include your API key in every request using the Authorization header.

    Authorization: Bearer smr_your_api_key_here
    3

    Make your first request

    Call the /signals endpoint to get current radar signals.

    Base URL

    https://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/api

    Endpoints

    GET
    /signals

    Returns current radar signals (active tokens on radar).

    Query Parameters

    ParameterTypeDefaultDescription
    min_scoreinteger0Minimum radar score (0-100)
    min_liquidityinteger0Minimum liquidity in USD
    max_age_hoursnumber4Maximum token age in hours, measured from first call (first_seen)
    max_age_minutesinteger240Same window in minutes (ignored when max_age_hours is set)
    limitinteger50Max results (max: 100)

    Response

    {
      "success": true,
      "timestamp": "2026-01-28T15:00:00Z",
      "count": 12,
      "signals": [
        {
          "address": "ABC123...",
          "name": "TokenName",
          "symbol": "TKN",
          "radar_score": 82,
          "market_cap": 148000,
          "liquidity": 12400,
          "volume_5m": 22100,
          "volume_15m": 41800,
          "volume_1h": 85000,
          "buys": 24,
          "sells": 9,
          "price": 0.000148,
          "age_minutes": 42,
          "trigger_reason": "High volume + strong buy pressure",
          "risk_level": "Low",
          "risk_score": 250,
          "first_seen": "2026-01-28T14:18:00Z",
          "last_seen": "2026-01-28T15:00:00Z",
          "is_new": true,
          "is_returning": false,
          "is_recovered": false,
          "is_dropped": false,
          "data_source": "live",
          "top_10_holders_pct": 42.5,
          "creator_holds_pct": 3.2,
          "lp_burned": true,
          "lp_locked": false,
          "mint_authority_revoked": true,
          "freeze_authority_revoked": true,
          "is_mutable": false,
          "top3_holders_pct": 18.1,
          "lp_health_score": 72,
          "volume_consistency": 85,
          "wallet_risk_score": 68,
          "time_to_peak_estimate": "fast",
          "call_tier": "PRIME",
          "score": 82,
          "reason": "High volume + strong buy pressure"
        }
      ]
    }

    Full field reference

    Every signal ships with the full risk and intelligence payload — no extra calls, no separate plan. These are the same fields most desks pay third-party risk vendors for.

    Identity & market
    FieldTypeMeaning
    addressstringSolana mint address (unique key)
    name / symbolstringToken metadata, backfilled from Jupiter when missing
    pricenumberLast observed USD price
    market_capnumberUSD market cap at last refresh
    liquiditynumberUSD liquidity across detected pools
    volume_5m / volume_15m / volume_1hnumberRolling USD volume windows
    buys / sellsintegerTrade counts in the latest window — buy pressure input
    age_minutesnumberMinutes since first_seen (our first call, not mint time)
    data_sourcestringlive = refreshed this cycle, cached = last known snapshot
    Scoring & lifecycle
    FieldRangeMeaning
    radar_score (alias: score)0-100Composite rank: liquidity, volume acceleration, buy pressure, holder growth, MC positioning, freshness. Higher is better.
    trigger_reason (alias: reason)stringHuman-readable explanation of why the token qualified
    call_tierPRIME / EARLY / STANDARDConviction band derived from liquidity depth and age at call time
    first_seenISO 8601When we first called the token — all age filters use this
    last_seenISO 8601Last successful refresh
    is_newbooleanFirst appearance in this cycle
    is_returningbooleanPreviously called, re-qualified
    is_recoveredbooleanDropped off, then recovered back above thresholds
    is_droppedbooleanFell below thresholds — kept for transparency, not a live call
    Risk & safety
    FieldRangeMeaning
    risk_levelLow / Medium / High / DangerBucketed verdict, sourced from our RugCheck report parser
    risk_score0-1000+Raw risk points — lower is safer. Tokens above our gate are rejected outright.
    top_10_holders_pct0-100Cumulative % held by top 10 wallets, liquidity pools excluded
    top3_holders_pct0-100Cumulative % held by top 3 wallets, same source and denominator as top 10. Returns null rather than a contradictory value on legacy rows.
    creator_holds_pct0-100Deployer wallet's share of supply
    lp_burnedbooleanLP tokens verifiably burned
    lp_lockedbooleanLP tokens locked in a known locker
    mint_authority_revokedbooleanSupply can no longer be inflated
    freeze_authority_revokedbooleanAccounts can no longer be frozen
    is_mutablebooleanMetadata can still be changed by the deployer
    Intelligence

    These are independent diagnostics — they explain why a token scored the way it did and are not double-counted inside radar_score, so you can safely build your own weighting on top of them.

    FieldRangeMeaning
    lp_health_score0-100 (higher = healthier)Liquidity depth, burn/lock state, and provider concentration
    volume_consistency0-100 (higher = steadier)How evenly volume is distributed across windows — low values suggest wash spikes
    wallet_risk_score0-100 (higher = safer)Holder concentration, sniper/sybil clustering, and early sell pressure. 100 is safest.
    time_to_peak_estimatefast / medium / slowHistorical pattern match for how quickly comparable calls topped out

    Any field can return null when a source hasn't indexed the token yet. Treat null as "unknown", never as 0.

    GET
    /token/:address

    Returns detailed data for a specific token by its address.

    Response

    {
      "success": true,
      "token": {
        "address": "ABC123...",
        "name": "TokenName",
        "symbol": "TKN",
        "website": "https://...",
        "twitter": "@handle",
        "image": "https://...",
        "current": {
          "price": 0.000148,
          "market_cap": 148000,
          "liquidity": 12400,
          "volume_5m": 22100,
          "volume_15m": 41800,
          "volume_1h": 85000,
          "buys": 24,
          "sells": 9,
          "holders": 156,
          "radar_score": 82,
          "data_source": "live"
        },
        "radar": {
          "first_seen": "2026-01-28T14:18:00Z",
          "first_call_mc": 95000,
          "peak_mc": 180000,
          "trigger_reason": "High volume + strong buy pressure"
        },
        "risk": {
          "level": "Low",
          "score": 250,
          "lp_warning": null,
          "top_10_holders_pct": 42.5,
          "creator_holds_pct": 3.2,
          "lp_burned": true,
          "lp_locked": false,
          "mint_authority_revoked": true,
          "freeze_authority_revoked": true,
          "is_mutable": false,
          "top3_holders_pct": 18.1
        },
        "intelligence": {
          "lp_health_score": 72,
          "volume_consistency": 85,
          "wallet_risk_score": 68,
          "time_to_peak_estimate": "fast"
        }
      }
    }
    GET
    /calls
    New

    Returns historical radar calls with performance metrics. Query by date or last N days.

    Query Parameters

    ParameterTypeDefaultDescription
    datestring-Specific date (YYYY-MM-DD)
    daysinteger7Days to look back (ignored if date provided)
    limitinteger100Max results (max: 500)
    min_multipliernumber0Minimum peak multiplier (e.g., 2 = 2x)

    Response

    {
      "success": true,
      "timestamp": "2026-01-28T15:00:00Z",
      "period": {
        "start": "2026-01-21",
        "end": "2026-01-28"
      },
      "total_calls": 156,
      "calls": [
        {
          "address": "ABC123...",
          "name": "PepeGPT",
          "symbol": "PGPT",
          "image": "https://...",
          "call_date": "2026-01-28",
          "first_seen": "2026-01-28T14:18:00Z",
          "first_call_mc": 95000,
          "peak_mc": 285000,
          "multiplier": 3.0,
          "radar_score": 82,
          "trigger_reason": "High volume + strong buy pressure",
          "risk_level": "Low",
          "risk_score": 250
        }
      ]
    }
    GET
    /status

    Health check and usage statistics for your API key.

    Response

    {
      "success": true,
      "api_version": "1.0",
      "key_name": "ClawdBot",
      "requests_today": 142,
      "requests_total": 5840,
      "daily_limit": 10000,
      "tier": "degen"
    }

    Rate Limits

    TierRequests/MinuteRequests/Day
    Degen (Pro)10010,000
    Chad (Enterprise)20050,000

    When rate limited, you'll receive a 429 status code. Wait for the specified retry period before making more requests.

    Error Responses

    401

    unauthorized

    Invalid or missing API key

    403

    forbidden

    API access requires Chad tier

    403

    subscription_expired

    Your subscription has expired

    429

    rate_limited

    Rate limit exceeded. Try again later.

    404

    not_found

    Endpoint or resource not found

    Code Examples

    import requests
    
    API_KEY = "smr_your_api_key_here"
    BASE_URL = "https://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/api"
    
    headers = {"Authorization": f"Bearer {API_KEY}"}
    
    # Get current signals
    response = requests.get(f"{BASE_URL}/signals", headers=headers)
    signals = response.json()
    
    for signal in signals["signals"]:
        print(f"{signal['symbol']}: Score {signal['radar_score']}, MC ${signal['market_cap']:,.0f}")
    
    # Get historical calls (last 7 days, 2x+ multiplier)
    response = requests.get(
        f"{BASE_URL}/calls",
        headers=headers,
        params={"days": 7, "min_multiplier": 2}
    )
    calls = response.json()
    
    for call in calls["calls"]:
        print(f"{call['symbol']}: {call['multiplier']:.1f}x (${call['first_call_mc']:,} → ${call['peak_mc']:,})")

    WebSocket (Real-Time)
    New

    Connections are not persistent

    WebSocket connections run on serverless edge infrastructure and will disconnect — due to inactivity timeouts, heartbeat failures, or platform-level restarts. Your client must implement auto-reconnect with exponential backoff. Use the example below as a starting point.

    Connection

    Connect to the WebSocket endpoint for real-time radar signals. Authenticate using your API key as a query parameter.

    wss://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/ws?api-key=smr_your_key

    Events

    EventDirectionDescription
    connectedServer → ClientSent on successful connection
    signal_newServer → ClientNew token added to radar (full payload). Also fired when a previously hidden token re-appears.
    signal_updateServer → ClientSignal score/reason/tier changed (full enriched payload, same schema as signal_new)
    signal_removedServer → ClientToken removed from radar
    snapshotServer → ClientSent automatically on connect — contains all active signals so you catch up on anything missed during disconnects
    pingServer → ClientHeartbeat every 30s
    pongClient → ServerClient must respond to pings
    replayClient → ServerRequest a fresh snapshot of all active signals on demand

    signal_new Payload

    {
      "event": "signal_new",
      "timestamp": 1707928800000,
      "data": {
        "address": "ABC123...",
        "name": "PepeGPT",
        "symbol": "PGPT",
        "radar_score": 82,
        "market_cap": 148000,
        "liquidity": 12400,
        "volume_5m": 22100,
        "volume_1h": 85000,
        "buys": 24,
        "sells": 9,
        "price": 0.000148,
        "holders": 156,
        "age_minutes": 0,
        "trigger_reason": "High volume + strong buy pressure",
        "risk_level": "Low",
        "risk_score": 250,
        "lp_health_score": 72,
        "volume_consistency": 85,
        "wallet_risk_score": 68,
        "time_to_peak_estimate": "fast",
        "first_seen": "2026-02-14T12:00:00Z",
        "data_source": "live"
      }
    }

    Connection Example — JavaScript (with auto-reconnect)

    const WS_URL = "wss://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/ws?api-key=smr_your_key";
    const MAX_BACKOFF_MS = 30_000;
    
    function connect(attempt = 0) {
      const ws = new WebSocket(WS_URL);
    
      ws.onopen = () => {
        console.log("Connected to MemeScout Radar");
        attempt = 0; // reset backoff on success
        // Snapshot is sent automatically — no need to request it
      };
    
      ws.onmessage = (event) => {
        const msg = JSON.parse(event.data);
        switch (msg.event) {
          case "snapshot":
            console.log(`Snapshot: ${msg.data.count} active signals`);
            msg.data.signals.forEach(s => console.log(`  ${s.symbol} | Score: ${s.radar_score}`));
            break;
          case "signal_new":
            console.log("New signal:", msg.data.symbol, "Score:", msg.data.radar_score);
            break;
          case "signal_update":
            console.log("Updated:", msg.data.symbol, "→ Score:", msg.data.radar_score);
            break;
          case "signal_removed":
            console.log("Removed:", msg.data.address);
            break;
          case "ping":
            ws.send(JSON.stringify({ event: "pong" }));
            break;
        }
      };
    
      ws.onclose = (e) => {
        const delay = Math.min(1000 * 2 ** attempt, MAX_BACKOFF_MS);
        console.warn(`Disconnected (${e.code}: ${e.reason}). Reconnecting in ${delay}ms...`);
        setTimeout(() => connect(attempt + 1), delay);
      };
    
      ws.onerror = (err) => {
        console.error("WebSocket error:", err);
        ws.close(); // triggers onclose → reconnect
      };
    }
    
    connect();

    Connection Example — Python (with auto-reconnect)

    import asyncio
    import websockets
    import json
    
    WS_URL = "wss://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/ws?api-key=smr_your_key"
    MAX_BACKOFF = 30
    
    async def on_signal(data):
        print(f"New: {data['symbol']} | Score: {data['radar_score']} | MC: ${data['market_cap']:,}")
    
    async def listen():
        attempt = 0
        while True:
            try:
                async with websockets.connect(WS_URL) as ws:
                    print("Connected to MemeScout Radar")
                    attempt = 0  # reset on success
                    async for raw in ws:
                        msg = json.loads(raw)
                        if msg["event"] == "snapshot":
                            print(f"Snapshot: {len(msg['data']['signals'])} active signals")
                            for s in msg["data"]["signals"]:
                                print(f"  {s['symbol']} | Score: {s['radar_score']}")
                        elif msg["event"] == "signal_new":
                            await on_signal(msg["data"])
                        elif msg["event"] == "signal_update":
                            await on_signal(msg["data"])  # same full payload
                        elif msg["event"] == "ping":
                            await ws.send(json.dumps({"event": "pong"}))
            except Exception as e:
                delay = min(2 ** attempt, MAX_BACKOFF)
                print(f"Disconnected ({e}). Reconnecting in {delay}s...")
                await asyncio.sleep(delay)
                attempt += 1
    
    asyncio.run(listen())

    Connection Limits & Behaviour

    • Max 2 concurrent connections per API key
    • Connections close after 5 minutes of inactivity (code 4008)
    • Connections close if heartbeat times out after 90s (code 4009)
    • Respond to ping events with pong to stay connected
    • Always implement reconnect logic — connections are not persistent
    • Requires Chad tier subscription

    Markdown for Agents
    AI-Ready

    Every MemeScout page is available as clean, token-efficient Markdown — ideal for AI agents, LLMs, and bots. Request any page as Markdown instead of scraping the HTML site (which returns JavaScript, not data).

    Do not scrape memescout.io/token/... directly

    MemeScout is a React SPA — the main site returns JavaScript bundles, not token data. Bots crawling https://memescout.io/token/<address> will only see JavaScript. Use the Markdown endpoint below instead.

    Endpoint

    GET https://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/markdown-for-agents?path=<path>

    No authentication required. Returns Content-Type: text/markdown with YAML front matter and an x-markdown-tokens header (estimated token count).

    Available Paths

    PathReturns
    ?path=/Site overview, navigation, radar description
    ?path=/pricingSubscription plans and FAQ
    ?path=/helpDashboard guide, radar score breakdown
    ?path=/docs/apiFull API reference
    ?path=/statsLive performance statistics (2x/5x/10x rates)
    ?path=/callsArchive overview — recent days and call counts
    ?path=/calls/YYYY-MM-DDAll tokens detected on a specific date with multipliers
    ?path=/token/:addressLive token data — price, MC, risk, radar score, multiplier

    Example — Token Detail

    # Fetch token data as Markdown (Python)
    import requests
    
    address = "BqqbcB2vdw2jnvANSxuBadnNsHdosuE9CtC599j7pump"
    url = f"https://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/markdown-for-agents?path=/token/{address}"
    
    response = requests.get(url, headers={"Accept": "text/markdown"})
    markdown = response.text
    
    # Response includes: price, market cap, liquidity, radar score,
    # risk level, top holder %, mint/freeze authority, multiplier
    print(markdown)

    Example — Specific Date Calls

    # Fetch all radar calls for a specific date
    curl "https://hctbncqmdygeymmtqjmj.supabase.co/functions/v1/markdown-for-agents?path=/calls/2026-03-24" \
      -H "Accept: text/markdown"
    
    # Returns: table of all tokens detected that day
    # Columns: Token, Symbol, Score, First MC, Peak MC, Multiplier, Trigger

    Discovery via robots.txt and llms.txt

    The markdown endpoint is advertised in /robots.txt and /llms.txt. Key pages also include a <link rel="alternate" type="text/markdown"> tag pointing directly to the markdown URL for that page.

    Ready to get started?

    Generate your API key and start building with Solana Meme Radar.