Uma API de busca do Twitter gratuita que devolve JSON, com os operadores de busca do X

Uma API de busca do Twitter gratuita que devolve JSON, com os operadores de busca do X
Unif Cookbooks team
Unif Cookbooks team

Atualizado

Pesquise posts públicos recentes do X em JSON a partir de um script ou agent de AI sem API key: o endpoint, operadores que funcionam, paginação e limites.

Em resumo: GET https://unifapi.com/tools/x/search?q=<query> devolve em JSON os posts públicos do X que batem com uma consulta. É grátis, sem fazer login, sem precisar de conta e sem chave de API, com limite por visitante. Os operadores de busca do X funcionam em q: from:, to:, since:, until:, min_faves:, min_retweets:, filter:media, filter:links, -filter:replies, lang: e frases entre aspas. Os resultados vêm 20 por página, os mais recentes primeiro, com um nextCursor para paginar. O limite gratuito é de 20 unidades a cada 10 minutos por visitante, impresso nos headers X-RateLimit-*, e uma busca custa 2 unidades porque é a chamada mais cara no upstream, o que dá 10 buscas. Sem datas, você recebe os posts mais recentes; adicione since: e until: e a mesma busca volta até 2006.

De tudo o que as pessoas querem do X sem conta, busca é o item que não tem uma boa resposta gratuita. As APIs de prévia de link (FxTwitter, vxTwitter) leem posts individuais. O endpoint de syndication lê posts individuais. O Nitter tinha busca, e a maioria das instâncias públicas do Nitter sumiu ou está bloqueada por motivos legais. Sobrava ou uma conta de desenvolvedor com nível pago ou um navegador headless controlando x.com/search, o que é lento, frágil e contra os termos.

Isto é o que o endpoint de busca gratuito faz, como consultá-lo e onde ele para.

A requisição

curl -s "https://unifapi.com/tools/x/search?q=from%3Anasa%20filter%3Amedia"
{
  "query": "from:nasa filter:media",
  "posts": {
    "items": [
      {
        "id": "2107566197579341846",
        "text": "After delivering science and supplies to the @Space_Station earlier this year, Northrop Grumman's Cygnus XL cargo spacecraft is scheduled to depart on Friday…",
        "createdAt": "2026-10-06T20:18:32.000Z",
        "url": "https://x.com/NASA/status/2107566197579341846",
        "author": { "handle": "NASA", "name": "NASA", "verified": true, "followers": 92373839 },
        "metrics": {
          "likes": 2195,
          "reposts": 302,
          "replies": 114,
          "quotes": 20,
          "bookmarks": 104,
          "views": 1520159
        },
        "media": [
          {
            "kind": "photo",
            "url": "https://pbs.twimg.com/media/…jpg",
            "width": 1920,
            "height": 1280
          }
        ]
      }
    ],
    "hasMore": true,
    "nextCursor": "DAACCgACHUAq4qFAJxAKAAMd…"
  }
}

A mesma requisição na página para humanos é https://unifapi.com/tools/x-search?q=from:nasa filter:media, e adicionar &format=json à URL dessa página devolve o JSON acima. Adicione format=md em vez disso, ou envie Accept: text/markdown, para receber os posts em Markdown, que cabe melhor na janela de contexto de um modelo do que JSON.

Operadores que funcionam

A consulta vai para a busca do X como foi escrita, então os operadores que o X documenta para a própria caixa de busca funcionam aqui. Estes são os que mais usamos:

OperadorExemploO que faz
from:from:nasaPosts de uma conta
to:to:nasaRespostas endereçadas a uma conta
@handle@nasaPosts que mencionam uma conta
#tag#Formula1Posts com uma hashtag
"phrase""crew-12"Frase exata
since: / until:since:2026-10-01Limites de data (dias inteiros)
min_faves:min_faves:100Pelo menos N curtidas
min_retweets:min_retweets:50Pelo menos N reposts
filter:mediafrom:nasa filter:mediaSó posts com foto ou vídeo
filter:linksfilter:linksSó posts com link
-filter:replies#Formula1 -filter:repliesExclui respostas
-filter:retweetsfrom:nasa -filter:retweetsExclui reposts
lang:lang:jaCódigo de idioma
ORnasa OR esaQualquer um dos termos

Eles se combinam. "Posts da NASA na última semana com pelo menos 100 curtidas e uma foto, sem respostas" é:

from:nasa since:2026-09-30 min_faves:100 filter:media -filter:replies

