作者:Sorsa 编辑部

更新:2026 年 7 月。在起步和定价指引里新增了 100 次免费请求的起步优惠,并为官方 X API 当前的按量付费定价刷新了成本对比。

核心要点: Twitter (X) 让你通过 API 核验五种用户动作:关注、转推、引用推文、评论和社区成员资格。每个核查返回单一的 true/false 结果。点赞在 2024 年 6 月变为私密,此后任何工具都无法再核验。账号所有权通过让用户发一个唯一代码来证明。

跑一个奖励 X 上动作的抽奖、大使计划或任务活动,一旦虚假用户名、半完成的任务和机器人开始填你的表单,整个活动就崩溃。到第三百个参与者,手动审查就没戏了,靠自觉的勾选框也一文不值。你实际需要的,是为每个参与者回答“这个人真的做了他声称的事吗?”的 API。Sorsa API 这个替代 Twitter/X API 服务商,把每个核验暴露为是/否接口:传一个用户名和一个动作、拿回布尔值。没有 OAuth 握手、没有开发者账号审批,就一个 ApiKey 请求头;速率限制是每个套餐固定每秒 20 次请求;每个账号注册即送 100 次免费请求(一次性、无需绑卡、对全部 40 个接口有效、永不过期),足够在你投入之前核验一整个测试活动。在按请求计费的定价下(入门套餐从 $0.0049 起、Pro 上降到约 $0.002),其成本只是在官方 X API 上重建同样核查的一个零头,因为官方 API 跨完整列表按资源计费。Sorsa 只读,所以只核验并读取公开数据、但不发帖、不关注、不发私信;写操作你仍会用官方 API。

我们开发并运营这些接口。在我们跑过并审计过这个模式的数十场活动里,大多是给创作者营销机构和抽奖工具。接口很简单。坑(私密账号、伪造的用户名、机器人农场、失去核查点赞的能力)不简单。本指南用可用 Python 走一遍每个核查,再把它们缝进一条完整的活动流程:先一个参与者,再为数万人做批量核验。如果你宁愿不写代码就跑整条流程,我们的抽奖核验方案把这些同样的核查封装在 UI 之后。


目录

  1. 在 X 上你能核验和不能核验什么
  2. 核验在官方 X API 上对比在 Sorsa 上如何运作
  3. 核查 1:用户关注了一个账号吗?
  4. 核查 2:用户转推了一条推文吗?
  5. 核查 3:用户引用了一条推文吗?
  6. 核查 4:用户评论了一条推文吗?
  7. 核查 5:用户是社区成员吗?
  8. 构建一条完整的活动核验流程
  9. 批量核验参与者
  10. 核验账号所有权
  11. 反欺诈:账号质量核查
  12. 按影响力加权的奖励评分
  13. 实战:14 天内 4.7 万名参与者
  14. 每位参与者的成本
  15. 如何开始
  16. 常见问题

