Insights

XRPL Token Search API

One endpoint, fuzzy-matched across name, symbol, issuer, and MD5. Free tier is plenty for a token picker; rate-limited only on anonymous use.

Why a Search Endpoint

Building a token selector from scratch means indexing the whole XRPL catalog, keeping it fresh, and doing relevance scoring. That’s the problem we already solved for the xrpl.to frontend, and the same index is exposed over HTTP. Powers autocomplete bars, wallet address pickers, swap widgets, and any UI where a user types a token name and picks from suggestions.

Endpoint

POST https://api.xrpl.to/search
Content-Type: application/json

{ "search": "solo" }

Returns three arrays — tokens, collections (NFT collections), and account (matched XRPL accounts). In most UIs you only render tokens.

Typical Response Shape

{
  "tokens": [
    {
      "md5":    "534f4c4f00000000000000000000000000000000",
      "name":   "SOLO",
      "issuer": "rsoLo2S1kiGeCcn6hCUXVrCpGMWLrRrLZz",
      "slug":   "solo",
      "exch":   2.341,
      "marketcap": 185000000,
      "vol24h": 4100000,
      "holders": 41230
    }
  ],
  "collections": [],
  "account":     []
}

Results are ranked by a combined score of name match + volume + holders, so the token a user actually means is almost always first.

Autocomplete Pattern

Debounce input, post the query, render the first 5–10 tokens. Include the token icon via /thumb/<md5>:

async function searchTokens(query) {
  const res = await fetch('https://api.xrpl.to/search', {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify({ search: query })
  });
  const { tokens } = await res.json();
  return tokens.slice(0, 10).map(t => ({
    id:     t.md5,
    name:   t.name,
    issuer: t.issuer,
    icon:   `/api/proxy/api/thumb/${t.md5}`,
    price:  t.exch
  }));
}

// Usage — debounce 250ms between keystrokes
const debounce = (fn, ms) => {
  let h; return (...args) => { clearTimeout(h); h = setTimeout(() => fn(...args), ms); };
};
const onType = debounce(async (q) => {
  if (q.length < 2) return;
  const results = await searchTokens(q);
  renderDropdown(results);
}, 250);

Match Behavior

  • Prefix + substring on name — typing sol hits SOLO, Solana-wrapped variants, etc.
  • Exact on md5 (32-hex chars), issuer (r-address), and slug.
  • Ranked by relevance × volume × holders, so tiny impostor tokens never crowd out the real one.

Rate Limits

Anonymous: 7 requests/minute per IP — enough for a responsive 250ms-debounced search bar used by one person. For production apps serving many users, grab a free developer key (90 req/min) or go paid for higher limits. Platform-key bypass is available for OEM partnerships.

Every rate-limited 429 response carries a Link header and a hint field pointing back to the signup page, so client-side error handling can surface the upgrade path automatically.

Common Pitfalls

  • Don’t use GET. The legacy /tokens?search= pattern works but returns a different (paginated) shape. Always POST /search.
  • Treat the issuer as part of the identity. Two different issuers can both mint a token called “USD”. When the user picks a result, store md5 (or issuer+currency), not just the name.
  • Cache client-side for 30s per query. Users often backspace and retype the same prefix.

Build With It