Canisellfor bots & agents

Token risk API · Base · x402

Can your bot sell it? Find out for one cent.

Send a new ERC-20 address on Base, get back SAFE, CAUTION or DANGER with the reasons behind it. The check simulates a buy and a sell, reads the tax, the owner's powers, the liquidity and the token's age. You pay per call in USDC over x402: no account, no API key.

  • $0.01 per check
  • $0.05 per batch of 10
  • MCP tool for Claude Desktop & Cursor

Taken from the free /v1/sample endpoint. It is an established token, so this is what a clean result looks like; the API is built for tokens that launched hours or days ago.

01 / CHECKS

Five things a bot needs to know before it buys

aCan it be soldA buy and a sell are simulated with eth_call state overrides against the best pool (Uniswap v2/v3/v4, Aerodrome). If the sell reverts, that is the strongest risk signal the API has.
bBuy & sell taxMeasured from the simulation, not read from the source. The round-trip loss (fees, hook taxes, slippage) is reported next to it.
cOwner powersWhether ownership is renounced, and whether the contract exposes mint, blacklist, pause, fee setters, trading switches or limit setters. Detects EIP-1967 and similar upgradeable proxies.
dLiquidityExit depth in USD across pools, and whether the LP tokens are burned, locked by a known launchpad (Clanker, Zora), or unknown.
eToken ageHow long ago the contract was created, plus creator signals: share of supply held, repeat deployers, fresh wallets.
02 / VERDICT

A label, a score, and the reasons in plain English

SAFEscore 75–100

Buy and sell simulate cleanly and no abusive owner controls were found. It does not mean the price will hold.

CAUTIONscore 45–74

Tradeable, but with risk signals such as taxes, active owner powers, thin liquidity or an upgradeable proxy.

DANGERscore below 45, or any critical signal

For example a failed simulated sell, a tax of 50% or more, or no pool on the supported DEXes.

GET /v1/sample · free · response, trimmed
{
  "address": "0x532f27101965dd16442E59d40670FaF5eBB142E4",
  "chain": "base",
  "verdict": "SAFE",
  "score": 95,
  "summary": "No blocking risks found: buy and sell simulate cleanly and no abusive owner controls detected.",
  "reasons": [
    "LP lock status unknown (position NFT); liquidity may be removable.",
    "Buy and sell simulated OK; round trip costs 2.0%.",
    "Exit liquidity ~$1.0M.",
    "Ownership renounced.",
    "Token is older than 30 days."
  ],
  "findings": [
    {
      "id": "lp_unknown",
      "severity": "low",
      "penalty": 5,
      "message": "LP lock status unknown (position NFT); liquidity may be removable."
    },
    {
      "id": "roundtrip_ok",
      "severity": "info",
      "penalty": 0,
      "message": "Buy and sell simulated OK; round trip costs 2.0%."
    },
    // 3 more findings omitted for display
  ],
  "token": {
    "name": "Brett",
    "symbol": "BRETT",
    "decimals": 18
  },
  "launchpad": null,
  "flags": {
    "trading": {
      "canBuy": true,
      "canSell": true,
      "buyTaxPct": 0,
      "sellTaxPct": 0,
      "roundTripLossPct": 1.99,
      "poolKind": "uniswap-v3"
    },
    "ownership": {
      "owner": "0x0000000000000000000000000000000000000000",
      "ownerSource": "owner()",
      "renounced": true,
      "capabilities": {
        "tradingToggle": [
          "enableTrading()"
        ],
        "feeExemption": [
          "excludeFromFees(address,bool)"
        ]
      },
      "proxy": {
        "kind": "none"
      }
    },
    "liquidity": {
      "totalDepthUsd": 1036551,
      "pools": [
        {
          "kind": "uniswap-v3",
          "id": "0xBA3F945812a83471d709BCe9C3CA699A19FB46f7",
          "quote": "0x4200000000000000000000000000000000000006",
          "quoteSymbol": "WETH",
          "depthQuote": 303.785329,
          "depthUsd": 688673,
          "lp": {
            "status": "unknown"
          },
          "source": "factory"
        },
        // 7 more pools omitted for display
      ]
    },
    "creator": {},
    "age": {
      "olderThanDays": 30
    }
  },
  "meta": {
    "block": 53369630,
    "checkedAt": "2026-11-01T10:23:28.499Z",
    "latencyMs": 1274,
    "engine": "0.1.0",
    "partial": [],
    "disclaimer": "Automated on-chain risk signals for Base, not financial advice. A SAFE verdict means no mechanical trap was detected, not that the price will hold."
  }
}

