TokensAPI

Token lists

Lists as plugins — curated and community lists, project ownership, statuses, member caps, provider budgets, and how composition works.

A token list is a named, ordered set of Solana mints with an accountable curator. The routes are on Lists; this page is the model.

Lists as plugins

Consuming apps explicitly name the lists they trust and compose them into one corpus with GET /v2/lists/tokens?lists=a,b. There is deliberately no global "all lists" union, because trust in a curator is the whole model: a list is a plugin you install, not a feed you inherit.

Curated and community lists

  • Curated lists are ours: majors, currencies, lsts, rwas, etfs, metals, stocks. The legacy aliases stables (currencies) and xstocks (etfs) are accepted wherever a slug is, on {slug} paths and in lists=. Curated slugs serve the effective curated membership and carry curated: true with a description and an owner.name.
  • Community lists are published by any API key. They carry curated: false, a null description and an owner.projectId.

The catalog (GET /v2/lists) returns every curated list plus every published community list; pagination applies to the community rows only and the curated set is prepended to page one.

Ownership

Any API key can create lists. The key that creates a list binds it to that key's project: every key on the project, regardless of read scopes, may manage that project's lists, and keys from other projects get 403 on writes. Anyone with an assets:read key can read any published or unlisted list. Moderators can lock a list, which also returns 403 on writes.

Slugs are globally unique and match ^[a-z][a-z0-9-]{2,62}$. Curated ids, their aliases and route words (all, lists, curated, tokens, search-tokens, check-slug) are reserved. Prefix by convention: ownership-core. A renamed or deleted slug is held for its previous owner for a 30-day window before anyone else can claim it.

Statuses

StatusIn the catalogReadable by slugComposableNotes
draftnoowner only via mine=trueno (notFound)Load it before anyone sees it
unlistednoyes, by anyone with the linkyesHidden from the catalog and from inLists annotations
publishedyesyesyesThe default on create
archivednoowner only via mine=trueno (notFound)The reversible hide-it option; DELETE is irreversible

GET /v2/lists?mine=true returns your project's lists in every status with status on each row, which is what a management UI should drive from.

Members and verification

A member is a mint plus an optional rank and note. Every mint must resolve somewhere when it is added: the curated registry (verified: true), then the token index, then a live provider lookup whose metadata is snapshotted onto the member. A mint unknown everywhere is rejected with unknown_mint; a malformed address with invalid_mint.

Lists may include mints outside the curated registry. Those tokens carry verified: false so your UI can render caution; verified is the only trust signal the list itself gives you.

Hydrated list tokens carry an advisory field:

StatusMeaningWhat the API does
cautionTrade with care: a known concern that does not make the token unsafe.Returned everywhere; never changes ranking or inclusion.
compromisedThe token or its issuer was exploited or has otherwise lost integrity.Never the primary variant; excluded from trending; still readable with the advisory attached.
blockedDo not trade: operators have withdrawn the token from the surface.Never the primary variant; excluded from trending, search and curated lists; still readable by id.

Each advisory carries status, reason, an optional url with more detail, since (unix milliseconds the current status was set), and source (admin for a human operator, webacy_depeg for the Webacy depeg monitor, peg_guard for the tokens.xyz peg monitor). System sources only ever set caution; escalation is a human decision. Read endpoints annotate; they never refuse. Treat compromised and blocked as do-not-trade in your UI.

On lists specifically, blocked mints are omitted from tokens during hydration (rank stays dense) and tokenCount reflects the visible tokens. The long form is in Advisories.

Caps and budgets

CapValue
Mints per batch add250 (batch_too_large)
Members per list5000 (list_full)
Lists per project100 (project_lists_limit)
Slugs per compose call10
Members composed per list5000; larger lists return truncated: true
name80 characters
note500 characters

Batch adds and single-member PUTs may reach the live provider for mints unknown to the index, so they draw from a per-key batch budget (30 calls per 10 minutes by default). Within one batch call at most about 50 unknown mints are resolved against the provider; the rest fail individually as unknown_mint and can be retried later. The curator search GET /v2/lists/search-tokens shares the search budget with /v2/search and /v2/resolve (120 calls per 10 minutes). Both budgets return 429 when exhausted; see Provider lookup budget.

Recommended automation flow: check the slug, create the list as draft, load it with one or a few batch calls, publish with PATCH { status: 'published' }, then keep it fresh with individual PUT and DELETE /members/{mint} calls. The Quickstart walks through exactly this with curl.

Composing lists

GET /v2/lists/tokens?lists=majors,acme-core returns the union of the named lists, deduped by mint, each token annotated with lists[], the requested slugs that contain it. Curated and community slugs mix freely. Unknown, draft or archived slugs are reported in notFound[] rather than failing the call, so a consumer can keep working when one of its curators disappears.

Compose responses are cached for 60 seconds and fall back to a last-good copy (up to 10 minutes old) when the list backend is unavailable; updatedAt on each list summary is the freshness signal.