Docs / Get started
Pagination
Only List large transfers has cursor pagination. It returns rows newest first, by row id.
| Part | Meaning |
|---|---|
limit | Rows per page, from 1 to 100. Default 25. |
before | Return rows with an id lower than this value. |
meta.next_cursor | The id of the last row on this page. Pass it as before. It is null on the last page. |
Keep all your filters the same on each page. The cursor carries no filter state.
#How it behaves
- The cursor is the integer row id. It is stable, and a page never shifts when new rows arrive, because new rows always get higher ids.
- New rows that arrive during a walk do not appear in later pages. To catch them, start again from the top and stop at the first
idyou already hold. - Rows older than 7 days are deleted once per hour. An old cursor stays valid, and it finds fewer rows as old ones expire.
- Row ids follow insert order, not block order. On EVM chains a poll can insert an older block's log after a newer block's native transfer, so
tsis not strictly falling across a page. Sort bytsorblockyourself if you need chain order.
Each page costs 1 unit. With no key, a limit of 30 units per minute caps a walk at 3,000 rows per minute. With a key, it caps at 12,000.
#Full loop
These loops read all transfers on Base of at least $1,000,000. They stop when next_cursor is null.
#!/usr/bin/env bash
# Needs curl and jq. Prints one JSON row per line.
base="https://farbeamlabs.com/api/v1/transfers?chain=base&min_usd=1000000&limit=100"
cursor=""
while :; do
url="$base"
[ -n "$cursor" ] && url="$base&before=$cursor"
page=$(curl -s -H "Authorization: Bearer $FARBEAM_KEY" "$url")
echo "$page" | jq -c '.data[]'
cursor=$(echo "$page" | jq -r '.meta.next_cursor // empty')
[ -z "$cursor" ] && break
sleep 1
doneconst BASE = "https://farbeamlabs.com/api/v1/transfers";
async function* walk(params) {
let before = null;
while (true) {
const query = new URLSearchParams({ ...params, limit: "100" });
if (before) query.set("before", String(before));
const res = await fetch(`${BASE}?${query}`, {
headers: { Authorization: `Bearer ${process.env.FARBEAM_KEY}` },
});
if (res.status === 429) {
const wait = Number(res.headers.get("retry-after") || 5);
await new Promise((resolve) => setTimeout(resolve, wait * 1000));
continue;
}
const { data, meta, error } = await res.json();
if (error) throw new Error(`${error.code}: ${error.message}`);
yield* data;
if (meta.next_cursor === null) return;
before = meta.next_cursor;
}
}
let total = 0;
for await (const row of walk({ chain: "base", min_usd: "1000000" })) {
total += row.usd;
}
console.log(total);import os, time
import requests
BASE = "https://farbeamlabs.com/api/v1/transfers"
HEADERS = {"Authorization": f"Bearer {os.environ['FARBEAM_KEY']}"}
def walk(**params):
before = None
while True:
query = {**params, "limit": 100}
if before:
query["before"] = before
res = requests.get(BASE, params=query, headers=HEADERS, timeout=30)
if res.status_code == 429:
time.sleep(int(res.headers.get("retry-after", 5)))
continue
body = res.json()
if "error" in body:
raise RuntimeError(body["error"]["code"])
yield from body["data"]
before = body["meta"]["next_cursor"]
if before is None:
return
print(sum(row["usd"] for row in walk(chain="base", min_usd=1000000)))#Catching up from a known point
To fetch only rows newer than a row you hold, walk from the top and stop at your last id. This is the method to fill a gap after a stream drops. See the streaming guide.
JavaScript
async function newerThan(lastId) {
const rows = [];
let before = null;
while (true) {
const query = new URLSearchParams({ limit: "100" });
if (before) query.set("before", String(before));
const res = await fetch(`https://farbeamlabs.com/api/v1/transfers?${query}`);
const { data, meta } = await res.json();
for (const row of data) {
if (row.id <= lastId) return rows;
rows.push(row);
}
if (meta.next_cursor === null) return rows;
before = meta.next_cursor;
}
}#Endpoints without a cursor
| Endpoint | How to limit it |
|---|---|
/chains/{chain}/blocks | limit from 1 to 25. The list is kept in memory and holds 25 blocks at most. |
/rules/{id}/deliveries | limit from 1 to 100. Newest first, and no older pages. |
/transfers/stats | hours from 1 to 168. Returns aggregates. |
/status/history | hours from 1 to 720. Returns every sample in the window. |
/labels | q, type and chain filters. Returns the whole match set. |
Rows beyond the 7 day window are not available through any endpoint. A historical archive and data exports are Planned.