A página de busca tem um filtro para cada um dos cinco mais comuns (conta, data, curtidas, mídia, respostas) e mostra a consulta que eles montam, que é a mesma string que a API recebe.

Mais recentes, não Principais

A busca do X tem duas ordenações: "Principais" (Top), que mistura relevância e idade e não hesita em abrir com um post de 2009, e "Mais recentes" (Latest), estritamente do mais novo para o mais antigo. O endpoint gratuito pede Mais recentes. Para monitoramento, reações a um evento e qualquer coisa com limite since:, é essa que você quer. Se quiser "os posts mais curtidos sobre X nesta semana", ordene você mesmo os resultados de Mais recentes por metrics.likes ou adicione min_faves: para cortar a cauda.

Paginação

Toda lista na API gratuita é { items, hasMore, nextCursor }. Para continuar, devolva o cursor:

curl -s "https://unifapi.com/tools/x/search?q=%23Formula1&cursor=DAACCgACHUAq4qFAJxAKAAMd…"

Cursores são strings opacas; não tente interpretá-los. hasMore é true exatamente quando nextCursor está definido. Uma página de busca tem 20 posts, então três requisições leem cerca de 60 posts por 6 das suas 20 unidades.

Limites, na resposta

HTTP/2 200
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 16
X-RateLimit-Reset: 1791357984

O nível gratuito é de 20 unidades a cada 10 minutos por visitante, somando todos os endpoints /tools/x/*, e uma busca custa 2. Quando acaba, a resposta é um 429 com Retry-After e um corpo em JSON dizendo onde levantar o teto:

{
  "error": {
    "type": "rate_limited",
    "message": "Free limit of 20 requests per 10 minutes reached. Retry after 412s, or use a UnifAPI workspace key (pay as you go) for uncapped access.",
    "retryAfterSeconds": 412,
    "upgrade": "https://unifapi.com/apis/twitter"
  }
}

Um agente bem-comportado lê X-RateLimit-Remaining antes de decidir paginar e dorme pelo tempo de Retry-After em vez de tentar de novo em loop.

O que ele não faz

  • Relevância. Os resultados vêm só do mais novo para o mais antigo. Posts antigos podem ser alcançados com datas (from:jack until:2006-04-01 devolve posts de março de 2006), mas nada coloca os melhores de um período em primeiro lugar, e o X traça os limites de dia de since:/until: no fuso horário dele, então um intervalo pode transbordar algumas horas para um lado ou para o outro.
  • Contas protegidas. Só posts públicos são devolvidos.
  • Contagens. Não existe um número de "quantos posts bateram"; o X não expõe isso para busca.
  • Garantias. O nível gratuito é infraestrutura compartilhada com teto por visitante. Um fluxo de trabalho que precisa de volume ou de SLA migra para a API medida, onde os nomes de campo são os mesmos.

Um loop de monitoramento em vinte linhas

import requests, time

BASE = "https://unifapi.com/tools/x/search"
seen = set()

def poll(query):
    r = requests.get(BASE, params={"q": query}, headers={"Accept": "application/json"})
    if r.status_code == 429:
        time.sleep(int(r.headers.get("Retry-After", "60")))
        return []
    r.raise_for_status()
    fresh = [p for p in r.json()["posts"]["items"] if p["id"] not in seen]
    seen.update(p["id"] for p in fresh)
    return fresh

while True:
    for post in poll('"unifapi" -filter:replies'):
        print(post["createdAt"], post["author"]["handle"], post["metrics"]["likes"], post["url"])
    time.sleep(600)

Uma busca a cada 10 minutos são 2 das 20 unidades gratuitas; o loop nunca estoura o limite e, mesmo assim, trata o caso do 429.

FAQ

Existe uma API de busca do Twitter gratuita em 2026?

Sim, esta: é grátis, sem fazer login e sem chave de API, com limite por visitante de 10 buscas a cada 10 minutos. A API oficial do X não tem nível gratuito de busca; o plano gratuito dela só permite publicar.

Os operadores da busca avançada do Twitter funcionam?

Sim. A consulta é repassada à busca do X sem alteração, então from:, since:, until:, min_faves:, filter:media, -filter:replies, lang: e frases entre aspas funcionam.

Até onde a busca vai no tempo?

Até 2006. Sem datas, você recebe primeiro os posts mais recentes; adicione since: e until: para pular para um período, por exemplo from:jack until:2006-04-01.

Dá para receber os resultados em Markdown em vez de JSON?

Sim. Adicione format=md ou envie Accept: text/markdown. A renderização em Markdown lista cada post com autor, texto, métricas e URL.