Skip to main content
For Bot Developers

Build a Trading Bot on Guava

GWI is the intelligence layer — discovery, scam gating, liquidity depth, whale and liquidation signals pushed to you in real time. Execution (Jupiter, 0x, your router) stays in your bot. Everything below is either free or covered by your API key.

Push, not poll

Liquidations, new pairs, wallet events and price ticks over one WebSocket.

Gate every trade

5-source scam cross-ref + honeypot checks before you ever sign a tx.

Backtest the moat

Export the labeled scam-wallet dataset and test whether a filter would have caught the rug.

REST endpoints for bots

Public endpoints are rate-limited by IP. /api/v1/* routes authenticate with the X-API-Key header — get your key on API Access.

MethodPathUse
GET/dex/new-pairsNew-launch firehose — filter by chain, min liquidity, min volume, age
GET/dex/trades/{chain}/{address}Recent DEX buys/sells for a token
GET/dex/liquidity-changesLiquidity removal feed — rug signals in progress
GET/token/{chain}/{address}/poolsPool list + liquidity depth for position sizing
GET/tokens/{chain}/{address}/ohlcOHLCV — CoinGecko → GeckoTerminal fallback (covers meme tokens)
GET/scam-alerts/check/{chain}/{address}5-source scam cross-reference — gate every buy
GET/api/v1/token/{chain}/{contract}/securityHoneypot + 30 security checks (X-API-Key)
GET/api/v1/datasets/scam-walletsLabeled scam-wallet export for backtesting (X-API-Key)
GET/perps/fundingFunding extremes across 200+ perp markets
GET/perps/liquidationsLiquidation tape buffer

WebSocket — wss://api.guavaintel.com/ws

One connection, subscribe to the channels you need. JSON protocol:{"action":"subscribe","channels":[...]}/ unsubscribe / ping. Server pushes {"type":"event","channel":"...","data":{...}}.

perps.liquidations

Binance forced liquidations as they happen

{ "venue": "binance", "symbol": "BTCUSDT", "coin": "BTC", "side_liquidated": "long", "size_usd": 420000, "price": 113000, "ts": 1789718400000, "large": true }
new_pairs / new_pairs.{chain}

Newly discovered DEX tokens (90s poll)

{ "name": "NewToken", "symbol": "NEW", "contract_address": "0x...", "network_slug": "solana", "price": 0.00042, "liquidity": 18500, "age_hours": 0.4, "pool_count": 1 }
wallet.{chain}.{address}

Normalized on-chain events touching a wallet

{ "type": "erc20_transfer", "chain": "ethereum", "from_address": "0x...", "to_address": "0x...", "token_address": "0x...", "usd_value": 152000 }
token.{chain}.{address}

Events touching a token contract

{ "type": "erc20_transfer", "chain": "ethereum", "token_address": "0x...", "value": "1500000", "hash": "0x..." }
events.{chain}

All normalized inbound events on a chain

{ "type": "native_transfer", "chain": "ethereum", "from_address": "0x...", "to_address": "0x...", "value": "2.5" }
price.{chain}.{address}

DexScreener price tick (~15s, on change)

{ "price_usd": 0.00042, "dex": "raydium", "pair": "abc...", "change_5m": 2.1, "change_1h": -0.8, "volume_24h": 152000, "liquidity_usd": 88000 }
Subscribe (JavaScript)
// Node 18+ (built-in WebSocket) or any ws client
const ws = new WebSocket("wss://api.guavaintel.com/ws");

ws.onopen = () => {
  ws.send(JSON.stringify({
    action: "subscribe",
    channels: ["new_pairs.solana", "perps.liquidations"],
  }));
};

ws.onmessage = (m) => {
  const msg = JSON.parse(m.data);
  if (msg.type === "event" && msg.channel === "new_pairs.solana") {
    console.log("New pair:", msg.data.symbol, msg.data.liquidity);
  }
};

Outbound webhooks (Enterprise)

Prefer push over a persistent socket? Register an endpoint on the Developer page — we POST signed events to your URL. Verify every delivery with the HMAC-SHA256 secret shown once at creation.

Signature verification (Python)
import hashlib, hmac

def verify_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

# In your webhook receiver:
#   signature = request.headers["X-GWI-Signature"]
#   if not verify_signature(await request.body(), signature, WEBHOOK_SECRET):
#       return 401

Example: new-pair sniper with scam gating

Subscribe to the new-pairs feed, filter by liquidity, gate through the scam cross-reference — then hand off to your execution layer.

import asyncio, json, requests, websockets

API = "https://api.guavaintel.com"
KEY = "gw_your_key"

def gate(token):
    """Reject anything flagged by the 5-source scam cross-ref."""
    r = requests.get(f"{API}/scam-alerts/check/{token['network_slug']}/{token['contract_address']}")
    return not r.json().get("reported", False)

async def main():
    async with websockets.connect(f"wss://api.guavaintel.com/ws") as ws:
        await ws.send(json.dumps({"action": "subscribe",
                                  "channels": ["new_pairs.solana"]}))
        async for raw in ws:
            msg = json.loads(raw)
            if msg.get("type") != "event":
                continue
            t = msg["data"]
            if (t.get("liquidity") or 0) < 10000:
                continue          # too thin — skip
            if not gate(t):
                continue          # flagged — skip
            print("Candidate:", t["symbol"], t["liquidity"])
            # -> your execution layer goes here (Jupiter/0x)

asyncio.run(main())

Agent frameworks can also call GWI through the MCP server (/mcp, Streamable HTTP) — see the MCP section of the API reference.