Products
Datacenter proxies from $19/mo Rotating proxies from $49/mo ISP proxies from $33/mo Dedicated proxies from $3.50/mo UDP proxies from $5/mo Try proxies
Use cases
Data & scraping AI services Social media & messaging E-commerce & finance Media & entertainment Marketing & ads Automation & tools All use cases →
Pricing
Full pricing table All 20 locations Money-back guarantee
Resources
Blog Proxy API MCP server Setup guides FAQ For business About us Affiliate program
English
English Русский
← PapaProxy.net Blog

Where new pairs come from in the DexScreener API

The DexScreener API has no new-pairs endpoint. Its documented routes return profiles, boosts, metas and pair lookups — and the creation timestamp you're after arrives inside the response, as something you filter on yourself.

API & data · Automation August 9, 2026 4 min read Alex Young Alex Young Technical specialist
Key takeawaysThere is no new-pairs endpoint, and no route accepts a "created after" filter.
  • There is no new-pairs endpoint, and no route accepts a "created after" filter.
  • The profile schema promises no timestamp — "new" is whatever your client hasn't seen before.
  • pairCreatedAt is a nullable field on the Pair object: you filter on it locally, never query by it.
  • Limits come in two tiers: 60 requests a minute for discovery feeds, 300 for pair and token lookups.
  • Key your state on chainId:pairAddress — one token can gain new pools later.
  • DexScreener is an indexer with no published detection latency; being first to a launch needs an on-chain source.

This summary was created with AI.

The endpoint everyone looks for

Start with the full documented surface, because that's what settles the question. The public reference at api.dexscreener.com lists these routes and nothing else:

Route Limit
/token-profiles/latest/v1 60 req/min
/token-profiles/recent-updates/v1 60 req/min
/community-takeovers/latest/v1 60 req/min
/ads/latest/v1 60 req/min
/token-boosts/latest/v1, /token-boosts/top/v1 60 req/min
/orders/v1/{chainId}/{tokenAddress} 60 req/min
/metas/trending/v1, /metas/meta/v1/{slug} 60 req/min
/latest/dex/pairs/{chainId}/{pairId} 300 req/min
/latest/dex/search 300 req/min
/token-pairs/v1/{chainId}/{tokenAddress} 300 req/min
/tokens/v1/{chainId}/{tokenAddresses} 300 req/min

There is no "new pairs" route in that list, and no route that accepts a "created after" filter. The pairs endpoint documentation describes lookups: /latest/dex/pairs/{chainId}/{pairId} returns one specific pair you already know the address of. The latest dex pairs endpoint people search for — something that hands you everything created in the last ten minutes — doesn't exist in the public API. What the site shows on its new-pairs tab is not exposed as a documented route.

This is also why the search demand exists in the first place. The website's New Pairs screener is far richer than the documented API: it filters the entire indexed pair universe by age, chain, liquidity, volume, launchpad and profile status, and sorts by age directly. No documented REST query exposes that universe. The public API only lets you retrieve pairs once you already hold a token or pair candidate — which is a completely different starting point.

Keeping three tasks separate saves most of the confusion around this topic:

Goal Where it actually comes from
Every newly created pool, as it happens On-chain RPC, log subscriptions, or a launchpad's own feed
New or recently updated token profiles /token-profiles/latest/v1 and /token-profiles/recent-updates/v1
Age of a pair you already discovered pairCreatedAt on the Pair object

Two more things worth noting while you're looking at that table. Every call is a plain GET with no key and no authentication. And the limits split into two tiers — 60 per minute for the discovery-ish routes, 300 for the pair and token lookups — which turns out to shape every design decision below, because the endpoints you'd use to find tokens are the scarce ones and the endpoints you'd use to enrich them are five times more generous.

What token-profiles and token-boosts actually return

The latest token profiles route is the closest thing to a discovery feed, and its schema is smaller than people expect: url, chainId, tokenAddress, icon, header, description, and a links array. That's it.

Read that list again and note what the schema doesn't promise: no timestamp. Nothing in the documented contract lets you sort or filter profiles by age, and the word "latest" describes the ordering the endpoint applies rather than a field you can act on.

