Farbeam
Docs / SDK guides

Recipe: stablecoin monitor

This recipe combines three things: USD stablecoin supply from DefiLlama, reference prices from CoinGecko, and stored large stablecoin transfers. It prints a short report once per run.

#The data

QuestionEndpointFieldsCache
Supply by asset, with 7 and 30 day changeStablecoin supplyassets[]10 min
Supply by chainSamechains[]10 min
Distance from $1Same, or Asset pricesprice or usd10 min, 60 s
Large mints and burnsList large transfersRows with the Null address labelOne poll

Supply covers the whole market by the source's method. Transfers cover curated tokens on indexed chains: USDC, USDT and DAI, USDbC on Base. These are different scopes, so do not divide one by the other.

#Code

Alert thresholds in this code are examples. Choose your own.

curl -s "https://farbeamlabs.com/api/v1/markets/stablecoins" \
  | jq -r '.data.assets[:10][] | [.symbol, .price, .circulating_usd, .change_7d_pct] | @tsv'
// stable.mjs: run with node stable.mjs
const API = "https://farbeamlabs.com/api/v1";
const get = async (path) => {
  const { data, error } = await (await fetch(API + path)).json();
  if (error) throw new Error(`${error.code}: ${error.message}`);
  return data;
};
const money = (n) => `$${Math.round(n).toLocaleString("en-US")}`;

const { assets, chains } = await get("/markets/stablecoins");
for (const asset of assets.slice(0, 10)) {
  const offPeg = asset.price === null ? null : Math.abs(asset.price - 1);
  const flag = offPeg !== null && offPeg > 0.005 ? "  price is more than 0.5% from $1" : "";
  console.log(asset.symbol.padEnd(8), money(asset.circulating_usd).padStart(20), `${asset.change_7d_pct}% 7d`, flag);
}
console.log("Covered chains:", chains.filter((c) => c.covered).map((c) => `${c.name} ${money(c.circulating_usd)}`).join(", "));

const rows = await get("/transfers?min_usd=1000000&limit=100");
const stable = new Set(["USDC", "USDT", "DAI", "USDbC"]);
for (const row of rows.filter((r) => stable.has(r.token))) {
  if (row.from_label === "Null address") console.log("mint", row.chain, row.token, money(row.usd), row.tx);
  if (row.to_label === "Null address") console.log("burn", row.chain, row.token, money(row.usd), row.tx);
}
# stable.py: run with python3 stable.py
import requests

API = "https://farbeamlabs.com/api/v1"

def get(path, **params):
    body = requests.get(API + path, params=params, timeout=30).json()
    if "error" in body:
        raise RuntimeError(body["error"]["code"])
    return body["data"]

data = get("/markets/stablecoins")
for asset in data["assets"][:10]:
    price = asset["price"]
    flag = "  price is more than 0.5% from $1" if price is not None and abs(price - 1) > 0.005 else ""
    print(f"{asset['symbol']:8} ${asset['circulating_usd']:>18,}  {asset['change_7d_pct']}% 7d{flag}")
print("Covered chains:", [(c["name"], c["circulating_usd"]) for c in data["chains"] if c["covered"]])

for row in get("/transfers", min_usd=1000000, limit=100):
    if row["token"] in ("USDC", "USDT", "DAI", "USDbC"):
        if row["from_label"] == "Null address":
            print("mint", row["chain"], row["token"], round(row["usd"]), row["tx"])
        if row["to_label"] == "Null address":
            print("burn", row["chain"], row["token"], round(row["usd"]), row["tx"])

This sample of one asset row was captured on 2026-11-04 UTC. It is an example.

JSON
{
  "name": "Tether",
  "symbol": "USDT",
  "mechanism": "fiat-backed",
  "price": 0.99905,
  "circulating_usd": 177773802949,
  "change_7d_pct": -2.23,
  "change_30d_pct": -3.32
}

#Alerts for large moves

Save rules for the transfer side. Each rule fires at most once per cooldown. Rules cannot read supply or price, so keep those checks in a scheduled job.

Beamline
token in ["USDC", "USDT", "DAI"] and usd >= 25m and not sampled
Beamline
from_label == "Null address" and token in ["USDC", "USDT", "DAI", "USDbC"]
Beamline
to_label == "Null address" and token in ["USDC", "USDT", "DAI", "USDbC"]

#Reading the results

ObservationWhat it can meanWhat it does not prove
Supply fell over 7 daysThe source counted less in circulationA loss of trust. Chain migration and redemptions also reduce it.
Price off $1 by a small amountNormal market noise or a source lagA depeg. Check more than one source.
Large row from Null addressA mint on that chainNew demand. Issuers also mint in advance, and bridges mint on arrival.
Large move between unlabeled walletsA transferAny intent

The price from DefiLlama and usd from /prices come from different sources and refresh at different rates. They will not match exactly, so do not build a check on a tiny difference between them.

Stablecoin valuation in Farbeam uses market prices, not a fixed $1. See USD valuation.

#Running on a schedule

Run this every 10 minutes at most for supply, since the source is cached for that long. Store the output yourself if you need a long series. Farbeam does not offer a history of these values, and a historical archive is Planned.

This recipe reports data. It makes no statement about the safety of any stablecoin, and it is not financial advice.