Real output of the free sample endpoint for an established token, checked 2026-11-01. Display-trimmed: some fields are removed and three findings and seven pools are left out. reasons is sorted most severe first; findings carries the same items with an id, a severity (critical, high, medium, low, info) and the score penalty. Batch calls return {"results": [...]} and report a per-address error instead of failing the whole call.

03 / QUICKSTART

Three lines. The third one pays.

shell
curl {{API_URL}}/v1/sample                        # 1. free: see the response shape
curl -i {{API_URL}}/v1/verdict/0xTOKEN            # 2. HTTP 402 + USDC payment terms
node check.mjs 0xTOKEN                            # 3. signs the 402, retries, prints the verdict
  • The sample and health endpoints need nothing.
  • The 402 response carries the price, the USDC asset on Base and the pay-to address in its PAYMENT-REQUIRED header (base64 JSON). Any x402 client can read it.
  • check.mjs is the short script below. It uses the standard @x402/fetch client, so the wallet only signs a USDC transfer authorization for the exact price.
check.mjs (JavaScript, about 10 lines)
check.mjs · npm i @x402/fetch @x402/evm viem
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

// use a dedicated wallet that holds a few dollars of USDC on Base
const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY);
const pay = wrapFetchWithPaymentFromConfig(fetch, {
  schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});

const res = await pay(`{{API_URL}}/v1/verdict/${process.argv[2]}`);
console.log(JSON.stringify(await res.json(), null, 2));
Batch: up to 10 addresses for $0.05
curl -X POST {{API_URL}}/v1/verdict/batch \
  -H 'content-type: application/json' \
  -d '{"addresses": ["0xTOKEN1", "0xTOKEN2"]}'      # same 402 flow; use `pay(url, { method: "POST", ... })`

Malformed addresses get HTTP 400 and addresses that are not tokens get 422. Failed checks are not settled, so you are not charged for them.

04 / PRICING

Pay for the calls you make. Nothing else.

One token

$0.01USDC

GET /v1/verdict/{address}

Batch of up to 10

$0.05USDC

POST /v1/verdict/batch
$0.005 per token, duplicates removed.

Free: / (service description), /v1/health (RPC reachability) and /v1/sample (example response). Payment is in USDC on Base through the x402 protocol: the server keeps no accounts or keys, a facilitator verifies and settles each payment. Results are cached for 60 seconds per address.

05 / LIMITS

What this is not

  • Heuristics, not advice. The output is automated on-chain risk signals. It is not financial advice and not an audit. A SAFE verdict means no mechanical trap was detected at that block, not that the price will hold or that the token cannot be rugged later.
  • A snapshot. An owner who keeps powers can change the token after the check. Re-check before large trades; results are cached for 60 seconds.
  • Base mainnet only (chain 8453), and ERC-20 tokens traded on Uniswap v2/v3/v4 or Aerodrome pools. Tokens that trade elsewhere may show as having no pool.
  • The simulation is one size. The buy is simulated at roughly $20. Large orders can face more slippage, and some Uniswap v4 hooks treat a same-transaction buy and sell differently from a later sale; those cases can produce false positives or false negatives.
  • Some facts are unknowable from the chain. LP lock status is often "unknown" for position-NFT liquidity. Off-chain signals (team, social, off-DEX transfers) are not looked at.
  • Mechanics, not intent. The API reports signals for an address. It does not say who is behind a token or whether anyone meant harm.
  • Early service. Engine 0.1.0, one operator, no uptime guarantee. A free /v1/health endpoint shows whether the service can reach the chain.