Skip to main content
GET /v1/polymarket/search is a single endpoint that searches across events, markets, traders, and builders at once. One query returns up to four typed result lists, each with its own pagination cursor, which makes it a natural fit for a command palette, a typeahead dropdown, or a global search bar. The q parameter accepts a free-text term (minimum 2 characters), a slug, or a wallet address.

When to use this

  • Building a command-palette (Cmd-K) overlay that jumps to any event, market, trader, or builder.
  • Adding a typeahead dropdown that suggests results as the user types.
  • Resolving a pasted wallet address to a trader profile.
  • Powering a global search bar that groups hits by category.
Call client.search.search with just q to search all four categories. Each category comes back as its own array on the response, defaulting to 10 results per category.
const { data } = await client.search.search({
  q: "election",
});

console.log(data.events);
console.log(data.markets);
console.log(data.traders);
console.log(data.builders);
The response is a SearchResponse with events, markets, traders, and builders arrays (each may be empty or null when a category has no hits), plus the matching events_pagination, markets_pagination, traders_pagination, and builders_pagination cursors. Event hits are PolymarketEvent objects (id, event_slug, title, image_url, market_count, …), market hits are MarketResponse objects (condition_id, market_slug, question, volume_usd, …), trader hits are TraderWithPnl objects (address, name, pseudonym, profile_image, …), and builder hits are BuilderMetadata objects (builder_code, name, icon_url, …).

Scoping results with type

Searching every category costs 1 credit per category. When a surface only needs some of them, pass type as a comma-separated list of events, markets, traders, and builders to search just those. A markets-only autocomplete, for example, only needs markets.
const { data } = await client.search.search({
  q: "fed rate",
  type: "markets,events",
});
Categories left out of type are omitted from the response, so a request scoped to markets,events returns no traders or builders lists and is billed for two categories instead of four.

Looking up a wallet by address

Passing a 0x address as q performs an exact wallet lookup against the traders category. This is the path to take when a user pastes an address into your search box and you want to resolve it straight to a trader profile. Scope to type: "traders" to skip the other categories.
const { data } = await client.search.search({
  q: "0x1234567890abcdef1234567890abcdef12345678",
  type: "traders",
});

const trader = data.traders?.[0];
A matching address comes back as the first entry in traders, with the resolved address, name, pseudonym, and profile_image for the wallet.

Enriching trader hits with PnL

By default trader hits carry only profile fields. Set include_pnl to true to attach a lifetime PnL summary to each trader, which is handy when search results double as a leaderboard preview. This adds 1 credit to the request on top of the per-category cost.
const { data } = await client.search.search({
  q: "whale",
  type: "traders",
  include_pnl: true,
});

const top = data.traders?.[0];
console.log(top?.address, top?.pnl);
With include_pnl enabled, each TraderWithPnl in traders gains a pnl field holding the wallet’s lifetime PnL summary. The field is absent when include_pnl is not set.

Sorting and timeframe

sort_by controls how events and markets are ordered. It accepts volume (the default), relevance, liquidity, holders, txns, unique_traders, and the date and time fields (creation_date, start_date, end_date, start_time, end_time, created_time). Pair it with sort_dir (asc or desc, default desc). When you sort by an activity metric such as volume, txns, or unique_traders, timeframe selects the window that metric is measured over: 1m, 5m, 30m, 1h, 6h, 24h (the default), 7d, 30d, or lifetime.
const { data } = await client.search.search({
  q: "trump",
  type: "markets",
  sort_by: "volume",
  sort_dir: "desc",
  timeframe: "7d",
});
Ranking the markets list by 7-day volume surfaces what is busy right now, which is usually what a search-as-you-type box should show first.

Per-category pagination

limit caps results per category (default 10, max 250), so a single response holds at most limit events, limit markets, and so on. Each category paginates independently through its own cursor. Read pagination_key from a category’s pagination block (data.events_pagination, data.markets_pagination, data.traders_pagination, or data.builders_pagination) and feed it back as the matching request parameter (events_pagination_key, markets_pagination_key, traders_pagination_key, or builders_pagination_key) to fetch the next page of just that category.
const first = await client.search.search({ q: "election", limit: 25 });

const next = await client.search.search({
  q: "election",
  limit: 25,
  markets_pagination_key:
    first.data.markets_pagination?.pagination_key ?? undefined,
});
Each *_pagination block is a PaginationMeta with has_more and pagination_key. When has_more is false, that category has no further pages, even if other categories still do. Because the cursors are independent, you can advance markets without re-fetching events, which keeps a category-grouped results panel cheap to load more on demand.
Last modified on June 13, 2026