In practice the live endpoint currently returns more than the schema lists — an updatedAt timestamp alongside fields like cto and openGraph. Useful, and worth knowing about, with two caveats that matter more than the convenience. It is not a pair-creation time — it reflects profile activity, not when a pool appeared. And it isn't part of the documented contract, so it can change or disappear without a version bump. Read it if it helps your diffing, but don't let your pipeline depend on it, and never substitute it for pairCreatedAt.

The same shape applies to community takeovers and to boosts — boosts add promotion data, not creation data.

That has one direct consequence for how you build: the state lives in your client, not in the API. You poll, you diff the returned set against what you already stored, and anything unseen is your "new". Miss a poll and you may miss entries entirely, because there's no cursor to resume from.

And these feeds are selective, though not in the way it's often described. Tokens are listed on DexScreener automatically, and profile metadata can be pulled from external token lists; the paid enhanced-info product is a way to supply or update that information faster and on your own terms. Boosts are a straightforwardly purchased promotion product. So the accurate framing is that this is a feed of profile and metadata activity, not a firehose of every pool that touched a DEX in the last minute. For a scanner that's sometimes exactly what you want, and sometimes precisely what you don't.

The latest dex tokens endpoint that older tutorials cite — /latest/dex/tokens/{tokenAddresses} — belongs to an earlier generation of this API. The current reference documents /tokens/v1/{chainId}/{tokenAddresses} instead, and the latest dex tokens documentation you'll find in blog posts written a year ago points at the legacy path. Use the versioned route.

Filtering on pairCreatedAt after the fact

Here's where the actual answer lives. The pairCreatedAt field is part of the Pair object — the shape returned by the pair and token lookup routes — and in the schema it's an integer, nullable. It's a Unix timestamp in milliseconds, and being nullable matters: some pairs come back without it, so code that assumes the field is present will throw on the ones that aren't.

Crucially, it's a response field, not a query parameter. There is no pairCreatedAt_gt you can send. The working pattern is therefore two-stage: find candidate token addresses on the 60-per-minute feeds, then look up their pairs on the 300-per-minute routes and filter locally on age.

Python
import time, requests

BASE = "https://api.dexscreener.com"
HEAD = {"Accept": "application/json"}
seen_pairs: set[str] = set()      # keyed by pair, not by token — see note below

def latest_profiles():
    r = requests.get(f"{BASE}/token-profiles/latest/v1", headers=HEAD, timeout=15)
    r.raise_for_status()
    data = r.json()
    return data if isinstance(data, list) else [data]      # tolerate both shapes

def pairs_for_token(chain_id, token_address):              # 300 req/min tier
    r = requests.get(f"{BASE}/token-pairs/v1/{chain_id}/{token_address}",
                     headers=HEAD, timeout=15)
    r.raise_for_status()
    return r.json() or []

def fresh_pairs(max_age_minutes=60):
    cutoff_ms = (time.time() - max_age_minutes * 60) * 1000
    out = []
    for profile in latest_profiles():                      # candidates, re-checked every cycle
        for pair in pairs_for_token(profile["chainId"], profile["tokenAddress"]):
            key = f"{pair['chainId']}:{pair['pairAddress']}"
            if key in seen_pairs:                          # your store is the only cursor
                continue
            created = pair.get("pairCreatedAt")            # nullable — never assume
            if created and created >= cutoff_ms:
                seen_pairs.add(key)
                out.append(pair)
    return out

for p in fresh_pairs():
    age_min = (time.time() * 1000 - p["pairCreatedAt"]) / 60000
    print(f"{p['chainId']:<10} {p['baseToken']['symbol']:<12} {age_min:6.1f} min  {p['url']}")

What to look at, and this is the detail most implementations get wrong: state is keyed on the pair, not the token. One token can have many pools — that's exactly why /token-pairs/v1/{chainId}/{tokenAddress} returns a list — so if you mark a token as seen, a new pool created for it tomorrow will never be reported. Keying on chainId:pairAddress and re-enriching candidates every cycle fixes that. pairCreatedAt is read with .get and checked for truthiness because it's nullable in the schema. And the two tiers are respected by design: one call per cycle to the 60-per-minute feed, then the cheaper 300-per-minute route for enrichment.

