Como migrar da API do Twitter/X
Migrar da API oficial do X exige cinco mudanças no código: mapear cada endpoint da v2 para o novo caminho, trocar o OAuth por uma chave de API, abandonar fields e expansions, reescrever o parsing do JSON e trocar o token de paginação.
Resposta rápida: O que se deve migrar são as leituras: a API oficial do X cobra US$ 0,005 por post e US$ 0,010 por usuário, e, a partir de 22 de novembro de 2026, cada autor devolvido com um post soma US$ 0,010. Para migrá-las, use a Sorsa API: um cabeçalho ApiKey, 20 tweets por requisição de busca a partir de US$ 0,07 por 1.000 e 100 requisições grátis para testar o mapa.
- Endpoint
POST /search-tweets- Tamanho da página
- 20 tweets por requisição
- Preço
- a partir de US$ 0,07 por 1.000
#O que mudou na API oficial do X desde 2023
O código escrito para a API oficial do X ainda funciona na maior parte; o que mudou desde 2023 foi o que ele pode chamar, o que recebe de volta e quanto cada resposta custa. A lista datada abaixo vem do changelog (abre em uma nova aba) do X e dos avisos em seu fórum de desenvolvedores, com a parte de uma integração que cada mudança atinge.
| Data | Mudança na API oficial do X | O que isso faz com o seu código |
|---|---|---|
| 30 de mar de 2023 | Planos pagos substituem o acesso gratuito; o Free passa a ser só de escrita | Leituras em um app gratuito devolvem erros |
| 26 de jun de 2023 | Endpoints de follows removidos do Basic e do Pro | As chamadas de seguidores e seguindo param nesses planos |
| 28 de set de 2023 | search/tweets e users/search da v1.1 descontinuados | O código de busca da v1.1 precisa de um novo endpoint |
| 19 de jan de 2026 | min_likes, min_replies, min_reposts removidos da busca | As consultas que os usavam tiveram de abandoná-los até 4 de maio |
| 6 de fev de 2026 | O pagamento por uso vira o modelo; créditos comprados antecipadamente | As chamadas são bloqueadas quando o saldo chega a zero |
| 23 de fev de 2026 | Respostas programáticas só permitidas quando o autor convoca você | Bots de resposta são recusados |
| 20 de abr de 2026 | Seguir, curtir e quote-posts removidos do autoatendimento | Essas chamadas de escrita param de funcionar |
| 4 de maio de 2026 | A busca passa para um novo índice; retweets saem dos resultados por palavra-chave | A mesma consulta devolve menos posts |
| 1º de jun e 1º de set de 2026 | Planos legados Basic e, depois, Pro migrados para o pagamento por uso | Um teto mensal vira uma cobrança por recurso |
| 22 de nov de 2026 | Expansions cobradas: US$ 0,010 por autor, US$ 0,005 por item de mídia | expansions=author_id pode triplicar o custo de um post |
30 de mar de 2023
- Mudança na API oficial do X
- Planos pagos substituem o acesso gratuito; o Free passa a ser só de escrita
- O que isso faz com o seu código
- Leituras em um app gratuito devolvem erros
26 de jun de 2023
- Mudança na API oficial do X
- Endpoints de follows removidos do Basic e do Pro
- O que isso faz com o seu código
- As chamadas de seguidores e seguindo param nesses planos
28 de set de 2023
- Mudança na API oficial do X
search/tweetseusers/searchda v1.1 descontinuados- O que isso faz com o seu código
- O código de busca da v1.1 precisa de um novo endpoint
19 de jan de 2026
- Mudança na API oficial do X
min_likes,min_replies,min_repostsremovidos da busca- O que isso faz com o seu código
- As consultas que os usavam tiveram de abandoná-los até 4 de maio
6 de fev de 2026
- Mudança na API oficial do X
- O pagamento por uso vira o modelo; créditos comprados antecipadamente
- O que isso faz com o seu código
- As chamadas são bloqueadas quando o saldo chega a zero
23 de fev de 2026
- Mudança na API oficial do X
- Respostas programáticas só permitidas quando o autor convoca você
- O que isso faz com o seu código
- Bots de resposta são recusados
20 de abr de 2026
- Mudança na API oficial do X
- Seguir, curtir e quote-posts removidos do autoatendimento
- O que isso faz com o seu código
- Essas chamadas de escrita param de funcionar
4 de maio de 2026
- Mudança na API oficial do X
- A busca passa para um novo índice; retweets saem dos resultados por palavra-chave
- O que isso faz com o seu código
- A mesma consulta devolve menos posts
1º de jun e 1º de set de 2026
- Mudança na API oficial do X
- Planos legados Basic e, depois, Pro migrados para o pagamento por uso
- O que isso faz com o seu código
- Um teto mensal vira uma cobrança por recurso
22 de nov de 2026
- Mudança na API oficial do X
- Expansions cobradas: US$ 0,010 por autor, US$ 0,005 por item de mídia
- O que isso faz com o seu código
expansions=author_idpode triplicar o custo de um post
Duas dessas mudanças alteraram resultados sem mudar uma linha de código. Desde que o novo índice de busca (abre em uma nova aba) entrou no ar em 4 de maio, uma busca por palavra-chave que funcionava bem em abril volta sem os retweets. E, a partir de 22 de novembro, a mesma requisição com expansions=author_id que custava US$ 5,00 por 1.000 posts passa a custar até US$ 15,00, porque o aviso sobre expansions (abre em uma nova aba) do X cobra cada autor devolvido como uma leitura de usuário.
Os planos também mudaram por baixo de código que já estava rodando. O X encerrou as assinaturas do Basic legado (abre em uma nova aba) nas datas de migração depois de 1º de junho de 2026, e as do Pro legado (abre em uma nova aba) depois de 1º de setembro; uma conta Pro mensal recebeu um crédito de US$ 5.000 na migração, com a recarga automática ativada. Hoje toda leitura consome créditos a US$ 0,005 por post e US$ 0,010 por usuário ou seguidor, até 3 milhões de leituras de posts por mês, e a tabela completa de tarifas está em nosso detalhamento dos preços da API do X.
#O que migra para a Sorsa API e o que fica no X
Toda leitura de dados públicos pode migrar: busca, timelines, consultas de posts e usuários, seguidores, listas, quotes, retweeters, respostas, Spaces, comunidades e trends. A Sorsa API, uma API e scraper do Twitter (X) em produção desde 2022, com mais de 6 bilhões de requisições atendidas, devolve tudo isso com uma única chave, sem OAuth e, como explica o guia sobre a API do Twitter sem conta de desenvolvedor, sem conta de desenvolvedor do X. Ela é somente leitura por princípio, então as chamadas que escrevem ficam onde estão.
Mantenha estas na API oficial do X:
- Postar, responder, apagar e enviar mídia.
- Mensagens diretas, e curtidas, follows, bookmarks e bloqueios, como ações ou como listas da atividade da sua própria conta.
- Quem curtiu um post e qualquer coisa de contas protegidas.
- Filtered stream, firehose, webhooks e a X Activity API: a Sorsa API é consultada por polling, não recebe dados por push (o padrão de polling está mais abaixo).
- Contagens de posts, Community Notes e a Ads API.
Sua conta do X não participa das leituras, porque a Sorsa API nunca pede seu login nem seus cookies. Depois da divisão, a API oficial do X cobra apenas as escritas, por requisição: US$ 0,015 por post criado e US$ 0,20 por um post com link.
É nas leituras que o dinheiro vai. Em leituras de busca e de timeline, 1 milhão de tweets custa US$ 5.000 na API oficial do X antes de qualquer cobrança de autores, e a partir de US$ 70 na Sorsa API, que devolve o autor de cada tweet dentro dele sem custo extra. As consultas por ID rendem mais: o POST /tweet-info-bulk devolve 100 tweets por requisição, a partir de US$ 0,014 por 1.000.
API oficial do X
US$ 5.000
para 1 milhão tweets
US$ 0,005 por post, antes dos autores
Sorsa API
a partir deUS$ 70
para 1 milhão tweets
a partir de US$ 0,07 por 1.000, autor incluído
#Migre para a Sorsa API em seis passos
Seis passos levam uma integração da v2 do inventário até a troca definitiva. Os cinco primeiros são edições no seu código; o último dura alguns dias, enquanto as duas APIs respondem às mesmas leituras.
-
Liste todas as chamadas que o seu código faz. Procure no código por
api.x.com/2,api.twitter.com/2e pelos nomes dos métodos do seu cliente, comosearch_recent_tweetsdo Tweepy ouposts.search_recentdo xdk. Exporte o uso do mês passado por recurso no Developer Console do X e marque cada chamada como leitura ou escrita. -
Obtenha uma chave e envie uma requisição. Cadastre-se, copie a chave do painel e chame o endpoint que substitui a sua leitura mais frequente.
Terminal curl -X POST "https://api.sorsa.io/v3/search-tweets" \ -H "ApiKey: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"query": "from:mira_moves_reads", "order": "latest"}'Resposta200 OK { "tweets": [ { "id": "1852331946812457001", "full_text": "Read path moved. Writes stay where they were.", "created_at": "2026-10-30T14:05:12Z", "lang": "en", "likes_count": 41, "retweet_count": 6, "reply_count": 3, "quote_count": 1, "view_count": 2380, "conversation_id_str": "1852331946812457001", "is_reply": false, "user": { "id": "1592041833471827968", "username": "mira_moves_reads", "display_name": "Mira Moves Reads", "followers_count": 912, "verified": false } } ], "next_cursor": "DAADDAABCgABGbHk7m4WYAEKAAIZsd" } -
Mapeie cada leitura para o seu endpoint. A tabela e o conversor da próxima seção associam cada leitura da v2 ao caminho e aos parâmetros correspondentes da Sorsa API.
-
Troque OAuth, fields e expansions por um único cabeçalho. Nas chamadas de leitura, apague o bearer token ou a assinatura OAuth 1.0a e envie
ApiKey: YOUR_API_KEYno lugar. Abandonetweet.fields,user.fieldseexpansions: todos os campos e o autor já vêm por padrão. -
Reescreva o parsing e a paginação. Leia
tweetsouusersonde você liadataeincludes, renomeie os campos que diferem e envienext_cursorde volta até que ele venha vazio. -
Faça um shadow run e depois a troca. Envie uma cópia das suas leituras à Sorsa API por alguns dias, compare os resultados, mova o tráfego em etapas e mantenha a chave do X para as escritas.
#Mapeie cada endpoint da API v2 do X para a Sorsa API
Toda leitura pública que uma integração provavelmente chama tem um endpoint na Sorsa API. A tabela associa cada caminho da v2, como escrito na especificação OpenAPI (abre em uma nova aba) do X, ao seu substituto e à quantidade que uma requisição devolve; a Sorsa API cobra por requisição, não por item, então a última coluna define o preço.
| Chamada da API v2 do X | Endpoint da Sorsa API | Uma requisição devolve |
|---|---|---|
GET /2/tweets/search/recent | POST /search-tweets (abre em uma nova aba) | cerca de 20 tweets |
GET /2/tweets/search/all | POST /search-tweets com since: e until: | cerca de 20 tweets |
GET /2/tweets/:id | POST /tweet-info (abre em uma nova aba) | 1 tweet |
GET /2/tweets (por IDs) | POST /tweet-info-bulk (abre em uma nova aba) | até 100 tweets |
GET /2/users/:id/tweets | POST /user-tweets (abre em uma nova aba) | cerca de 20 tweets |
GET /2/users/:id/mentions | POST /mentions (abre em uma nova aba) | cerca de 20 tweets |
GET /2/tweets/:id/quote_tweets | POST /quotes (abre em uma nova aba) | cerca de 20 tweets |
GET /2/tweets/:id/retweeted_by | POST /retweeters (abre em uma nova aba) | uma página de perfis |
Busca com conversation_id: | POST /comments (abre em uma nova aba) | cerca de 20 respostas |
GET /2/users/by/username/:username | GET /info (abre em uma nova aba) | 1 perfil |
GET /2/users e GET /2/users/by | GET /info-batch (abre em uma nova aba) | até 100 perfis |
GET /2/users/:id/followers | GET /followers (abre em uma nova aba) | até 200 perfis |
GET /2/users/:id/following | GET /follows (abre em uma nova aba) | até 200 perfis |
GET /2/users/search | POST /search-users (abre em uma nova aba) | uma página de perfis |
GET /2/lists/:id/members | GET /list-members (abre em uma nova aba) | uma página de perfis |
GET /2/lists/:id/followers | GET /list-followers (abre em uma nova aba) | uma página de perfis |
GET /2/lists/:id/tweets | GET /list-tweets (abre em uma nova aba) | cerca de 20 tweets |
GET /2/spaces/:id | GET /spaces (abre em uma nova aba) | 1 Space |
GET /2/communities/:id | POST /community-info (abre em uma nova aba) | 1 comunidade |
GET /2/communities/search | POST /search-communities (abre em uma nova aba) | uma página de comunidades |
GET /2/trends/by/woeid/:woeid | GET /trends (abre em uma nova aba) | os trends de 1 localidade |
GET /2/usage/tweets | GET /key-usage-info (abre em uma nova aba) | seu saldo, sem custo |
GET /2/tweets/search/recent- Endpoint da Sorsa API
POST /search-tweets(abre em uma nova aba)- Uma requisição devolve
- cerca de 20 tweets
GET /2/tweets/search/all- Endpoint da Sorsa API
POST /search-tweetscomsince:euntil:- Uma requisição devolve
- cerca de 20 tweets
GET /2/tweets/:id- Endpoint da Sorsa API
POST /tweet-info(abre em uma nova aba)- Uma requisição devolve
- 1 tweet
GET /2/tweets(por IDs)- Endpoint da Sorsa API
POST /tweet-info-bulk(abre em uma nova aba)- Uma requisição devolve
- até 100 tweets
GET /2/users/:id/tweets- Endpoint da Sorsa API
POST /user-tweets(abre em uma nova aba)- Uma requisição devolve
- cerca de 20 tweets
GET /2/users/:id/mentions- Endpoint da Sorsa API
POST /mentions(abre em uma nova aba)- Uma requisição devolve
- cerca de 20 tweets
GET /2/tweets/:id/quote_tweets- Endpoint da Sorsa API
POST /quotes(abre em uma nova aba)- Uma requisição devolve
- cerca de 20 tweets
GET /2/tweets/:id/retweeted_by- Endpoint da Sorsa API
POST /retweeters(abre em uma nova aba)- Uma requisição devolve
- uma página de perfis
Busca com
conversation_id:- Endpoint da Sorsa API
POST /comments(abre em uma nova aba)- Uma requisição devolve
- cerca de 20 respostas
GET /2/users/by/username/:username- Endpoint da Sorsa API
GET /info(abre em uma nova aba)- Uma requisição devolve
- 1 perfil
GET /2/userseGET /2/users/by- Endpoint da Sorsa API
GET /info-batch(abre em uma nova aba)- Uma requisição devolve
- até 100 perfis
GET /2/users/:id/followers- Endpoint da Sorsa API
GET /followers(abre em uma nova aba)- Uma requisição devolve
- até 200 perfis
GET /2/users/:id/following- Endpoint da Sorsa API
GET /follows(abre em uma nova aba)- Uma requisição devolve
- até 200 perfis
GET /2/users/search- Endpoint da Sorsa API
POST /search-users(abre em uma nova aba)- Uma requisição devolve
- uma página de perfis
GET /2/lists/:id/members- Endpoint da Sorsa API
GET /list-members(abre em uma nova aba)- Uma requisição devolve
- uma página de perfis
GET /2/lists/:id/followers- Endpoint da Sorsa API
GET /list-followers(abre em uma nova aba)- Uma requisição devolve
- uma página de perfis
GET /2/lists/:id/tweets- Endpoint da Sorsa API
GET /list-tweets(abre em uma nova aba)- Uma requisição devolve
- cerca de 20 tweets
GET /2/spaces/:id- Endpoint da Sorsa API
GET /spaces(abre em uma nova aba)- Uma requisição devolve
- 1 Space
GET /2/communities/:id- Endpoint da Sorsa API
POST /community-info(abre em uma nova aba)- Uma requisição devolve
- 1 comunidade
GET /2/communities/search- Endpoint da Sorsa API
POST /search-communities(abre em uma nova aba)- Uma requisição devolve
- uma página de comunidades
GET /2/trends/by/woeid/:woeid- Endpoint da Sorsa API
GET /trends(abre em uma nova aba)- Uma requisição devolve
- os trends de 1 localidade
GET /2/usage/tweets- Endpoint da Sorsa API
GET /key-usage-info(abre em uma nova aba)- Uma requisição devolve
- seu saldo, sem custo
Quatro hábitos mudam com os caminhos. Os endpoints de tweets usam POST com um corpo JSON, enquanto as consultas de usuários, listas e utilidades continuam em GET. Um username funciona onde a v2 pedia um ID numérico, então a consulta extra antes de cada chamada de timeline desaparece. O tweet_link aceita a URL completa de um post ou só o ID. E o POST /user-tweets continua paginando além dos 3.200 posts mais recentes, onde a timeline de usuário do X trava.
Algumas leituras da v2 não têm equivalente, porque a Sorsa API devolve apenas o que qualquer pessoa vê em um perfil público: usuários que curtiram, curtidas e bookmarks de um usuário, contagens de posts, a timeline inicial e todos os streams. A Sorsa API também responde a perguntas que a v2 não responde: o POST /check-follow (abre em uma nova aba) diz em uma requisição se uma conta segue outra, e o GET /about (abre em uma nova aba) devolve o país de uma conta e o histórico de usernames.
O conversor abaixo transforma uma chamada da v2 por vez na requisição equivalente da Sorsa API, com os campos que mudam e o preço de 1.000 resultados em cada lado.
curl -G "https://api.x.com/2/tweets/search/recent" \
-H "Authorization: Bearer $X_BEARER_TOKEN" \
--data-urlencode "query=from:mira_moves_reads" \
-d "max_results=100" \
-d "expansions=author_id" \
-d "tweet.fields=created_at,public_metrics"
curl -X POST "https://api.sorsa.io/v3/search-tweets" \
-H "ApiKey: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "from:mira_moves_reads", "order": "latest"}'
- Endpoint da Sorsa API
POST /search-tweets- Uma requisição retorna
- cerca de 20 tweets
- API oficial do X, 1,000 resultados
- US$ 5,00, mais até US$ 10,00 pelos autores
- Sorsa API, 1,000 resultados
- a partir de US$ 0,07
Paginação: next_token vira next_cursor no corpo JSON. A mesma consulta busca desde 2006, e não só nos últimos 7 dias, e cada tweet traz o seu autor.
Escolha a chamada da v2 que o seu código faz para ver a mesma requisição na Sorsa API e quanto custam 1,000 resultados em cada uma.
Se o seu código usa filtered stream ou webhooks
A Sorsa API não tem stream nem webhook, então uma regra de filtered stream vira uma consulta de busca que você consulta por polling. Envie a regra como consulta do POST /search-tweets com "order": "latest", acrescente since_id: com o ID mais novo que você guardou e siga o next_cursor, para que um minuto movimentado com mais de 20 posts novos não perca nenhum deles.
import os
import time
import requests
URL = "https://api.sorsa.io/v3/search-tweets"
HEADERS = {"ApiKey": os.environ.get("SORSA_API_KEY", "YOUR_API_KEY")}
RULE = '"open data" lang:en'
def new_tweets(since_id):
body = {"query": f"{RULE} since_id:{since_id}", "order": "latest"}
found = []
while True:
r = requests.post(URL, headers=HEADERS, json=body, timeout=30)
if r.status_code == 429:
time.sleep(1)
continue
r.raise_for_status()
page = r.json()
found += page.get("tweets", [])
if not page.get("next_cursor"):
return found
body["next_cursor"] = page["next_cursor"]
newest = "1852331946812457001"
while True:
tweets = new_tweets(newest)
for t in sorted(tweets, key=lambda t: int(t["id"])):
print(t["id"], t["user"]["username"], t["full_text"][:60])
if tweets:
newest = max((t["id"] for t in tweets), key=int)
time.sleep(15)
Uma chave roda 20 requisições por segundo em todos os planos, o que dá 1.200 consultas de uma página por minuto, compartilhadas entre as suas regras. Agendamento, alertas e deduplicação para tarefas de monitoramento são tratados no guia de monitoramento do Twitter em tempo real.
#Reescreva o parsing da resposta
A Sorsa API envia cada tweet como um único objeto com o autor dentro, então o join entre data e includes desaparece e o trabalho que sobra é renomear campos.
Os nomes de campos abaixo vêm do dicionário de dados do X e da referência em produção da Sorsa API, lidos em 2 de novembro de 2026. A maioria das mudanças é um achatamento, em que uma métrica sai de public_metrics e mantém o nome, e algumas são renomeações.
| Campo da API v2 do X | Campo da Sorsa API |
|---|---|
data[] | tweets[], ou users[] para listas de contas |
text e note_tweet.text | full_text |
author_id com includes.users[] | user, o perfil completo |
public_metrics.like_count | likes_count |
public_metrics.impression_count | view_count |
public_metrics.retweet_count, reply_count, quote_count, bookmark_count | os mesmos nomes, um nível acima |
conversation_id | conversation_id_str |
referenced_tweets com includes.tweets[] | quoted_status, retweeted_status, in_reply_to_tweet_id |
attachments.media_keys com includes.media[] | entities[] com type, link, preview |
name em um usuário | display_name |
public_metrics.following_count, tweet_count em um usuário | followings_count, tweets_count |
meta.next_token e pagination_token | next_cursor, nos dois sentidos |
errors[] com title e detail | {"message": "..."} |
data[]- Campo da Sorsa API
tweets[], ouusers[]para listas de contas
textenote_tweet.text- Campo da Sorsa API
full_text
author_idcomincludes.users[]- Campo da Sorsa API
user, o perfil completo
public_metrics.like_count- Campo da Sorsa API
likes_count
public_metrics.impression_count- Campo da Sorsa API
view_count
public_metrics.retweet_count,reply_count,quote_count,bookmark_count- Campo da Sorsa API
- os mesmos nomes, um nível acima
conversation_id- Campo da Sorsa API
conversation_id_str
referenced_tweetscomincludes.tweets[]- Campo da Sorsa API
quoted_status,retweeted_status,in_reply_to_tweet_id
attachments.media_keyscomincludes.media[]- Campo da Sorsa API
entities[]comtype,link,preview
nameem um usuário- Campo da Sorsa API
display_name
public_metrics.following_count,tweet_countem um usuário- Campo da Sorsa API
followings_count,tweets_count
meta.next_tokenepagination_token- Campo da Sorsa API
next_cursor, nos dois sentidos
errors[]comtitleedetail- Campo da Sorsa API
{"message": "..."}
Os IDs continuam strings e as datas continuam em ISO 8601, então os dados guardados mantêm o formato. A paginação se reduz a um único nome: envie next_cursor como parâmetro de query nos endpoints GET ou no corpo JSON nos endpoints POST, e pare quando ele vier vazio. O rate limiting também fica mais simples. As janelas de 15 minutos e os cabeçalhos x-rate-limit-* descritos em nosso guia sobre os rate limits da API do X dão lugar a um único limite de 20 requisições por segundo por chave: um 429 significa esperar um segundo e tentar de novo, e um 403 significa que a chave está ausente ou que as requisições do mês acabaram.
Bom saber
O tamanho das páginas não é fixo. Uma página de busca tem até 20 tweets e pode ter menos enquanto ainda restam páginas, então faça o loop com base no
next_cursor, nunca no número de itens, ou uma página curta encerra o trabalho antes da hora.
#Código Tweepy e xdk, antes e depois
Tweepy e xdk são bibliotecas gratuitas; a conta vem da API oficial do X por trás delas, então a migração troca o cliente, não a linguagem. Aqui está a mesma busca com autores, paginada até o fim, primeiro em Tweepy e depois em Python puro na Sorsa API:
import tweepy
client = tweepy.Client(bearer_token="X_BEARER_TOKEN")
for page in tweepy.Paginator(
client.search_recent_tweets,
query="from:mira_moves_reads",
tweet_fields=["created_at", "public_metrics"],
expansions=["author_id"],
user_fields=["username", "name"],
max_results=100):
users = {u.id: u for u in page.includes.get("users", [])}
for t in page.data or []:
author = users[t.author_id]
print(t.id, author.username, t.public_metrics["like_count"])
As listas de campos, o join de includes e o paginador saem do código; entra um cabeçalho. O código com xdk muda do mesmo modo: Client(bearer_token=...) e client.posts.search_recent(...) paginam os mesmos data e includes, por isso dão lugar ao loop acima. A consulta também alcança mais longe depois da migração, porque o POST /search-tweets busca desde 2006 em todos os planos, enquanto a busca recente da v2 cobre os últimos 7 dias.
O código construído sobre o pacote twitter-api-v2 para Node.js migra do mesmo modo, para fetch e um cabeçalho:
const URL = "https://api.sorsa.io/v3/search-tweets";
const headers = {
ApiKey: process.env.SORSA_API_KEY ?? "YOUR_API_KEY",
"Content-Type": "application/json",
};
const body = { query: "from:mira_moves_reads", order: "latest" };
do {
const res = await fetch(URL, {
method: "POST",
headers,
body: JSON.stringify(body),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const page = await res.json();
for (const t of page.tweets ?? []) {
console.log(t.id, t.user.username, t.likes_count);
}
body.next_cursor = page.next_cursor;
} while (body.next_cursor);
Para código Tweepy que só lê, mova as leituras para a Sorsa API: a busca devolve 20 tweets por requisição a partir de US$ 0,07 por 1.000, os perfis vêm 100 por requisição a partir de US$ 0,014 por 1.000, e não é preciso OAuth. Novas tentativas, lotes e um controlador de ritmo para 20 requisições por segundo estão no guia da API do Twitter com Python.
#Traduza suas consultas de busca
O POST /search-tweets aceita a sintaxe da Busca Avançada do X, a linguagem da caixa de busca do x.com, então palavras-chave, frases entre aspas, from:, to:, lang:, conversation_id: e hashtags passam sem alteração. O que muda são os operadores is: e has: da v2 e seus parâmetros de tempo, que passam para dentro da consulta:
| API v2 do X | Consulta na Sorsa API |
|---|---|
parâmetros start_time e end_time | since:2026-10-01 e until:2026-11-01 |
parâmetros since_id e until_id | since_id:ID e max_id:ID (inclusivo) |
sort_order=recency ou relevancy | "order": "latest" ou "popular" no corpo |
-is:retweet | nada: os retweets ficam de fora por padrão |
is:reply e -is:reply | filter:replies e -filter:replies |
is:quote | filter:quote |
has:media, has:images, has:links | filter:media, filter:images, filter:links |
has:video_link | filter:native_video |
min_likes:, min_reposts:, min_replies: | min_faves:, min_retweets:, min_replies: |
point_radius: | geocode: |
parâmetros
start_timeeend_time- Consulta na Sorsa API
since:2026-10-01euntil:2026-11-01
parâmetros
since_ideuntil_id- Consulta na Sorsa API
since_id:IDemax_id:ID(inclusivo)
sort_order=recencyourelevancy- Consulta na Sorsa API
"order": "latest"ou"popular"no corpo
-is:retweet- Consulta na Sorsa API
- nada: os retweets ficam de fora por padrão
is:replye-is:reply- Consulta na Sorsa API
filter:repliese-filter:replies
is:quote- Consulta na Sorsa API
filter:quote
has:media,has:images,has:links- Consulta na Sorsa API
filter:media,filter:images,filter:links
has:video_link- Consulta na Sorsa API
filter:native_video
min_likes:,min_reposts:,min_replies:- Consulta na Sorsa API
min_faves:,min_retweets:,min_replies:
point_radius:- Consulta na Sorsa API
geocode:
Três detalhes atrapalham as consultas traduzidas. Os retweets nativos ficam de fora, a menos que você acrescente include:nativeretweets. O geocode: recebe a latitude primeiro, como em geocode:37.77,-122.41,5km, enquanto o point_radius: da v2 recebia a longitude primeiro. E o max_id: inclui o próprio ID, enquanto o until_id da v2 o exclui. A lista completa de operadores, com receitas, está em nosso guia de operadores de busca do Twitter.
#Teste com um shadow run e depois faça a troca
Um shadow run envia uma cópia de cada leitura à Sorsa API enquanto a API oficial do X continua atendendo o seu app, de modo que os resultados são comparados antes de qualquer coisa depender deles.
O script executa uma consulta sobre o mesmo dia encerrado nas duas APIs e compara os IDs dos posts. Execute-o para cada consulta e timeline de que você depende; uma janela fechada impede que posts novos distorçam a contagem.
import os
import requests
X_URL = "https://api.x.com/2/tweets/search/recent"
X_HEADERS = {"Authorization": "Bearer " + os.environ["X_BEARER_TOKEN"]}
S_URL = "https://api.sorsa.io/v3/search-tweets"
S_HEADERS = {"ApiKey": os.environ.get("SORSA_API_KEY", "YOUR_API_KEY")}
def x_ids(query, start, end):
params = {"query": query, "start_time": start,
"end_time": end, "max_results": 100}
ids = set()
while True:
r = requests.get(X_URL, headers=X_HEADERS, params=params, timeout=30)
r.raise_for_status()
page = r.json()
ids |= {t["id"] for t in page.get("data", [])}
token = page.get("meta", {}).get("next_token")
if not token:
return ids
params["next_token"] = token
def sorsa_ids(query, since, until):
body = {"query": f"{query} since:{since} until:{until}",
"order": "latest"}
ids = set()
while True:
r = requests.post(S_URL, headers=S_HEADERS, json=body, timeout=30)
r.raise_for_status()
page = r.json()
ids |= {t["id"] for t in page.get("tweets", [])}
if not page.get("next_cursor"):
return ids
body["next_cursor"] = page["next_cursor"]
query = "from:mira_moves_reads"
a = x_ids(query, "2026-10-30T00:00:00Z", "2026-10-31T00:00:00Z")
b = sorsa_ids(query, "2026-10-30_00:00:00_UTC", "2026-10-31_00:00:00_UTC")
print(f"official X API {len(a)}, Sorsa API {len(b)}, shared {len(a & b)}")
print("only on X:", sorted(a - b)[:10])
print("only on Sorsa API:", sorted(b - a)[:10])
Espere pequenas diferenças em vez de zero: posts apagados entre as duas chamadas somem, e a busca por palavra-chave do X deixa os retweets de fora desde 4 de maio de 2026. A busca recente do X alcança 7 dias para trás, então mantenha a janela dentro da última semana. Quando os IDs baterem nas leituras que você mais executa, faça a troca em etapas:
- Coloque os dois clientes atrás de uma mesma interface e de uma única flag de configuração, para que qualquer tipo de leitura possa voltar com um só valor.
- Mova 10% das leituras, acompanhe os erros e o
GET /key-usage-info, que é grátis e nunca desconta das suas requisições, e depois mova o restante. - Mantenha a chave da API oficial do X só para as escritas, e reduza o limite de gastos e o valor da recarga automática no Developer Console.
- Apague os caminhos de código de leitura, as listas de campos e a paginação antiga depois que um ciclo de cobrança completo passar.
#Tire suas leituras da API oficial do X
Uma integração da v2 só de leitura migra para a Sorsa API, a API do Twitter feita para ler dados públicos do X, com um cabeçalho, um endpoint por chamada e um parser que perde o join. A busca sai a partir de US$ 0,07 por 1.000 tweets em vez de US$ 5,00, os seguidores a partir de US$ 0,007 por 1.000 em vez de US$ 10,00, e todos os planos respondem a 20 requisições por segundo. Comece pela leitura mais cara, faça um shadow run dela por alguns dias e mantenha a API oficial do X só para o que escreve.
#Perguntas frequentes
Para qual API do Twitter devo migrar a partir da API oficial do X?
Para ler dados públicos do X, migre para a Sorsa API: cada leitura da v2 corresponde a um endpoint, os tweets custam a partir de US$ 0,014 por 1.000 por ID e a partir de US$ 0,07 por busca, contra US$ 5,00 na API oficial do X, todos os planos rodam a 20 requisições por segundo e a busca chega até 2006. Uma chave de API substitui o OAuth. A Sorsa API é somente leitura, então mantenha a API oficial do X para postar.
Quanto tempo leva uma migração da API oficial do X?
A mudança de código cresce com o número de chamadas distintas da v2, não com o volume de dados: cada chamada vira um endpoint, um cabeçalho e alguns campos renomeados. Some um shadow run de alguns dias, em que as duas APIs respondem às mesmas leituras e você compara os IDs. Postagens, DMs e outras escritas ficam na API oficial do X, então só o caminho de leitura migra.
Posso continuar postando no X depois de migrar as leituras para a Sorsa API?
Pode. Mantenha a API oficial do X para postar, responder e enviar DMs, e mande as leituras para a Sorsa API. A Sorsa API é somente leitura por princípio: a chave dela não consegue agir em nenhuma conta do X e nunca precisa do seu login do X, então as duas convivem sem conflito. Se o seu caminho de escrita ainda assina com tokens de usuário OAuth 1.0a, o X permite que os apps os troquem por tokens OAuth 2.0 desde 21 de setembro de 2026.
Preciso migrar da v1.1 para a v2 primeiro?
Não. O código que ainda chama leituras da v1.1 pode ser mapeado direto para a Sorsa API: statuses/user_timeline vira POST /user-tweets, statuses/show vira POST /tweet-info e users/show vira GET /info. O X classifica a v1.1 como legada, com suporte limitado, e descontinuou a busca da v1.1 em 2023, então parar na v2 significa reescrever para OAuth 2.0 e para a cobrança por uso antes de migrar de novo.
O que aconteceu com os planos legados Basic e Pro da API do X?
O X os migrou para o pagamento por uso: as assinaturas do Basic legado terminaram nas datas de migração depois de 1º de junho de 2026, e as do Pro, depois de 1º de setembro de 2026. Uma conta Pro mensal recebeu um crédito de US$ 5.000 na migração, com a recarga automática ativada. Agora as leituras são cobradas por recurso, US$ 0,005 por post e US$ 0,010 por usuário, enquanto os mesmos tweets custam a partir de US$ 0,07 por 1.000 por busca na Sorsa API.
#Como verificamos
Em 2 de novembro de 2026, montamos o mapa de endpoints comparando a especificação OpenAPI do próprio X (versão 2.173, 200 caminhos) com a referência em produção da Sorsa API (45 endpoints), e conferimos cada operador da v2 na lista de operadores do X e cada substituto nos operadores de busca da Sorsa API. No mesmo dia, lemos o changelog do X, a página de preços, a documentação de paginação e de rate limits, a referência do XDK para Python e o cliente do Tweepy 4.17.0, além dos avisos do fórum do X sobre o índice de busca, os planos legados e a cobrança de expansions. Não tínhamos uma chave da Sorsa API para esta rodada, então a resposta exibida usa valores de demonstração; executamos os blocos em Python e Node.js contra um mock local que responde nos formatos documentados das duas APIs.
Fontes
- X API changelog (docs.x.com) (abre em uma nova aba)
- X API pay-per-usage pricing (docs.x.com) (abre em uma nova aba)
- X API OpenAPI specification (abre em uma nova aba)
- Search operators, X API v2 (docs.x.com) (abre em uma nova aba)
- Search endpoints migrating to a new index (X Developers, May 2026) (abre em uma nova aba)
- Legacy Basic plans moving to pay-per-use (X Developers, May 21, 2026) (abre em uma nova aba)
- Legacy Pro plans moving to pay-per-use (X Developers, August 14, 2026) (abre em uma nova aba)
- X API PPU: expansions update (X Developers, October 23, 2026) (abre em uma nova aba)
- Python XDK (docs.x.com) (abre em uma nova aba)
- Sorsa API reference, OpenAPI
- Migration from the official X API (Sorsa API docs) (abre em uma nova aba)
- Search operators (Sorsa API docs) (abre em uma nova aba)