Ключевые выводыЭндпоинта новых пар нет, и ни один маршрут не принимает фильтр «создано после».
- Эндпоинта новых пар нет, и ни один маршрут не принимает фильтр «создано после».
- Схема профиля не обещает отметки времени: «новое» — это то, чего ваш клиент ещё не видел.
pairCreatedAt— поле объекта Pair, допускающее null: по нему фильтруют локально, а не запрашивают.- Лимиты двухуровневые: 60 запросов в минуту у лент обнаружения и 300 у запросов пар и токенов.
- Ключуйте состояние по
chainId:pairAddress— у токена позже могут появиться новые пулы. - DexScreener — индексатор без опубликованной задержки обнаружения: быть первым на запуске можно только с ончейн-источником.
Краткое содержание подготовлено с помощью ИИ.
Эндпоинт, который все ищут
Начнём с полной документированной поверхности — именно она закрывает вопрос. Публичный справочник на api.dexscreener.com перечисляет эти маршруты и никаких других:
| Маршрут | Лимит |
|---|---|
/token-profiles/latest/v1 |
60 запросов/мин |
/token-profiles/recent-updates/v1 |
60 запросов/мин |
/community-takeovers/latest/v1 |
60 запросов/мин |
/ads/latest/v1 |
60 запросов/мин |
/token-boosts/latest/v1, /token-boosts/top/v1 |
60 запросов/мин |
/orders/v1/{chainId}/{tokenAddress} |
60 запросов/мин |
/metas/trending/v1, /metas/meta/v1/{slug} |
60 запросов/мин |
/latest/dex/pairs/{chainId}/{pairId} |
300 запросов/мин |
/latest/dex/search |
300 запросов/мин |
/token-pairs/v1/{chainId}/{tokenAddress} |
300 запросов/мин |
/tokens/v1/{chainId}/{tokenAddresses} |
300 запросов/мин |
Маршрута «новые пары» в этом списке нет, как нет и маршрута, принимающего фильтр «создано после». Документация эндпоинта пар описывает точечный запрос: /latest/dex/pairs/{chainId}/{pairId} возвращает одну конкретную пару, адрес которой вы уже знаете. Того «эндпоинта последних пар», который ищут, — чтобы отдал всё созданное за последние десять минут, — в публичном API не существует. То, что сайт показывает на вкладке новых пар, документированным маршрутом не открыто.
Отсюда же растёт и сам поисковый спрос. Скринер новых пар на сайте заметно богаче документированного API: он фильтрует всю проиндексированную вселенную пар по возрасту, сети, ликвидности, объёму, лаунчпаду и наличию профиля и сортирует прямо по возрасту. Ни один документированный REST-запрос эту вселенную не открывает. Публичный API позволяет получить пары только после того, как у вас уже есть кандидат — токен или пара, — а это совсем другая точка старта.
Большую часть путаницы вокруг темы снимает разделение трёх задач:
| Задача | Откуда это берётся на самом деле |
|---|---|
| Каждый созданный пул в момент появления | Ончейн-RPC, подписка на логи или собственная лента лаунчпада |
| Новые или недавно обновлённые профили токенов | /token-profiles/latest/v1 и /token-profiles/recent-updates/v1 |
| Возраст уже найденной пары | Поле pairCreatedAt в объекте Pair |
Ещё две вещи стоит заметить, глядя на эту таблицу. Каждый вызов — обычный GET без ключа и аутентификации. И лимиты делятся на два уровня: 60 в минуту у «поисковых» маршрутов и 300 у запросов пар и токенов. Это различие определяет все дальнейшие решения: эндпоинты, которыми токены находят, — дефицитные, а те, которыми их обогащают, в пять раз щедрее.
Что на самом деле возвращают token-profiles и token-boosts
Маршрут последних профилей токенов — ближайшее к ленте обнаружения, и его схема меньше, чем ожидают: url, chainId, tokenAddress, icon, header, description и массив links. И всё.
Перечитайте список и заметьте, чего схема не обещает: отметки времени. В документированном контракте нет ничего, что позволяло бы сортировать или фильтровать профили по возрасту, а слово «latest» описывает порядок, который применяет эндпоинт, а не поле, с которым можно работать.
На практике живой эндпоинт сейчас возвращает больше, чем перечислено в схеме, — отметку updatedAt вместе с полями вроде cto и openGraph. Это полезно знать, но с двумя оговорками, которые важнее самого удобства. Это не время создания пары: поле отражает активность по профилю, а не момент появления пула. И оно не входит в документированный контракт, то есть может измениться или исчезнуть без смены версии. Читайте его, если оно помогает вашему диффу, но не стройте на нём конвейер и никогда не подменяйте им pairCreatedAt.
Та же форма у community takeovers и у бустов: бусты добавляют данные о продвижении, а не о создании.
Отсюда прямое следствие для архитектуры: состояние живёт в вашем клиенте, а не в API. Вы опрашиваете, сравниваете полученный набор с уже сохранённым, и всё невиданное считается «новым». Пропустите опрос — и записи можно потерять совсем: курсора, с которого можно продолжить, здесь нет.
И эти ленты избирательны, но не совсем так, как это обычно описывают. Токены листятся на DexScreener автоматически, а метаданные профиля могут подтягиваться из внешних списков токенов; платный продукт расширенной информации — это способ предоставить или обновить эти данные быстрее и на своих условиях. Бусты же — прямо покупаемый продукт продвижения. Поэтому точная формулировка такая: перед вами лента активности профилей и метаданных, а не поток всех пулов, коснувшихся DEX за последнюю минуту. Для сканера это иногда ровно то, что нужно, а иногда — ровно то, что не нужно.
Эндпоинт последних токенов, на который ссылаются старые туториалы, — /latest/dex/tokens/{tokenAddresses} — относится к прежнему поколению этого API. Актуальный справочник документирует вместо него /tokens/v1/{chainId}/{tokenAddresses}, а «документация latest dex tokens», которую вы найдёте в постах годичной давности, указывает на устаревший путь. Используйте версионированный маршрут.
Как фильтровать по pairCreatedAt постфактум
Вот здесь и находится настоящий ответ. Поле pairCreatedAt входит в объект Pair — ту форму, которую возвращают маршруты запроса пар и токенов, — и в схеме это целое число, допускающее null. Это Unix-время в миллисекундах, и допустимость null важна: часть пар приходит без него, поэтому код, считающий поле обязательным, упадёт на первой же такой.
Главное — это поле ответа, а не параметр запроса. Никакого pairCreatedAt_gt отправить нельзя. Поэтому рабочая схема двухэтапная: находим адреса токенов-кандидатов на лентах с лимитом 60 в минуту, затем запрашиваем их пары на маршрутах с лимитом 300 и фильтруем по возрасту локально.
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] # допускаем обе формы
def pairs_for_token(chain_id, token_address): # уровень 300 запросов/мин
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(): # кандидаты, перепроверяются каждый цикл
for pair in pairs_for_token(profile["chainId"], profile["tokenAddress"]):
key = f"{pair['chainId']}:{pair['pairAddress']}"
if key in seen_pairs: # ваше хранилище — единственный курсор
continue
created = pair.get("pairCreatedAt") # может быть null — не предполагайте
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} мин {p['url']}")
На что смотреть — и это та деталь, которую чаще всего реализуют неверно: состояние ключуется по паре, а не по токену. У одного токена может быть много пулов — именно поэтому /token-pairs/v1/{chainId}/{tokenAddress} возвращает список, — и если пометить как виденный токен, то новый пул, созданный для него завтра, не будет обнаружен никогда. Ключ chainId:pairAddress и перепроверка кандидатов каждый цикл это исправляют. pairCreatedAt читается через .get и проверяется на истинность, потому что в схеме допускает null. А два уровня лимитов соблюдены самой конструкцией: один вызов за цикл к ленте с лимитом 60 и более дешёвый маршрут с лимитом 300 для обогащения.
Чего пример намеренно не делает: нет персистентности, поэтому после перезапуска он сообщит обо всём заново (кладите seen_pairs в Redis или файл); нет отступления при упоре в лимит; нет устаревания списка кандидатов, поэтому набор токенов только растёт; нет обработки случая, когда у токена много пулов, а нужен самый ликвидный. И постоянная оговорка: токен попадает в этот цикл, только если у него есть профиль, — то есть даже корректный детектор по парам видит подмножество новых пар, а не все.
Как сузить до одной сети
Большая часть поискового спроса вокруг темы касается одной сети, обычно Solana, и ответ API на «новые пары в Solana» снова непрямой. Ленты обнаружения не принимают параметр сети вовсе, поэтому фильтровать нужно по полю chainId уже после получения ответа — одной строкой в цикле выше.
Сеть как параметр пути есть у маршрутов запроса: /token-pairs/v1/{chainId}/{tokenAddress} и /tokens/v1/{chainId}/{tokenAddresses} для токенов, которые у вас уже есть, и /latest/dex/pairs/{chainId}/{pairId} для конкретной пары. Этим и исчерпывается «последние пары по сети» в документированном API: привязка к сети существует для запросов, но не для обнаружения.
Ещё два угла, о которых стоит знать. /latest/dex/search относится к уровню 300 в минуту и принимает свободный текстовый запрос — это удобно для обогащения и поиска пар по тикеру или адресу, хотя лентой новых пар по сети он тоже не является. И маршрут, который легко пропустить: /metas/meta/v1/{slug} возвращает полные объекты Pair пачкой по слагу тренда, — то есть если вас интересует тематика, а не полнота, это документированный способ получить много пар вместе с их pairCreatedAt одним вызовом уровня 60 в минуту.
Честное ограничение здесь архитектурное, а не числовое. DexScreener — индексатор, а не источник событий самой сети: токены листятся автоматически, как только появился пул и прошла хотя бы одна сделка, а логи блокчейна обрабатываются по собственному расписанию. Гарантии задержки обнаружения не публикуются, поэтому не предполагайте детерминированную цифру ни в одну сторону — и не берите её из чужого блог-поста. Если вашей стратегии важны секунды, обнаруживайте создание пула ончейн, а DexScreener используйте для обогащения того, что ваш стек уже нашёл.
Поток вместо опроса
Естественный следующий вопрос — нельзя ли подписаться вместо опроса, и ответ утвердительный, только на странице, отдельной от REST-справочника. DexScreener документирует WebSocket API на wss://api.dexscreener.com, и его пути зеркалят REST-ленты: /token-profiles/latest/v1, /token-profiles/recent-updates/v1, /token-boosts/latest/v1, /token-boosts/top/v1, /community-takeovers/latest/v1, /ads/latest/v1.
Две вещи нужно знать до перехода. Нагрузка обёрнута: сервер присылает {"limit": 90, "data": [ ... ]}, а не голый массив, как REST, — и клиент, написанный под REST, сломается на лишнем слое. И потоки покрывают ровно ленты профилей и бустов, а не создание пар: подписка даёт активность профилей по факту и снимает задачу диффа из цикла выше, но всех новых пулов по-прежнему не выдаёт.
Поток помогает там, где опрос слабее всего: запись, появившаяся и исчезнувшая между двумя опросами, для поллера невидима, а для подписчика — нет. Чего он не меняет, так это стороны обогащения: вы всё так же тратите уровень 300 запросов в минуту, превращая кандидатов в пары с ликвидностью, объёмом и временем создания. И постоянное хранилище остаётся нужным: документация вебсокета описывает подключение и нагрузку, но не семантику переподключения, — считайте обрыв разрывом в состоянии, принимайте нагрузку рукопожатия за новую точку отсчёта и сверяйтесь с тем, что уже накоплено.
Инфраструктурным вопрос становится на масштабе: несколько сетей, несколько стратегий, растущий список наблюдения. Но с одним допущением здесь стоит быть осторожным. Справочник задаёт 60 и 300 запросов в минуту на эндпоинт, однако область действия ограничителя он не определяет: там не сказано, что бюджет считается по IP-адресу, не обещан независимый лимит каждому адресу и не описана модель всплесков. Поэтому правильный порядок такой: сначала измерьте область действия на живом поведении и только затем решайте, действительно ли отдельные воркеры получают независимые бюджеты. Что означают эти два уровня на практике, — в нашем руководстве по лимитам DexScreener. Если измерения это подтверждают, наши персональные прокси дают выделенные IPv4-адреса, статичные на весь срок плана, по одному на воркера, — а перед масштабированием парка опроса сверьтесь с условиями использования DexScreener.