What this deliberately doesn't do: no persistence, so a restart re-reports everything (put seen_pairs in Redis or a file); no rate-limit backoff; no candidate-list ageing, so the token set only grows; no handling for a token with many pools where you only care about the deepest. And the standing caveat — a token enters this loop only if it has a profile, so even a correct pair-keyed detector sees a subset of new pairs, not all of them.

Narrowing to a single chain

Most of the search volume around this topic is about one chain, usually Solana, and the API's answer to "new pairs on Solana" is again indirect. The discovery feeds take no chain parameter at all, so you filter on the chainId field after the response arrives — one line in the loop above.

The routes that take a chain as a path parameter are the lookup ones: /token-pairs/v1/{chainId}/{tokenAddress} and /tokens/v1/{chainId}/{tokenAddresses} for tokens you already have, and /latest/dex/pairs/{chainId}/{pairId} for a specific pair. That's the extent of latest dex pairs by chain in the documented API — chain scoping for lookups, not for discovery.

Two more angles worth knowing. /latest/dex/search sits in the 300-per-minute tier and accepts a free-text query, which makes it useful for enrichment and for finding pairs by ticker or address, though it isn't a chain-filtered new-pair feed either. And a route that's easy to miss: /metas/meta/v1/{slug} returns full Pair objects in bulk for a trend slug — so if your interest is thematic rather than exhaustive, it's a documented way to get many pairs, with their pairCreatedAt values, in one 60-per-minute call.

The honest limitation is architectural rather than numeric. DexScreener is an indexer, not a chain-native event source: it lists tokens automatically once a pool exists and has traded, and processes chain logs on its own schedule. It publishes no detection-latency guarantee, so don't assume a deterministic figure in either direction — and don't take a number from a blog post as one either. If seconds matter to your strategy, detect pool creation on-chain and use DexScreener to enrich what your own stack already found.

Streaming instead of polling

The natural next question is whether you can subscribe instead of poll, and the answer is yes — on a page separate from the REST reference. DexScreener documents a WebSocket API at wss://api.dexscreener.com whose paths mirror the REST feeds: /token-profiles/latest/v1, /token-profiles/recent-updates/v1, /token-boosts/latest/v1, /token-boosts/top/v1, /community-takeovers/latest/v1, /ads/latest/v1.

Two things to know before you switch. The payload is wrapped — the server sends {"limit": 90, "data": [ ... ]} rather than the bare array REST returns, so a client written against REST will break on the extra layer. And the streams cover exactly the profile and boost feeds, not pair creation: subscribing gets you profile activity as it happens, which removes the diffing problem in the loop above, but it still doesn't hand you every new pool.

Streaming helps most where polling is weakest: an entry that appears and disappears between two polls is invisible to a poller and visible to a subscriber. What it doesn't change is the enrichment side — you still spend the 300-per-minute tier turning candidates into pairs with liquidity, volume and creation times. And you still keep a persistent store, because the WebSocket documentation covers the connection and payload but not reconnect semantics: treat a dropped connection as a state gap, take the handshake payload as your new baseline, and reconcile against what you already have.

Where this becomes an infrastructure question is scale: several chains, several strategies, and a watchlist that grows. Be careful about one assumption here, though. The reference states 60 and 300 requests per minute per endpoint, but it doesn't define the limiter's scope — it doesn't say the budget is counted per IP address, doesn't promise an independent allowance to each address, and doesn't describe a burst model. So the correct order is: measure the scope against live behaviour first, and only then decide whether separate workers can genuinely run independent budgets. For what those two tiers mean in practice, see our DexScreener rate-limit guide. If your measurements say they can, our proxies for crypto projects provide dedicated IPv4 addresses, static for the full plan term, one per worker — and check DexScreener's terms for how they expect the API to be used before scaling a polling fleet.