Farbeam
Docs / SDK guides

Recipe: token screening

This recipe reads token reports for a list of addresses and prints the status of each check side by side. It makes reports easier to compare. It does not rank tokens, because Farbeam gives no composite score. You read the table and make your own judgment.

#Costs

A report costs 3 units. With no key, 30 units per minute allows 10 reports per minute. With a key, 120 units allow 40. The cache times on a report are 60 s for market data and 5 minutes for checks, so re-reading faster than that returns the same values and spends units.

#Code

# One token: list every check that is not a pass
curl -s "https://farbeamlabs.com/api/v1/tokens/ethereum/0xdAC17F958D2ee523a2206206994597C13D831ec7" \
  | jq -r '.data.checks[] | select(.status != "pass") | [.id, .status, .detail] | @tsv'
// screen.mjs: run with node screen.mjs
const TOKENS = [
  ["ethereum", "0xdAC17F958D2ee523a2206206994597C13D831ec7"],
  ["ethereum", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"],
  ["solana", "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"],
];
const headers = process.env.FARBEAM_KEY ? { Authorization: `Bearer ${process.env.FARBEAM_KEY}` } : {};
const pause = process.env.FARBEAM_KEY ? 1600 : 6100;

const rows = [];
for (const [chain, address] of TOKENS) {
  const res = await fetch(`https://farbeamlabs.com/api/v1/tokens/${chain}/${address}`, { headers });
  const { data, error } = await res.json();
  if (error) {
    rows.push({ token: address.slice(0, 10), error: error.code });
  } else {
    const row = {
      token: data.token.symbol ?? address.slice(0, 10),
      chain,
      liquidity: data.market?.liquidity_usd ?? null,
      failed_sources: data.sources.filter((s) => !s.ok).map((s) => s.name).join(" "),
      ...data.counts,
    };
    for (const check of data.checks) {
      if (check.status === "fail" || check.status === "warn") row[check.id] = check.status;
    }
    rows.push(row);
  }
  await new Promise((resolve) => setTimeout(resolve, pause));
}
console.table(rows);
# screen.py: run with python3 screen.py
import os, time
import requests

TOKENS = [
    ("ethereum", "0xdAC17F958D2ee523a2206206994597C13D831ec7"),
    ("ethereum", "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"),
    ("solana", "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN"),
]
key = os.environ.get("FARBEAM_KEY")
headers = {"Authorization": f"Bearer {key}"} if key else {}
pause = 1.6 if key else 6.1

for chain, address in TOKENS:
    body = requests.get(f"https://farbeamlabs.com/api/v1/tokens/{chain}/{address}", headers=headers, timeout=30).json()
    if "error" in body:
        print(address, body["error"]["code"])
    else:
        d = body["data"]
        flags = [f"{c['id']}={c['status']}" for c in d["checks"] if c["status"] in ("warn", "fail")]
        unknown = [c["id"] for c in d["checks"] if c["status"] == "unknown"]
        failed = [s["name"] for s in d["sources"] if not s["ok"]]
        liquidity = (d["market"] or {}).get("liquidity_usd")
        print(d["token"]["symbol"], chain, f"liquidity={liquidity}", flags, f"unknown={unknown}", f"failed_sources={failed}")
    time.sleep(pause)

The three tokens above are examples for the output, and they are not suggestions. Replace them with your own list.

#Reading the output

Read reading token reports first. Some rules for a table like this:

ColumnNote
fail and warn countsDo not sort by them as a score. Major stablecoins show warnings for admin powers.
unknownThis is missing information. A token with many unknowns has been checked less.
failed_sourcesWhen this is not empty, unknown probably reflects a source failure. Read again later.
liquidityA sum across pools the source returned. Outlier pools are left out.

Checks are read from third parties and can be wrong or out of date.

#Finding candidates to read

Trending pools gives a list of pools per chain. Each entry has a base_token, which you can pass to the report. A rank in that list is not a recommendation, and many new pools are thin.

Python
import requests

pools = requests.get("https://farbeamlabs.com/api/v1/markets/pools", params={"chain": "base"}, timeout=30).json()["data"]
print([p["base_token"] for p in pools[:5]])

#Handling errors

ResultMeaningAction
400 invalid_addressThe format does not match the chainCheck the chain and address pair
404 not_foundNo pool data and no token dataOften not a token. Solana reads Not a token or Not a token mint.
429 rate_limitedUnits used upWait for Retry-After
502 upstream_unavailableEvery source failedRetry later

#What this recipe does not do

It makes no decision for you, and it does not check for scam websites or social claims. It does not read the code of a contract. Screening is the start of reading about a token and does not end it. Nothing here is advice to buy, sell or hold any token.