Skip to main content
GET
Reverse X lookup
Finds every wallet attested to an X handle. Costs 1 match credit per wallet returned, 100 per page. A handle with no wallets attached costs nothing. Separately, each request weighs 2 units against your rate limit. Only wallets whose recorded sources are all attested evidence (an onchain record, a Farcaster verification, an owner-signed link) are returned. Sources are recorded per wallet, not per handle, so a wallet whose attested link sits beside a correlated source is left out too: we cannot tell which of the two supplied the handle. A single-wallet lookup still shows it, with its labels. The total and every page follow the same rule, and an empty result means no such wallet, not that no address is attested anywhere. This lookup needs a key that belongs to an account. A key bought with USDC and no account resolves addresses but answers this one with 403 ACCOUNT_REQUIRED: turning a handle into the wallets behind it is the direction that can find a person, so somebody has to answer for the search. This runs the graph backwards, and it answers a question most wallet tooling cannot: which wallets has this account linked to itself? It is a one-time check, for example whether an account holds your token before a partnership, an allowlist or an airdrop. Following what a person holds over time is not what it is for, and the terms of service forbid it.

Path parameters

string
required
1 to 15 characters, letters, numbers and underscores. A leading @ is accepted and stripped. Case-insensitive.

Query parameters

string
Continues a paginated result: pass the next_cursor value from the previous response, unmodified. Omit it for the first page. A value this API did not produce returns INVALID_CURSOR.

Request

Response

array
Matching wallets, at most 100 per page, ordered by Farcaster reach (highest follower count first, wallets without one last, wallet address as the tiebreak). Each entry carries wallet, an always-present twitter object, and whichever of ens_name, farcaster, lens, github and sources apply, plus a flat quality_score. The twitter object carries self_declared: true when the wallet’s owner named the handle in their own record and nothing else backs it: the owner claims the handle, and the account never confirmed it. See self-declared handles.
object
quality_score here is a flat number, unlike the nested quality object on single lookup. Same scale, different shape.

One handle, many wallets

Multiple results are normal, not a bug. People keep a hot wallet and a vault, and the same handle can be attested from several addresses.

Second accounts are matched too

A wallet is returned when the handle is its primary X account or its second attested one. Some owners have attested two live X accounts from the same wallet through different evidence; a single lookup shows that as twitter.also, and searching either handle finds the wallet. A wallet matched this way has a different handle in its own twitter.handle field, and names the handle you searched for under twitter.also. The same conditions apply as for twitter.also itself: both accounts must be live, and where the attestation carried an account id it must still match. Nothing is returned on the strength of a handle we cannot corroborate. A wallet matched this way needs only that second account’s own source to be attested, and a second account from a correlated source is not matched. These wallets bill exactly as any other: 1 match credit per wallet returned. The endpoint returns at most 100 wallets per page. When truncated is true, pass meta.next_cursor back as the cursor query parameter to fetch the next page; the last page carries next_cursor: null. Each page is its own request: it weighs 2 rate-limit units and bills 1 match credit per wallet it returns. Pages walk the index in Farcaster-reach order, so the first page holds the most reachable wallets. The cursor is a position in a live index, not a snapshot: a wallet whose follower count changes mid-walk can appear twice or be skipped, and total_count can move between pages. Treat the cursor as opaque, use it promptly, and do not store it.

Errors

INVALID_HANDLE, INVALID_CURSOR, plus the standard errors. No matches is not an error: data is [] with total_count: 0 at HTTP 200.