Por Sorsa Editorial
Atualizado: julho de 2026. Adicionamos a oferta inicial de 100 requisições grátis à orientação de primeiros passos e de preço, e atualizamos a comparação de custo com a API oficial do X para o preço atual de pagamento por uso dela.
Em resumo: O Twitter (X) permite verificar cinco ações de usuário por uma API: follows, retweets, quote tweets, comentários e participação em Comunidade. Cada checagem retorna um único resultado true/false. As curtidas se tornaram privadas em junho de 2024 e não podem mais ser verificadas por nenhuma ferramenta. A posse de uma conta é comprovada fazendo o usuário postar um código único.
Rodar um sorteio, programa de embaixadores ou campanha de quests que recompensa ações no X quebra no momento em que @s falsos, tarefas pela metade e bots começam a encher o seu formulário. Lá pelo participante trezentos, a revisão manual é sem esperança e checkboxes de sistema de honra não valem nada. O que você de fato precisa é de uma API que responda, para cada participante, "essa pessoa realmente fez o que alegou?" A Sorsa API, um provedor alternativo de API do Twitter (X), expõe cada verificação como um endpoint de sim/não: passe um @ e uma ação, receba um booleano de volta. Não há handshake OAuth e nem aprovação de conta de desenvolvedor, só um único cabeçalho ApiKey; o rate limit é um fixo de 20 requisições por segundo em todos os planos; toda conta começa com 100 requisições grátis (única vez, sem cartão, válidas em todos os 40 endpoints e que nunca expiram), o bastante para verificar uma campanha de teste completa antes de se comprometer; e, no preço fixo por requisição (a partir de US$ 0,0049 no plano de entrada, caindo para cerca de US$ 0,002 no Pro), custa uma fração de reconstruir as mesmas checagens na API oficial do X, que cobra por recurso em listas completas. A Sorsa é somente leitura, então ela verifica e lê dados públicos mas não posta, não segue e não envia DM; para ações de escrita você ainda usaria a API oficial.
Nós construímos e operamos esses endpoints, e ao longo de dezenas de campanhas rodamos e auditamos esse padrão, na maior parte para agências de marketing de criadores e ferramentas de sorteio. Os endpoints são simples. As armadilhas (contas privadas, @s falsificados, fazendas de bot, a capacidade perdida de checar curtidas) não são. Este guia percorre cada checagem com Python funcional, e depois as costura em um pipeline completo de campanha: um participante primeiro, depois verificação em massa para dezenas de milhares. Se você prefere rodar o fluxo inteiro sem escrever código, nossa solução de verificação de sorteio embrulha essas mesmas checagens atrás de uma interface.
Índice
- O que você pode e não pode verificar no X
- Como a verificação funciona na API oficial do X contra a Sorsa
- Checagem 1: o usuário seguiu uma conta?
- Checagem 2: o usuário deu retweet em um tweet?
- Checagem 3: o usuário citou um tweet?
- Checagem 4: o usuário comentou em um tweet?
- Checagem 5: o usuário é membro de uma Comunidade?
- Montando um pipeline completo de verificação de campanha
- Verificando participantes em massa
- Verificando a posse de uma conta
- Antifraude: checagens de qualidade de conta
- Pontuação de recompensa ponderada por influência
- Na prática: 47.000 participantes em 14 dias
- Custo por participante
- Primeiros passos
- Perguntas frequentes
O que você pode e não pode verificar no X {#what-you-can-and-cannot-verify-on-x}
Cinco ações de usuário no X são verificáveis por uma API hoje: um follow, um retweet, um quote tweet, um comentário e entrar em uma Comunidade. Cada uma mapeia para um endpoint e retorna um booleano. As curtidas não são mais verificáveis por nenhuma ferramenta, pública ou de terceiros, porque o X as tornou privadas em junho de 2024. As visualizações também não são verificáveis.
| Ação | Endpoint | Método | Retorna | Verificável? |
|---|---|---|---|---|
| Usuário segue uma conta | /check-follow | POST | {follow: true/false} | Sim |
| Usuário deu retweet em um tweet | /check-retweet | POST | {retweet: true/false} | Sim |
| Usuário citou um tweet | /check-quoted | POST | {status: "quoted" / "retweet" / "not_found"} | Sim |
| Usuário comentou em um tweet | /check-comment | GET | {commented: true/false, tweet: {...}} | Sim |
| Usuário entrou em uma Comunidade do X | /check-community-member | POST | {is_member: true/false} | Sim |
| Usuário curtiu um tweet | (nenhum) | (nenhum) | (nenhum) | Não, privado desde junho de 2024 |
| Usuário viu/teve impressão de um tweet | (nenhum) | (nenhum) | (nenhum) | Não |
A restrição das curtidas é a surpresa mais comum. Em junho de 2024, o X tornou as curtidas privadas para todos: só o autor de um post pode ver quem o curtiu, e nenhuma API (incluindo a API oficial do X) consegue mais responder "o usuário A curtiu o tweet B". Se você tem templates de campanha antigos que incluem "Curta este post", substitua essa tarefa por um retweet ou comentário. Ambos continuam totalmente verificáveis e produzem sinais de engajamento mais fortes, de qualquer forma.
Todo o resto na tabela acima é uma única chamada de API. A autenticação é um único cabeçalho ApiKey (sem fluxo OAuth, sem aprovação de app), e a resposta é JSON puro. O resto deste guia é o como-fazer prático.
Como a verificação funciona na API oficial do X contra a Sorsa {#how-verification-works-on-the-official-x-api-vs-sorsa}
A API oficial do X não tem endpoint que responda diretamente se um usuário específico seguiu, deu retweet, citou ou comentou. Você reconstrói cada resposta buscando listas completas de seguidores, de quem deu retweet ou de quem respondeu, e as vasculhando, cobrado por recurso buscado. Uma API de verificação feita para o propósito, em vez disso, retorna um booleano por checagem em uma única requisição.
Esta é a maior razão isolada pela qual as equipes recorrem a uma camada de verificação dedicada, e vale ver lado a lado. Os números abaixo são as tarifas atuais de pagamento por uso da API oficial do X e o preço fixo por requisição da Sorsa.
| Tarefa | API oficial do X (pagamento por uso) | Sorsa API |
|---|---|---|
| Um usuário seguiu uma conta | Sem endpoint direto. Pagine a lista completa de seguidores ou de seguindo da conta e a vasculhe; cada perfil retornado é cobrado como uma leitura de usuário (US$ 0,010 cada). | Uma requisição /check-follow retorna follow: true/false. |
| Um usuário deu retweet em um tweet | Sem endpoint direto. Busque a lista completa de quem deu retweet e a vasculhe pelo @. | Uma requisição /check-retweet retorna retweet: true/false, com paginação para listas muito grandes. |
| Um usuário citou um tweet | Sem endpoint direto. Busque os quote tweets e case o autor. | Uma requisição /check-quoted retorna quoted, retweet ou not_found. |
| Um usuário comentou | Sem endpoint direto. Busque a lista de respostas e vasculhe pelo @. | Uma requisição /check-comment retorna commented: true/false mais a resposta. |
| Um usuário é membro de comunidade | Sem endpoint público equivalente. | Uma requisição /check-community-member retorna is_member: true/false. |
| Autenticação | OAuth 2.0 com um Bearer token e um app de desenvolvedor aprovado. | Um único cabeçalho ApiKey. Sem fila de aprovação. |
| Cobrança | Por recurso buscado: US$ 0,005 por post, US$ 0,010 por perfil de usuário, com um teto mensal de 2.000.000 de leituras de post. | Fixo por requisição: 1 chamada = 1 requisição, de US$ 0,0049 (Starter) até cerca de US$ 0,002 (Pro), todo endpoint incluído. |
| Rate limit | Varia por endpoint, em janelas fixas. | Fixo de 20 requisições por segundo em todos os planos. |
Há uma segunda vantagem, mais silenciosa, de checar contra a audiência completa em vez de uma amostra. A interface pública do X e a maioria dos sorteadores gratuitos de sorteio só mostram a fatia mais recente de uma audiência, muitas vezes os últimos 100 ou mais que deram retweet ou responderam, então um vencedor sorteado deles silenciosamente exclui todos que entraram mais cedo. A verificação contra a lista completa evita isso: o /check-retweet da Sorsa pagina 100 entradas por vez pela lista inteira, e as checagens diretas por usuário respondem por um participante específico não importa onde ele esteja na audiência.
Se o seu objetivo é o dado de engajamento subjacente em vez de uma resposta de sim/não (a lista completa de quem respondeu, citou ou deu retweet e as métricas deles), esse é um trabalho diferente, coberto no nosso guia da API de engajamento do Twitter.
Checagem 1: o usuário seguiu uma conta? {#check-1-did-the-user-follow-an-account}
A tarefa de campanha mais comum ("Siga @SuaMarca para participar"). O endpoint /check-follow responde isso diretamente. A lógica do endpoint é "user_2 segue user_1?", então user_1 é a marca e user_2 é o participante.
Endpoint: POST https://api.sorsa.io/v3/check-follow
Parâmetros
Forneça um identificador para a marca (a conta seguida) e um para o participante.
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
username_1 | string | Um destes | O @ da marca. |
user_link_1 | string | destes | Ou a URL do perfil da marca. |
user_id_1 | string | Ou o ID numérico de usuário da marca. | |
username_2 | string | Um destes | @ do participante. |
user_link_2 | string | destes | Ou a URL do perfil do participante. |
user_id_2 | string | Ou o ID numérico de usuário do participante. |
Python
import requests
API_KEY = "YOUR_API_KEY"
BASE = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": API_KEY, "Content-Type": "application/json"}
def check_follow(brand_handle: str, participant_handle: str) -> dict:
resp = requests.post(
f"{BASE}/check-follow",
headers=HEADERS,
json={"username_1": brand_handle, "username_2": participant_handle},
timeout=15,
)
resp.raise_for_status()
return resp.json()
result = check_follow("YourBrand", "participant123")
if result["follow"]:
print("Follow verified.")
elif result.get("user_protected"):
print("Account is private; follow cannot be confirmed.")
else:
print("Not following.")
Resposta
{
"follow": true,
"user_protected": false
}
Casos de borda a conhecer
Se user_protected for true, a conta do participante é privada e o grafo de follow dela não é visível a nenhum terceiro. Você tem três opções: rejeitar a entrada, pedir ao participante que torne a conta pública para verificação, ou usar a verificação de posse de conta (coberta abaixo) para confirmar que ele é dono do @ e então aceitar a entrada com uma exceção manual. Na nossa experiência, menos de 1% dos participantes de sorteio têm contas privadas, então uma rejeição firme com uma mensagem clara costuma ser suficiente.
Esta checagem responde uma direção de uma relação de follow para uma campanha. Para checar um único follow ou follows mútuos fora do contexto de campanha, veja nosso guia sobre como checar se uma conta segue outra, ou rode uma checagem avulsa no navegador com a ferramenta de checagem de follow no-code.
Checagem 2: o usuário deu retweet em um tweet? {#check-2-did-the-user-retweet-a-tweet}
"Dê retweet neste post para participar." Mecânica padrão para impulsionar o alcance. O endpoint /check-retweet retorna um booleano e pagina para listas grandes.
Endpoint: POST https://api.sorsa.io/v3/check-retweet
Parâmetros
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tweet_link | string | Sim | URL do tweet a verificar. |
username | string | Um destes | @ do participante. |
user_link | string | destes | Ou a URL do perfil. |
user_id | string | Ou o ID numérico de usuário. | |
next_cursor | string | Não | Paginação para tweets com > 100 retweets. |
Python
def check_retweet(tweet_link: str, participant_handle: str) -> bool:
cursor = None
for _ in range(5): # check up to 500 retweets total
body = {"tweet_link": tweet_link, "username": participant_handle}
if cursor:
body["next_cursor"] = cursor
resp = requests.post(f"{BASE}/check-retweet", headers=HEADERS, json=body, timeout=15)
resp.raise_for_status()
data = resp.json()
if data["retweet"]:
return True
cursor = data.get("next_cursor")
if not cursor:
return False
return False
Como a paginação funciona
Cada chamada vasculha os 100 retweets mais recentes. Se o seu tweet tem milhares de retweets e o usuário deu retweet cedo, a ação dele pode estar mais fundo na lista e exigir paginação. O exemplo acima limita em 5 páginas (os 500 retweets mais recentes) para manter a verificação rápida. Para a maioria das campanhas isso é mais do que suficiente, porque os participantes tendem a dar retweet em horas após ver a instrução, então a ação deles fica no topo da lista.
Esta é a diferença prática de sortear um vencedor pela interface nativa do X ou por um sorteador gratuito, que normalmente só veem o lote mais recente. Como o /check-retweet percorre a lista completa 100 por vez, quem deu retweet cedo é encontrado com a mesma confiabilidade de quem deu tarde. A API oficial do X não oferece checagem direta equivalente: você buscaria a lista inteira de quem deu retweet e a vasculharia você mesmo, com configuração de OAuth, contabilidade de rate limit por janela e a sua própria lógica de paginação por cima.
Checagem 3: o usuário citou um tweet? {#check-3-did-the-user-quote-a-tweet}
"Cite isto com o que você achou." Isto é mais valioso do que um retweet simples porque o quote tweet adiciona o comentário do próprio participante e amplifica a campanha com texto personalizado.
Endpoint: POST https://api.sorsa.io/v3/check-quoted
O endpoint /check-quoted é esperto em distinguir um quote de um retweet simples, retornando um de três status.
Python
def check_quoted(tweet_link: str, participant_handle: str) -> dict:
resp = requests.post(
f"{BASE}/check-quoted",
headers=HEADERS,
json={"tweet_link": tweet_link, "username": participant_handle},
timeout=15,
)
resp.raise_for_status()
return resp.json()
data = check_quoted("https://x.com/YourBrand/status/1234567890", "participant123")
if data["status"] == "quoted":
print(f"Quote verified on {data['date']}: {data['text']}")
elif data["status"] == "retweet":
print("Retweeted without commentary; does not satisfy quote requirement.")
else:
print("No quote or retweet found.")
Por que o texto do quote importa
A resposta inclui o texto completo do quote e a data, que você pode canalizar para uma checagem de qualidade antes de aprovar a entrada. Uma campanha que exige "cite com o que você achou do novo produto" merece mais do que um quote de uma palavra tipo "legal". A maioria das equipes que rodam essas campanhas aplica uma regra de mínimo de caracteres (tipicamente 30 a 50 caracteres), uma checagem de palavrão e uma hashtag obrigatória se a campanha usar uma.
def quote_is_acceptable(quote_text: str, min_length: int = 30, required_hashtag: str = None) -> bool:
if len(quote_text.strip()) < min_length:
return False
if required_hashtag and required_hashtag.lower() not in quote_text.lower():
return False
return True
Checagem 4: o usuário comentou em um tweet? {#check-4-did-the-user-comment-on-a-tweet}
"Deixe um comentário sob este post." O único endpoint de verificação que usa GET em vez de POST.
Endpoint: GET https://api.sorsa.io/v3/check-comment
Parâmetros (query string)
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
tweet_link | string | Sim | URL do tweet. |
username | string | Um destes | @ do participante. |
user_link | string | destes | Ou a URL do perfil. |
user_id | string | Ou o ID numérico de usuário. |
Python
def check_comment(tweet_link: str, participant_handle: str) -> dict:
resp = requests.get(
f"{BASE}/check-comment",
headers={"ApiKey": API_KEY},
params={"tweet_link": tweet_link, "username": participant_handle},
timeout=15,
)
resp.raise_for_status()
return resp.json()
data = check_comment("https://x.com/YourBrand/status/1234567890", "participant123")
if data["commented"]:
text = data["tweet"]["full_text"]
print(f"Comment verified: {text[:120]}")
else:
print("No comment found.")
Resposta e qualidade do comentário
Quando commented é true, a resposta de /check-comment inclui o objeto de tweet completo do próprio comentário: texto, métricas de engajamento, detecção de idioma, timestamp. Use isto para impor mínimo de comprimento, palavras-chave obrigatórias ou rejeitar respostas de spam só com emoji. Em uma campanha onde o comentário é a tarefa de engajamento inteira, a régua de qualidade deveria ser mais alta do que um único emoji.
def comment_is_acceptable(comment: dict, min_length: int = 20, required_keyword: str = None) -> bool:
text = comment.get("full_text", "").strip()
if len(text) < min_length:
return False
if required_keyword and required_keyword.lower() not in text.lower():
return False
# Reject emoji-only or single-word comments
if len(text.split()) < 3:
return False
return True
Checagem 5: o usuário é membro de uma Comunidade? {#check-5-is-the-user-a-community-member}
"Entre na nossa Comunidade do X para participar." Útil quando você quer que o participante seja uma parte sustentada da comunidade em vez de quem dá retweet uma única vez.
Endpoint: POST https://api.sorsa.io/v3/check-community-member
def check_community_member(community_id: str, participant_handle: str) -> bool:
resp = requests.post(
f"{BASE}/check-community-member",
headers=HEADERS,
json={"community_id": community_id, "username": participant_handle},
timeout=15,
)
resp.raise_for_status()
return resp.json().get("is_member", False)
is_member = check_community_member("1966045657589813686", "participant123")
print("Member" if is_member else "Not a member")
O ID da comunidade é a string numérica longa na URL da comunidade (x.com/i/communities/<id>). O endpoint /check-community-member retorna um booleano limpo. Comunidades muitas vezes são um sinal mais durável do que um retweet único, porque entrar em uma comunidade sinaliza intenção de continuar engajado.
Montando um pipeline completo de verificação de campanha {#building-a-full-campaign-verification-pipeline}
Em uma campanha real, os participantes completam várias tarefas. Aqui vai um padrão que roda as cinco checagens para um participante, retorna um resultado estruturado e aplica regras de qualidade ao comentário e ao quote.
from dataclasses import dataclass, field
@dataclass
class CampaignConfig:
brand_handle: str
tweet_to_retweet: str
tweet_to_quote: str
tweet_to_comment: str
community_id: str
required_hashtag: str = ""
min_quote_length: int = 30
min_comment_length: int = 20
@dataclass
class ParticipantResult:
username: str
follow: bool = False
retweet: bool = False
quote: bool = False
quote_text: str = ""
comment: bool = False
comment_text: str = ""
community: bool = False
completed: int = field(init=False, default=0)
def total(self) -> int:
return sum([self.follow, self.retweet, self.quote, self.comment, self.community])
def verify_participant(username: str, cfg: CampaignConfig) -> ParticipantResult:
r = ParticipantResult(username=username)
# Follow
r.follow = check_follow(cfg.brand_handle, username)["follow"]
# Retweet
r.retweet = bool(check_retweet(cfg.tweet_to_retweet, username))
# Quote tweet (with quality check)
quote_data = check_quoted(cfg.tweet_to_quote, username)
if quote_data["status"] == "quoted":
r.quote_text = quote_data.get("text", "")
r.quote = quote_is_acceptable(r.quote_text, cfg.min_quote_length, cfg.required_hashtag)
# Comment (with quality check)
comment_data = check_comment(cfg.tweet_to_comment, username)
if comment_data.get("commented"):
r.comment_text = comment_data["tweet"].get("full_text", "")
r.comment = comment_is_acceptable(comment_data["tweet"], cfg.min_comment_length)
# Community
r.community = check_community_member(cfg.community_id, username)
r.completed = r.total()
return r
cfg = CampaignConfig(
brand_handle="YourBrand",
tweet_to_retweet="https://x.com/YourBrand/status/111111111",
tweet_to_quote="https://x.com/YourBrand/status/222222222",
tweet_to_comment="https://x.com/YourBrand/status/333333333",
community_id="1966045657589813686",
required_hashtag="#YourLaunch",
)
result = verify_participant("participant123", cfg)
print(f"@{result.username}: {result.completed}/5 tasks done")
Um único participante custa 5 requisições de API (uma por tarefa). No rate limit universal da Sorsa de 20 requisições por segundo, uma thread de worker pode verificar cerca de 4 participantes por segundo sequencialmente. Para a maioria das campanhas que rodam verificação uma vez por submissão, isso é folga mais do que suficiente.
Verificando participantes em massa {#verifying-participants-in-bulk}
Quando uma campanha tem milhares de participantes e você quer verificá-los em lote (por exemplo, antes de anunciar vencedores), o padrão fica assim. Note o tratamento de rate limit, a saída em CSV e o design retomável (escreve uma linha imediatamente após cada participante, para que uma queda não perca o progresso).
import csv
import time
from pathlib import Path
def verify_campaign_batch(usernames: list[str], cfg: CampaignConfig, output_file: str) -> None:
fields = ["username", "follow", "retweet", "quote", "comment", "community",
"completed", "quote_text", "comment_text"]
already_done = set()
out_path = Path(output_file)
if out_path.exists():
with out_path.open() as f:
already_done = {row["username"] for row in csv.DictReader(f)}
mode = "a" if out_path.exists() else "w"
with out_path.open(mode, newline="") as f:
writer = csv.DictWriter(f, fieldnames=fields)
if mode == "w":
writer.writeheader()
for i, username in enumerate(usernames):
if username in already_done:
continue
try:
r = verify_participant(username, cfg)
writer.writerow({
"username": r.username,
"follow": r.follow,
"retweet": r.retweet,
"quote": r.quote,
"comment": r.comment,
"community": r.community,
"completed": r.completed,
"quote_text": r.quote_text,
"comment_text": r.comment_text,
})
f.flush()
print(f"[{i+1}/{len(usernames)}] @{username}: {r.completed}/5")
except requests.HTTPError as e:
if e.response.status_code == 429:
print("Rate limit hit, sleeping 5s and retrying...")
time.sleep(5)
continue
print(f"[{i+1}] @{username}: ERROR {e}")
time.sleep(0.25) # stay safely under 20 req/s with 5 reqs per participant
participants = open("entries.txt").read().splitlines()
verify_campaign_batch(participants, cfg, "campaign_results.csv")
Este padrão verifica cerca de 14.000 participantes por hora com uma única thread. Se você paralelizar em dois ou três workers (ainda respeitando o teto global de 20 req/s), você pode chegar a 30.000 por hora. Para a maioria das campanhas abaixo de 100.000 entradas, a verificação sequencial de uma única thread termina de um dia para o outro.
Verificando a posse de uma conta {#verifying-account-ownership}
Antes que um participante possa ganhar qualquer coisa, você pode querer provar que ele de fato é dono do @ do X que submeteu. Sem esse passo, qualquer um pode colar um @ famoso no seu formulário e reivindicar a recompensa. O padrão padrão: gerar um código único, pedir ao participante que poste um tweet contendo ele, e depois checar a linha do tempo recente dele pelo código.
import secrets
def generate_verification_code(prefix: str = "VERIFY") -> str:
return f"{prefix}-{secrets.token_hex(4)}"
def verify_account_ownership(username: str, expected_code: str) -> bool:
"""Check if the user posted a tweet containing the verification code."""
resp = requests.post(
f"{BASE}/user-tweets",
headers=HEADERS,
json={"username": username},
timeout=15,
)
resp.raise_for_status()
tweets = resp.json().get("tweets", [])
for tweet in tweets:
if expected_code in tweet.get("full_text", ""):
return True
return False
# Workflow
code = generate_verification_code()
print(f"Ask the user to post a tweet containing: {code}")
# ... user posts the tweet ...
if verify_account_ownership("participant123", code):
print("Account ownership confirmed.")
else:
print("Code not found in recent tweets.")
Este é o mesmo mecanismo que a maioria das plataformas sérias de sorteio e de embaixadores usa. O participante pode apagar o tweet após a verificação se quiser, já que você só precisa confirmar o post uma vez.
Antifraude: checagens de qualidade de conta {#anti-fraud-account-quality-checks}
Campanhas automatizadas atraem bots, e plataformas que rodam mecânicas de quest em larga escala investem muito em prevenção de sybil como resultado. Algumas checagens no nível da API descartam os infratores óbvios sem precisar de um sistema completo de detecção de sybil. Cada uma é uma chamada adicional a /info.
from datetime import datetime, timezone
def is_legitimate_account(
username: str,
min_age_days: int = 30,
min_tweets: int = 10,
min_followers: int = 5,
) -> tuple[bool, dict]:
resp = requests.get(
f"{BASE}/info",
headers={"ApiKey": API_KEY},
params={"username": username},
timeout=15,
)
resp.raise_for_status()
profile = resp.json()
created = datetime.fromisoformat(profile["created_at"].replace("Z", "+00:00"))
age_days = (datetime.now(timezone.utc) - created).days
checks = {
"account_age_ok": age_days >= min_age_days,
"has_tweets": profile.get("tweets_count", 0) >= min_tweets,
"has_followers": profile.get("followers_count", 0) >= min_followers,
"not_protected": not profile.get("protected", False),
}
return all(checks.values()), checks
Três observações de rodar isto em produção:
- Idade mínima de 30 dias pega a maioria das contas de bot recém-criadas. Fazendas de bot tipicamente registram contas em lotes e as usam em dias. Um piso de 30 dias derruba a maioria. Suba para 90 dias se a sua campanha é de alto valor.
- Contas com zero tweets são quase sempre falsas. Um mínimo de 5 a 10 tweets existentes é um sinal forte de uso humano real.
- A razão de seguidores para seguindo importa menos do que você pensa. Pessoas reais com 50 seguidores e 800 seguindo são comuns (consumidores passivos). Não use a razão como filtro primário.
Esses limiares removem os bots óbvios de forma barata. Para campanhas de alto valor onde você quer ir além e pontuar quanto da própria base de seguidores de um participante parece falsa ou inativa, nosso guia sobre auditar seguidores falsos percorre essa passada mais profunda.
Aplique esta checagem antes de rodar qualquer uma das cinco verificações. Se is_legitimate_account retornar False, você economiza 5 requisições de verificação em um participante que teria rejeitado de qualquer forma.
Pontuação de recompensa ponderada por influência {#influence-weighted-reward-scoring}
Nem todos os participantes têm o mesmo alcance. Um retweet de um criador com 50.000 seguidores vale mais para uma campanha de marca do que um de uma conta com 50. A correção direta é ponderar o valor em pontos de cada tarefa por uma função logarítmica do contador de seguidores do participante.
import math
BASE_POINTS = {"follow": 10, "retweet": 15, "quote": 25, "comment": 20, "community": 10}
def get_follower_count(username: str) -> int:
resp = requests.get(
f"{BASE}/info",
headers={"ApiKey": API_KEY},
params={"username": username},
timeout=15,
)
resp.raise_for_status()
return resp.json().get("followers_count", 0)
def calculate_weighted_points(result: ParticipantResult) -> dict:
followers = get_follower_count(result.username)
# log scaling: 100 followers -> 2x, 10K -> 4x, 1M -> 6x
multiplier = max(1.0, math.log10(followers + 1))
total = 0
breakdown = {}
for task, base in BASE_POINTS.items():
if getattr(result, task):
points = round(base * multiplier)
breakdown[task] = points
total += points
return {"followers": followers, "multiplier": round(multiplier, 2),
"breakdown": breakdown, "total": total}
O resultado: uma conta com 50 seguidores completando as cinco tarefas ganha cerca de 80 pontos. Uma conta com 50.000 seguidores completando as mesmas tarefas ganha cerca de 380 pontos. A campanha recompensa o alcance proporcionalmente sem pagar a micro-celebridades o mesmo que a contas de alcance zero.
Para campanhas com tempero de cripto, você pode substituir o multiplicador de contador de seguidores pelo Sorsa Score, que mede o reconhecimento de uma conta entre KOLs, projetos e VCs de cripto. Duas contas podem ter contadores de seguidores parecidos mas Sorsa Scores muito diferentes se uma é uma voz cripto-nativa e a outra é uma conta de interesse geral.
Na prática: 47.000 participantes em 14 dias {#in-practice-47000-participants-in-14-days}
Uma agência de marketing de criadores com quem trabalhamos lançou um sorteio de 14 dias para uma marca de artigos para casa de venda direta ao consumidor. A mecânica da campanha era padrão: seguir a marca, dar retweet no tweet de lançamento, citá-lo com uma hashtag da marca, comentar em um segundo tweet e entrar na Comunidade do X deles. Três vencedores receberiam cada um uma reforma de cômodo mobiliada avaliada em cerca de US$ 4.500.
As submissões chegavam por uma landing page de campanha. No dia 14, eles tinham 47.000 entradas.
As campanhas anteriores da agência, rodadas em checkboxes de sistema de honra, tipicamente viam 50 a 60 por cento de conclusões falsas ou parciais, exigindo dias de revisão manual antes de anunciar vencedores. Desta vez eles usaram o pipeline de verificação por API acima. Números da execução:
- 47.000 submissões no total
- 235.000 requisições de verificação (5 por participante)
- 47.000 chamadas
/infoadicionais para os passos de antifraude e de peso por influência - Uso total de API: ~282.000 requisições ao longo da janela da campanha
- Plano usado: Enterprise (500 mil requisições/mês a US$ 899)
- 31.200 participantes passaram nas 5 tarefas
- 8.400 participantes passaram em 3 a 4 tarefas (elegíveis para o nível de prêmio parcial)
- 7.400 participantes rejeitados de saída (falharam na checagem de qualidade de conta ou completaram 0 a 2 tarefas)
- Tempo de moderação manual economizado: ~120 horas (a estimativa deles, com base em campanhas passadas em escala parecida)
O custo de rodar a verificação nesta escala (um mês do plano Enterprise) foi menor do que um único dia de tempo de moderador. A agência agora usa o mesmo pipeline como template para cada campanha de marca que roda.
Divulgação: A Sorsa API é o nosso produto, e os números acima descrevem uma implantação de cliente anonimizada e composta, em vez de um único engajamento nomeado. As alegações técnicas são precisas e a vantagem de custo é uma propriedade real do preço fixo por requisição; para a sua própria campanha, rode um pequeno piloto antes de se comprometer com um fluxo.
Custo por participante {#cost-per-participant}
Uma verificação completa de cinco tarefas, com antifraude e pontuação por influência sobrepostas, leva 7 requisições de API por participante:
- 1 requisição para
/info(antifraude mais contador de seguidores para a pontuação) - 5 requisições para as cinco verificações
- 1 requisição opcionalmente para a verificação de posse de conta (se implementada)
A Sorsa usa preço de tarifa fixa: 1 chamada de API = 1 requisição da cota mensal, independentemente do endpoint. No plano Pro (US$ 199/mês, 100.000 requisições), isso é cerca de 14.000 participantes totalmente verificados por mês. No Enterprise (US$ 899/mês, 500.000 requisições), cerca de 71.000. Planos customizados estão disponíveis acima desse teto.
| Tamanho da campanha | Requisições necessárias | Plano recomendado | Preço do plano |
|---|---|---|---|
| Até 1.400 participantes | ~10.000 | Starter | US$ 49/mês |
| Até 14.000 participantes | ~100.000 | Pro | US$ 199/mês |
| Até 71.000 participantes | ~500.000 | Enterprise | US$ 899/mês |
| 71.000+ participantes | Customizado | Contate vendas | Customizado |
Nas tarifas do plano Pro, uma verificação completa de 7 requisições custa cerca de US$ 0,014 por participante. Para uma campanha de 10.000 participantes, isso é aproximadamente US$ 140 em requisições de API.
O contraste com a API oficial do X vem do modelo de cobrança, não de um único preço de manchete. O X cobra por recurso buscado, US$ 0,005 por post e US$ 0,010 por perfil de usuário, e não tem endpoint de checagem direta, então verificar ações significa puxar listas inteiras de quem deu retweet e de seguidores e pagar por cada item nelas, sob um teto mensal de 2 milhões de leituras de post e OAuth 2.0. A Sorsa cobra uma requisição fixa por chamada /check-* independentemente do tamanho da audiência subjacente. O detalhamento completo por plano e por endpoint para os dois provedores vive no nosso guia de preços da API do Twitter, e se você ainda está pesando opções, nosso apanhado de alternativas à API do Twitter compara o campo mais amplo em custo e capacidades.
Primeiros passos {#getting-started}
Você pode ter uma checagem de verificação funcional rodando em poucos minutos. Não há aprovação de conta de desenvolvedor para esperar e nem fluxo OAuth para conectar: crie uma chave, ponha-a no cabeçalho ApiKey e chame /check-follow. Toda conta começa com 100 requisições grátis, uma franquia única que não precisa de cartão, nunca expira e cobre todos os 40 endpoints, então você pode verificar um pequeno lote de teste antes de pagar qualquer coisa. Depois disso o plano de entrada é US$ 49 para 10.000 requisições, todo endpoint está incluído em todo nível, e o rate limit é um fixo de 20 requisições por segundo.
- Experimente os endpoints sem código no playground da API.
- Leia o quickstart para fazer sua primeira requisição autenticada.
- Siga o passo a passo de verificação de campanha para o pipeline de ponta a ponta na documentação.
- Para campanhas acima de 500.000 requisições por mês ou um rate limit maior, fale com o time de vendas.
Para o menu completo de endpoints de verificação e formatos de resposta, veja a referência de endpoints de verificação.
Perguntas frequentes {#faq}
Dá para verificar curtidas do Twitter via API?
Não. O X tornou as curtidas privadas em junho de 2024, e a partir de 2026 nenhuma API pública ou de terceiros consegue responder se um usuário curtiu o tweet de outro. Esta é uma mudança no nível da plataforma, não uma limitação da Sorsa. Se o seu template de campanha ainda pede curtidas, substitua essa tarefa por um retweet ou comentário, ambos que continuam totalmente verificáveis e carregam sinais de engajamento mais fortes.
Preciso de OAuth ou de aprovação de conta de desenvolvedor para verificar ações do Twitter?
Não com a Sorsa API. A autenticação é um único cabeçalho ApiKey, sem handshake OAuth, sem URLs de callback e sem revisão ou fila de aprovação de app. A API oficial do X exige OAuth 2.0 e um app de desenvolvedor aprovado, e cobra por recurso buscado, o que torna a verificação em escala mais lenta de configurar e mais cara do que um modelo fixo por requisição.
Dá para checar se alguém deu retweet em um tweet que tem milhares de retweets?
Sim. O endpoint /check-retweet vasculha 100 retweets por chamada e retorna um next_cursor para paginar. O código de exemplo neste guia limita em 5 páginas (500 retweets), o que costuma ser suficiente porque os participantes tipicamente dão retweet em horas após serem instruídos. Para tweets onde você precisa vasculhar mais fundo, aumente o limite de páginas e a checagem continua percorrendo a lista completa.
Como verifico que alguém de fato é dono do @ do Twitter que ele inscreveu?
Gere um código curto único, peça ao participante que poste um tweet contendo ele, e depois use o endpoint user-tweets para vasculhar a linha do tempo recente dele por esse código. Um exemplo funcional está na seção de posse de conta deste guia. Este é o padrão que plataformas sérias de sorteio e de embaixadores usam para impedir que as pessoas submetam um @ que não controlam.
O que acontece se um participante tem uma conta privada (protegida)?
As respostas de check-follow e check-quoted incluem uma flag user_protected. Quando ela é true, o grafo de follow da conta não é exposto e você não consegue confirmar programaticamente um follow ou quote. Suas opções são pedir ao participante que torne o perfil público para verificação, rejeitar a entrada com uma mensagem clara, ou rodar a verificação de posse de conta e aceitar com uma exceção manual. Em uma campanha típica, menos de 1% dos participantes têm contas privadas.
Como impedir que bots burlem um sorteio?
Use três camadas de defesa no nível da API: uma checagem de qualidade de conta pelo endpoint /info para idade mínima, contador de tweets e seguidores; checagens de qualidade de comentário e quote para mínimo de comprimento e uma hashtag obrigatória; e verificação de posse de conta antes que qualquer recompensa saia. Nenhuma delas é um sistema completo de detecção de sybil, mas juntas removem os casos de vitória fácil que drenam a maioria das campanhas, e cada conta rejeitada também te economiza as requisições de verificação que você teria gasto com ela.
Verificar engajamento é mais barato do que usar a API oficial do X?
Para verificação especificamente, sim. A API oficial do X não tem endpoint de checagem direta, então você reconstrói cada resposta puxando listas completas de quem deu retweet ou de seguidores e pagando por recurso, US$ 0,005 por post e US$ 0,010 por perfil, sob um teto de 2 milhões de leituras de post. A Sorsa cobra uma requisição fixa por checagem independentemente do tamanho da audiência, de US$ 0,0049 até cerca de US$ 0,002 por requisição, então uma verificação completa de campanha roda por uma pequena fração do custo.
Posso usar essas checagens para casos de uso não de marketing?
Sim. Usos comuns não de marketing incluem restringir o acesso a um canal privado do Discord verificando que um usuário segue a marca antes de conceder um cargo, acompanhar a conformidade de amplificação social de funcionários ou parceiros, e validar alegações de atribuição submetidas por usuários em programas de afiliados. Cada um é a mesma checagem booleana única, apenas aplicada fora do contexto de sorteio.
Revisado por Keksich, fundador da Sorsa, profissional de marketing e pesquisador da API do X.
Como este guia foi montado: ele se apoia no nosso trabalho prático construindo e operando os endpoints de verificação da Sorsa, em chamadas ao vivo contra a própria API e na documentação da Sorsa API para detalhes de endpoint e resposta. A comparação de custo usa o preço atual de pagamento por uso da API oficial do X e suas páginas de política como referência para as tarifas dela, o teto de 2 milhões de leituras de post e a exigência de OAuth. Verificado em junho de 2026.