在 X 上你能核验和不能核验什么 {#what-you-can-and-cannot-verify-on-x}

今天在 X 上有五种用户动作可通过 API 核验:一次关注、一次转推、一条引用推文、一条评论,以及加入一个社区。每种映射到一个接口、返回布尔值。点赞不再能被任何工具(公开或第三方)核验,因为 X 在 2024 年 6 月把点赞设为私密。浏览也不能核验。

动作接口方法返回可核验?
用户关注一个账号/check-followPOST{follow: true/false}
用户转推了一条推文/check-retweetPOST{retweet: true/false}
用户引用了一条推文/check-quotedPOST{status: "quoted" / "retweet" / "not_found"}
用户评论了一条推文/check-commentGET{commented: true/false, tweet: {...}}
用户加入了一个 X 社区/check-community-memberPOST{is_member: true/false}
用户点赞了一条推文(无)(无)(无)否,自 2024 年 6 月起私密
用户浏览/展示了一条推文(无)(无)(无)

点赞限制是最常见的意外。2024 年 6 月,X 对所有人把点赞设为私密:只有一条帖子的作者能看到谁点赞了帖子,任何 API(包括官方 X API)都无法再回答“用户 A 点赞了推文 B 吗”。如果你有含“点赞这条帖子”的旧活动模板,把那个任务换成转推或评论。两者都仍完全可核验,而且本就产生更强的互动信号。

上表里其他一切都是一次 API 调用。认证是单一的 ApiKey 请求头(没有 OAuth 流程、没有应用审批),响应是朴素 JSON。本指南余下部分是实用操作。


核验在官方 X API 上对比在 Sorsa 上如何运作 {#how-verification-works-on-the-official-x-api-vs-sorsa}

官方 X API 没有直接回答某个特定用户是否关注、转推、引用或评论的接口。你通过取回完整的粉丝、转推者或回复者列表并搜索来重建每个答案,按抓取的资源计费。专门打造的核验 API 则在一次请求里为每个核查返回一个布尔值。

这是团队伸手去拿专用核验层最大的单一原因,值得并排看。下面的数字是官方 X API 当前的按量付费费率和 Sorsa 的按请求计费定价。

任务官方 X API(按量付费)Sorsa API
一个用户是否关注了一个账号无直接接口。分页遍历该账号完整的粉丝或关注列表并搜索它;每份返回的资料都作为一次用户读取(每份 $0.010)计费。一次 /check-follow 请求返回 follow: true/false
一个用户是否转推了一条推文无直接接口。取回完整的转推者列表、在其中搜索该用户名。一次 /check-retweet 请求返回 retweet: true/false,对超大列表带分页。
一个用户是否引用了一条推文无直接接口。取回引用推文、匹配作者。一次 /check-quoted 请求返回 quotedretweetnot_found
一个用户是否评论了无直接接口。取回回复列表、搜索该用户名。一次 /check-comment 请求返回 commented: true/false 加那条回复。
一个用户是否是社区成员无等价的公开接口。一次 /check-community-member 请求返回 is_member: true/false
认证OAuth 2.0 加一个 Bearer 令牌和一个已批准的开发者应用。一个单一的 ApiKey 请求头。无审批队列。
计费按抓取的资源:每条帖子 $0.005、每份用户资料 $0.010,每月上限 200 万次帖子读取。按请求计费:1 次调用 = 1 次请求,从 $0.0049(Starter)降到约 $0.002(Pro),包含每个接口。
速率限制因接口而异,在固定窗口里。每个套餐固定每秒 20 次请求。

对照完整受众、而非样本来核查,还有第二个更安静的优势。公开 X 界面和多数免费抽奖挑选器只浮现受众最近的一片,往往是最后 100 个左右的转推者或回复者。从中抽出的一个赢家,会静默地排除掉所有更早参与的人。对照完整列表核验避开了那个:Sorsa 的 /check-retweet 每次 100 条地翻遍整份列表,直接的按用户核查无论参与者坐在受众的哪里都为其回答。

如果你的目标是底层的互动数据、而非是/否答案(回复者、引用者或转推者的完整列表及其指标),那是另一回事,在我们的 Twitter 互动 API 指南里覆盖。


核查 1:用户关注了一个账号吗? {#check-1-did-the-user-follow-an-account}

最常见的活动任务(“关注 @YourBrand 参与”)。/check-follow 接口直接回答这个。接口的逻辑是“user_2 是否关注 user_1?”,所以 user_1 是品牌、user_2 是参与者。

接口: POST https://api.sorsa.io/v3/check-follow

参数

为品牌(被关注账号)提供一个标识符、为参与者提供一个。

参数类型必填描述
username_1string三选一品牌的用户名。
user_link_1string或品牌的资料 URL。
user_id_1string或品牌的数字用户 ID。
username_2string三选一参与者的用户名。
user_link_2string或参与者的资料 URL。
user_id_2string或参与者的数字用户 ID。

Python

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.")

响应

json
{
  "follow": true,
  "user_protected": false
}

要知道的边缘情况

如果 user_protectedtrue,参与者的账号是私密的、其关注关系图对任何第三方都不可见。你有三个选项:拒绝该参与、请参与者把账号设为公开以便核验,或用账号所有权核验(下面覆盖)。最后一种做法先确认他们拥有这个用户名、再手动放行接受该参与。以我们的经验,不到 1% 的抽奖参与者有私密账号,所以带清晰提示的硬性拒绝通常没问题。

这个核查为一个活动回答关注关系的一个方向。要在活动上下文之外检查单次关注或互相关注,见我们关于如何检查一个账号是否关注另一个的指南,或用无代码的关注检查工具在浏览器里跑一次性检查。


核查 2:用户转推了一条推文吗? {#check-2-did-the-user-retweet-a-tweet}

“转推这条帖子参与。” 提升触达的标准机制。/check-retweet 接口返回布尔值、并为大列表分页。

接口: POST https://api.sorsa.io/v3/check-retweet

参数

参数类型必填描述
tweet_linkstring要核验的推文的 URL。
usernamestring三选一参与者用户名。
user_linkstring或资料 URL。
user_idstring或数字用户 ID。
next_cursorstring对转推 > 100 的推文分页。

Python

python
def check_retweet(tweet_link: str, participant_handle: str) -> bool:
    cursor = None
    for _ in range(5):  # 总共检查最多 500 条转推
        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

分页如何运作

每次调用扫描最近的 100 条转推。如果你的推文有数千转推、而用户很早就转推了,他们的动作可能在列表更深处、需要分页。上面的示例封顶在 5 页(最近 500 条转推)以保持核验快速。对多数活动这绰绰有余,因为参与者往往在看到提示后几小时内转推,所以他们的动作坐在列表顶端。

这是与从原生 X 界面或一个免费挑选器抽赢家的实际差别,后者通常只看到最近一批。因为 /check-retweet 每次 100 条地走遍完整列表,一个早期转推者被找到得和一个晚期的一样可靠。官方 X API 没有等价的直接核查:你会取回整份转推者列表、自己搜索,还要在其上加 OAuth 设置、窗口化的速率限制核算,以及你自己的分页逻辑。


核查 3:用户引用了一条推文吗? {#check-3-did-the-user-quote-a-tweet}

“带上你的想法引用推文。” 这比一次纯转推更有价值,因为引用推文加了参与者自己的评论、用个性化文本放大了活动。

接口: POST https://api.sorsa.io/v3/check-quoted

/check-quoted 接口聪明地区分一次引用和一次纯转推,返回三种状态之一。

Python

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.")

为什么引用文本要紧

响应包含完整的引用文本和日期,你可以在批准该参与之前把引用管进质量核查。一个要求“就新产品带上你的想法引用”的活动,配得上比一个像 "nice" 的单词引用更好的东西。多数跑这些活动的团队应用最低字符规则(通常 30 到 50 字符)、脏话核查,以及如果活动用一个话题标签则要求它。

python
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

核查 4:用户评论了一条推文吗? {#check-4-did-the-user-comment-on-a-tweet}

“在这条帖子下留个评论。” 唯一用 GET 而非 POST 的核验接口。

接口: GET https://api.sorsa.io/v3/check-comment

参数(查询字符串)

参数类型必填描述
tweet_linkstring推文的 URL。
usernamestring三选一参与者用户名。
user_linkstring或资料 URL。
user_idstring或数字用户 ID。

Python

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.")

响应与评论质量

commentedtrue 时,/check-comment 的响应包含评论本身的完整推文对象:文本、互动指标、语言检测、时间戳。用它来强制最低长度、必需关键词,或拒绝纯表情的垃圾回复。在一个评论就是整个互动任务的活动里,质量门槛应该高于一个单表情。

python
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
    # 拒绝纯表情或单词评论
    if len(text.split()) < 3:
        return False
    return True

核查 5:用户是社区成员吗? {#check-5-is-the-user-a-community-member}

“加入我们的 X 社区来参与。” 当你想让参与者成为社区持续的一部分、而非一次性转推者时有用。

接口: POST https://api.sorsa.io/v3/check-community-member

python
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")

社区 ID 是社区 URL 里那串长数字字符串(x.com/i/communities/<id>)。/check-community-member 接口返回干净的布尔值。社区往往比一次性转推是更持久的信号,因为加入一个社区标志着留下来互动的意图。


构建一条完整的活动核验流程 {#building-a-full-campaign-verification-pipeline}

在一场真实活动里,参与者完成好几个任务。这里是为一个参与者跑全部五个核查、返回一个结构化结果、并对评论和引用应用质量规则的模式。

python
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)

    # 关注
    r.follow = check_follow(cfg.brand_handle, username)["follow"]

    # 转推
    r.retweet = bool(check_retweet(cfg.tweet_to_retweet, username))

    # 引用推文(带质量核查)
    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_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)

    # 社区
    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")

单个参与者花 5 次 API 请求(每个任务一次)。在 Sorsa 通用的每秒 20 次请求限制下,一个工作线程顺序地约每秒能核验 4 个参与者。对多数每次提交核验一次的活动,那绰绰有余。


批量核验参与者 {#verifying-participants-in-bulk}

当一场活动有数千参与者、而你想批量核验他们时(例如在宣布赢家之前),模式看起来是这样的。注意速率限制处理、CSV 输出,以及可断点续跑的设计(每个参与者之后立即写一行,好让一次崩溃不丢进度)。

python
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)  # 每位参与者 5 次请求,稳稳待在每秒 20 次以下


participants = open("entries.txt").read().splitlines()
verify_campaign_batch(participants, cfg, "campaign_results.csv")

这个模式单线程约每小时核验 1.4 万名参与者。如果你跨两三个工作线程并行(仍尊重全局每秒 20 次的上限),你能达到每小时 3 万名。对多数不到 10 万参与者的活动,单线程顺序核验一夜完成。


核验账号所有权 {#verifying-account-ownership}

在参与者能赢得任何东西之前,你可能想证明他们真的拥有他们提交的 X 用户名。没有这一步,任何人都能把名人的用户名粘进你的表单、并声称奖励。标准模式:生成一个唯一代码、请参与者发一条含它的推文,再在他们近期时间线里查这个代码。

python
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:
    """检查用户是否发了一条含核验代码的推文。"""
    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


# 工作流
code = generate_verification_code()
print(f"Ask the user to post a tweet containing: {code}")
# ...用户发出那条推文...
if verify_account_ownership("participant123", code):
    print("Account ownership confirmed.")
else:
    print("Code not found in recent tweets.")

这是多数正经的抽奖和大使平台用的同一机制。参与者可以在核验后删掉那条推文(如果他们想),因为你只需确认那次发帖一次。


反欺诈:账号质量核查 {#anti-fraud-account-quality-checks}

自动化活动招来机器人,而跑大规模任务机制的平台因此在女巫防范上投入很大。几个 API 级核查无需完整的女巫检测系统就排除明显的作弊者。每一个都是对 /info 的一次额外调用。

python
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

从生产里跑这个得来的三个观察:

  1. 30 天的最低年龄抓住大多数崭新机器人账号。 机器人农场通常批量注册账号、几天内就用。一个 30 天的下限干掉大多数。若你的活动高价值就推到 90 天。
  2. 零推文账号几乎总是假的。 最少 5 到 10 条现有推文是真人使用的强信号。
  3. 关注对粉丝比没你想的那么要紧。 有 50 个粉丝、800 个关注的真人很常见(被动消费者)。不要把比例用作主要过滤器。

这些阈值便宜地清掉明显的机器人。对你想更进一步、给参与者自己粉丝群有多少看着假或不活跃打分的高价值活动,我们关于审计虚假粉丝的指南走一遍那更深的一遍。

在跑五个核验核查中的任何一个之前应用这个核查。如果 is_legitimate_account 返回 False,你就为一个本会拒绝的参与者省下 5 次核验请求。


按影响力加权的奖励评分 {#influence-weighted-reward-scoring}

并非所有参与者有同样的触达。一个 5 万粉丝创作者的一次转推,对一个品牌活动比一个 50 粉丝账号的更有价值。直接的修法是用参与者粉丝数的对数函数给每个任务的分值加权。

python
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)
    # 对数缩放:100 粉丝 -> 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}

结果:一个 50 粉丝的账号完成全部五个任务约得 80 分。一个 5 万粉丝的账号完成同样任务约得 380 分。活动按比例奖励触达,不给微名人和零触达账号一样的分。

对加密味的活动,你可以把粉丝数乘数换成 Sorsa Score,这个分数衡量账号在加密 KOL、项目和 VC 中的认可度。两个账号可以有相似的粉丝数、但很不同的 Sorsa Score:如果一个是加密原生声音、另一个是通用兴趣账号,就会这样。


实战:14 天内 4.7 万名参与者 {#in-practice-47000-participants-in-14-days}

一家我们合作过的创作者营销机构,为一个直接面向消费者的家居品牌发起了一场 14 天抽奖。活动机制是标准的:关注品牌、转推上线推文、带品牌话题标签引用它、评论第二条推文,并加入他们的 X 社区。三名赢家将各获得一次价值约 $4,500 的房间焕新装修。

参与通过活动落地页进来。到第 14 天他们有 4.7 万个参与。

该机构之前用靠自觉勾选框跑的活动,通常见到 50% 到 60% 的虚假或部分完成,宣布赢家前要好几天手动审查。这次他们用了上面的 API 核验流程。此次运行的数字:

  • 4.7 万个总提交
  • 23.5 万次核验请求(每位参与者 5 次)
  • 另外 4.7 万次 /info 调用,用于反欺诈和影响力加权步骤
  • API 总用量:约 28.2 万次请求,跨整个活动窗口
  • 所用套餐:Enterprise($899 含 50 万次请求/月)
  • 3.12 万名参与者通过全部 5 个任务
  • 8,400 名参与者通过 3 到 4 个任务(符合部分奖励档)
  • 7,400 名参与者被直接拒绝(未通过账号质量核查或完成 0 到 2 个任务)
  • 省下的手动审核时间:约 120 小时(他们的估计,基于过去类似规模的活动)

在这个规模跑核验的成本(一个月的 Enterprise 套餐)不到一天审核员时间的成本。该机构现在把同一条流程用作他们跑的每个品牌活动的模板。

披露: Sorsa API 是我们的产品,上面的数字描述的是一个匿名的、综合的客户部署、而非单一的具名合作。技术论断是准确的、成本优势是按请求计费的真实属性;对你自己的活动,在投入工作流之前先跑一个小试点。


每位参与者的成本 {#cost-per-participant}

一次完整的五任务核验,叠加反欺诈和影响力评分,每位参与者花 7 次 API 请求:

  • 1 次 /info 请求(反欺诈加用于评分的粉丝数)
  • 5 次请求用于五个核验核查
  • 可选 1 次请求用于账号所有权核验(如实现)

Sorsa 采用按请求计费:1 次 API 调用 = 月度额度里的 1 次请求,无论哪个接口。在 Pro 套餐($199/月,10 万次请求)上,那约为每月 1.4 万名完全核验的参与者。在 Enterprise($899/月,50 万次请求)上约 7.1 万名。那个上限之上有定制套餐。

活动规模所需请求数推荐套餐套餐价格
最多 1,400 名参与者~10,000Starter$49/月
最多 14,000 名参与者~100,000Pro$199/月
最多 71,000 名参与者~500,000Enterprise$899/月
71,000+ 名参与者定制联系销售定制

在 Pro 套餐费率下,一次完整的 7 请求核验约花 每位参与者 $0.014。对一个 1 万参与者的活动,那约为 $140 的 API 请求。

与官方 X API 的反差来自计费模型、而非某个标价。X 按抓取的资源计费,每条帖子 $0.005、每份用户资料 $0.010,且没有直接核查接口,所以核验动作意味着拉取整份转推者和粉丝列表、并为其中每个条目付费,在 200 万次帖子读取月度上限和 OAuth 2.0 之下。Sorsa 无论底层受众多大都对每次 /check-* 调用收一次请求。两家服务商完整的按套餐和按接口拆解在我们的 Twitter API 定价指南里;如果你还在权衡选项,我们对 Twitter API 替代方案的梳理在成本和能力上对比了更广的领域。


如何开始 {#getting-started}

你可以几分钟就有可用的核验核查在跑。没有要等的开发者账号审批、没有要接的 OAuth 流程:创建一个密钥、把它放进 ApiKey 请求头、调用 /check-follow。每个账号注册即送 100 次免费请求,一份无需绑卡、永不过期、覆盖全部 40 个接口的一次性额度,所以你可以在付费之前核验一个小测试批。之后入门套餐是 $49 含 1 万次请求,每个层级都包含每个接口,速率限制是固定每秒 20 次请求。

关于核验接口和响应形状的完整菜单,见核验接口参考


常见问题 {#faq}

能通过 API 核验 Twitter 点赞吗?

不能。X 在 2024 年 6 月把点赞设为私密,而截至 2026 年,没有公开或第三方 API 能回答一个用户是否点赞了另一个人的推文。这是平台级变化、而非 Sorsa 的局限。如果你的活动模板仍要求点赞,把那个任务换成转推或评论,两者都仍完全可核验、并携带更强的互动信号。

核验 Twitter 动作需要 OAuth 或开发者账号审批吗?

用 Sorsa API 不需要。认证是一个单一的 ApiKey 请求头,没有 OAuth 握手、没有回调 URL,也没有应用审核或审批队列。官方 X API 确实需要 OAuth 2.0 和一个已批准的开发者应用,且它按抓取的资源计费,这让规模化核验比按请求计费模型更慢搭建、更贵。

能检查有人是否转推了一条有数千转推的推文吗?

能。/check-retweet 接口每次调用扫描 100 条转推、并返回 next_cursor 用于分页。本指南里的示例代码封顶在 5 页(500 条转推),这通常够,因为参与者往往在被提示后几小时内转推。对你需要扫得更深的推文,提高页数上限,核查就继续走遍完整列表。

如何核验有人真的拥有他们参与用的 Twitter 用户名?

生成一个唯一短代码、请参与者发一条含它的推文,再用 user-tweets 接口在他们的近期时间线里查那个代码。一个可用示例在本指南的账号所有权一节。这是正经的抽奖和大使平台用来防止人们提交他们不掌控的用户名的标准模式。

如果参与者有一个私密(受保护)账号会怎样?

check-follow 和 check-quoted 的响应包含 user_protected 标志。当该标志为 true 时,该账号的关注关系图不被暴露、你无法以编程方式确认一次关注或引用。你的选项是请参与者把资料设为公开以便核验、带清晰提示拒绝该参与,或跑账号所有权核验并手动放行接受。在典型活动里,不到 1% 的参与者有私密账号。

如何防止机器人钻抽奖的空子?

用三层 API 级防御:通过 /info 接口做账号质量核查(最低年龄、推文数和粉丝);对评论和引用做质量核查(最低长度和一个必需话题标签);以及在任何奖励发出之前做账号所有权核验。这些没有一个是完整的女巫检测系统。但合起来,它们移除了榨干大多数活动的“轻松赢”情况,每个被拒账号还为你省下本会花在该账号上的核验请求。

核验互动比用官方 X API 更便宜吗?

具体到核验,是的。官方 X API 没有直接核查接口。你只能通过拉取完整的转推者或粉丝列表、按资源付费来重建每个答案:每条帖子 $0.005、每份资料 $0.010,都在 200 万次帖子读取上限之下。Sorsa 无论受众多大都对每次核查收一次请求,从 $0.0049 降到约每次请求 $0.002,所以一次完整的活动核验只花一个小零头。

能把这些核查用于非营销用例吗?

能。常见的非营销用途有几类。通过在授予角色之前核验一个用户关注品牌来门控私密 Discord 频道;追踪员工或合作伙伴的社交放大合规;以及在联盟计划里校验用户提交的归因声明。每一个都是同一个单布尔核查,只是应用在抽奖上下文之外。


审校:Keksich(Sorsa 创始人,X API 研究者)

本指南是怎么写成的:它取材于我们构建并运营 Sorsa 核验接口的一线工作、对着 API 本身的实时调用,以及关于接口和响应细节的 Sorsa API 文档。成本对比用官方 X API 当前的按量付费定价和政策页面作为其费率、200 万次帖子读取上限和 OAuth 要求的参照。于 2026 年 6 月核实。