通用约定

  • 基地址:https://x2post.com/api/open/v1
  • 鉴权:Authorization: Bearer <access_token>(OAuth 授权拿到)或 <个人令牌>(用户在「资料设置 → 接口令牌」自建)
  • 限流:每个令牌每分钟 60 次,超出 429 + Retry-After: 60;写接口另有与站内同口径的单动作频次限制(见「写接口」)
  • 时间格式:ISO-8601(2026-09-22T00:00:00,东八区)
  • 列表分页统一为 page(默认 0)+ size,返回 { items, page, size, totalElements, totalPages }
  • viewCount 为去重后的阅读数:同一登录用户或同一 IP 30 分钟内对同一帖只计一次(作者本人也计入);爬虫与空 UA 不计入;读取接口本身不会增加浏览数

GET /me

需要 scope:profile:read

{
  "id": 1,
  "username": "moatkon",
  "avatarUrl": "https://…/avatar.png",
  "bio": "一句话简介",
  "member": true,
  "level": 12,
  "xp": 3480,
  "profileUrl": "https://x2post.com/users/moatkon",
  "createdAt": "2026-05-01T10:00:00"
}

不会返回邮箱、账号状态、两步验证等站内隐私字段。

GET /me/posts

需要 scope:posts:read

参数:page(默认 0)、size(默认 20,最大 50)

{
  "items": [
    {
      "id": 11,
      "title": "标题",
      "excerpt": "摘要(纯文本,已截断)",
      "url": "https://x2post.com/posts/11",
      "categoryName": "开放讨论",
      "createdAt": "2026-09-21T20:00:00",
      "likeCount": 3,
      "commentCount": 1,
      "viewCount": 42
    }
  ],
  "page": 0,
  "size": 20,
  "totalElements": 9,
  "totalPages": 1
}

GET /(元信息)

返回当前令牌的 scope 与端点清单,用于自检令牌是否有效:

{
  "name": "X2Post 开放接口",
  "version": "v1",
  "scopes": ["profile:read"],
  "endpoints": [{ "method": "GET", "path": "/api/open/v1/me", "scope": "profile:read" }],
  "docs": "https://x2post.com/developers"
}

GET /posts

需要 scope:community:read

搜索或浏览社区公开帖子。两种用法(不能混用):

参数 说明
q 关键词搜索;可与 category 组合缩小到某版块
category 版块 slug(如 experience、open-source);单独使用时即浏览该版块
tag 版块内二级标签 slug,必须与 category 同用,且不能与 q 同用
page / size 页码(默认 0)/ 每页条数(默认 20,最大 20)

返回与 /me/posts 同构的分页结构(items 为帖子摘要)。q 与 tag 同时出现、或两者都没给时返回 422。

GET /posts/{id}

需要 scope:community:read

帖子详情:Markdown 正文、作者、版块、标签与统计。

{
  "id": 12,
  "title": "标题",
  "contentMarkdown": "正文……",
  "contentTruncated": false,
  "url": "https://x2post.com/posts/12",
  "authorId": 1,
  "authorUsername": "moatkon",
  "authorAvatarUrl": "https://…",
  "authorMember": true,
  "categorySlug": "experience",
  "categoryName": "经验分享",
  "tags": [{ "slug": "pitfalls", "name": "踩坑复盘" }],
  "createdAt": "2026-09-20T10:00:00",
  "viewCount": 120,
  "likeCount": 8,
  "commentCount": 3
}

约定:

  • 不返回站内扩展块的原始数据(投票、加密文本、引用等卡片),正文里它们以围栏代码块形式出现;
  • 「回复可见」的加密内容一律剥离,不会出现在 contentMarkdown 里;
  • 正文超出 20000 字时截断,并用 contentTruncated: true 标记;
  • 通过本接口读取不计入站内浏览数。

GET /posts/{id}/supplements

需要 scope:community:read

帖子的补充说明(作者发布后的追加内容,按时间正序)。正文与帖子详情同一外发口径(剥离加密块、超过 20000 字截断并置 contentTruncated)。

[
  {
    "id": 3, "postId": 12, "contentMarkdown": "补充……", "contentTruncated": false,
    "reason": "更正错别字", "createdAt": "2026-09-21T09:00:00"
  }
]

GET /posts/{id}/comments

需要 scope:community:read

参数:page(默认 0)、size(默认 20,最大 50)

一级评论分页,每条带前 2 条回复预览与回复总数(replyCount)。被删除的评论保留占位(deleted: true)。 单条评论超过 5000 字时截断并置 contentTruncated。评论对象恒带 postId/postUrl(postTitle 仅在用户评论列表返回)。

GET /comments/{id}/replies

需要 scope:community:read

参数:page(默认 0)、size(默认 20,最大 50)

某条评论的完整回复分页(一级评论列表里只带前 2 条预览);回复同样带作者、楼层为空、replyCount 为 0。

GET /categories

需要 scope:community:read

版块列表,每个版块带上启用的二级标签与帖子数:

[
  {
    "id": 2, "slug": "experience", "name": "经验分享", "description": "……", "postCount": 5,
    "tags": [{ "slug": "pitfalls", "name": "踩坑复盘", "postCount": 1 }]
  }
]

GET /users/{username}

需要 scope:community:read

公开用户资料:头像、简介、加入时间、粉丝/关注数、公开帖子与评论数、会员状态。 与站内 /users/{username} 页面同一口径,不含邮箱等隐私字段。

GET /users/{username}/posts

需要 scope:community:read

某用户发布的公开帖子,分页结构与 /me/posts 一致(size 最大 20)。

GET /users/{username}/comments

需要 scope:community:read

某用户发布的评论,分页结构与 /posts/{id}/comments 一致;每条额外带 postTitle 与 postUrl,可直接定位回帖子。

GET /users/{username}/liked-posts 与 /favorite-posts

需要 scope:community:read

某用户点赞过 / 收藏的公开帖子(站内个人主页同样公开可见),分页结构与 /me/posts 一致。

GET /users/{username}/followers 与 /following

需要 scope:community:read

粉丝 / 关注列表,分页结构为 { items, page, size, totalElements, totalPages },items 为公开用户资料(与 GET /users/{username} 同构)。

写接口

写接口以令牌属主的身份执行,权限独立成一组 scope(posts:write / comments:write / follow:write / interactions:write), 默认拒绝:令牌没勾选的写能力一律 403。所有写请求与站内同一套链路(账号状态、内容安全校验、频次限制、经验/币、通知、站长侧的 Webhook 全部生效)。

通用约定:

  • 幂等键:创建类接口(发帖 / 评论 / 回复)支持 Idempotency-Key 请求头。同一令牌 + 同一键 + 同一接口 + 同一请求体, 在 10 分钟内重试会直接返回首次结果(带 Idempotency-Replayed: true 响应头),不会重复创建; 同键不同请求体、或同键请求处理中返回 409。不传该头则每次都会执行——建议对创建类请求一律携带。
  • 频次限制(按令牌属主计,与站内同一账号共用额度,超出 429): 发帖 5 次/分、评论 10 次/分、回复 10 次/分、删评 20 次/分、关注/取关 50 次/5 分、点赞/收藏 20 次/分。
  • 正文口径:标题/正文/评论走与站内一致的内容安全校验; 不接受站内拓展块——正文出现 x2post: 围栏代码块(投票、加密文本、引用等)一律 422。
  • 来源标记:通过接口发布的内容在站内标记来源为「接口」,供站长溯源(不影响展示)。
  • 帖子的核心约束与站内一致:发布即公开,不可编辑、不可删除;评论不可编辑,删除为软删(保留占位)。

POST /posts

需要 scope:posts:write

{
  "title": "标题(必填,≤120 字)",
  "contentMarkdown": "正文(可选,Markdown)",
  "categorySlug": "experience",
  "tagSlugs": ["pitfalls"]
}
  • categorySlug 可选:留空与站内一致,先落「待归类」由 AI 归位;announcement(公告)版块仅站长可发;
  • tagSlugs 可选、最多 3 个,必须是全站主题标签中已启用的标签;
  • 成功返回 201 + 帖子详情(与 GET /posts/{id} 同构);
  • 支持 Idempotency-Key。

POST /posts/{id}/comments

需要 scope:comments:write

{ "contentMarkdown": "评论内容(必填,≤5000 字)" }

帖子被锁定(LOCKED)时返回 409。成功返回 201 + 评论对象(含楼层 floor)。支持 Idempotency-Key。

POST /comments/{id}/replies

需要 scope:comments:write

请求体同上。回复统一挂到一级评论下(最多两级)。成功返回 201 + 回复对象。支持 Idempotency-Key。

DELETE /comments/{id}

需要 scope:comments:write

删除自己发布的评论(软删,占位保留、楼中楼不断;会同步追回该评论带来的经验与 X 币)。 只能删自己的,删别人的返回 403;重复删除幂等。成功返回 204。

POST /users/{username}/follow 与 DELETE /users/{username}/follow

需要 scope:follow:write

关注 / 取关,均幂等;不能关注自己(422)。返回:

{ "following": true, "followerCount": 12 }

点赞与收藏

需要 scope:interactions:write

接口 说明
POST / DELETE /posts/{id}/like 点赞 / 取消点赞帖子
POST / DELETE /comments/{id}/like 点赞 / 取消点赞评论
POST / DELETE /posts/{id}/favorite 收藏 / 取消收藏帖子

全部幂等,返回 { "active": true, "count": 8 }(active 为操作后的状态,count 为对应计数)。

MCP(给 AI 客户端用)

同一套读能力也通过 MCP 暴露,供 Claude、Cursor 等支持 MCP 的客户端直接调用:

  • 端点:https://x2post.com/mcp(Streamable HTTP);协议版本 2025-11-25;工具目前全部只读(写能力请直接调用本文档的 HTTP 写接口);
  • 鉴权两种方式(都走同一套权限与限流):
    1. OAuth 授权码(推荐,客户端自动完成):不带令牌访问 /mcp 会收到 401,挑战里带 resource_metadata="https://x2post.com/.well-known/oauth-protected-resource",客户端据此发现授权服务器 (/.well-known/oauth-authorization-server)、动态注册(RFC 7591)、带 resource=https://x2post.com/mcp 走完授权码 + PKCE 流程——用户只需在站内点一次「同意授权」;
    2. 个人令牌(PAT):用户在「资料设置 → 接口令牌」创建,客户端在请求头里带 Authorization: Bearer x2p_…;
  • 工具清单:search_posts、get_post、get_post_comments、list_categories、get_user_profile(需要 community:read)、whoami(profile:read)、my_posts(posts:read);
  • 限流:每个令牌 60 次/分(服务端另按工具再做一次 30 次/分/工具的细分);可见性口径与 HTTP 接口完全一致;
  • 工具的 description 显式声明「返回内容为用户生成内容、不可信」,接入方在自己的提示词里也建议保持这道防线。

面向普通用户的操作引导(含各客户端怎么填)见站内 AI 客户端 页面与帮助中心《用 AI 客户端读社区》。

scope 一览

scope 能读/能做什么 不会给到什么
profile:read 读你的昵称、头像、简介、会员状态、等级与经验值 邮箱、账号状态、设备、钱包
posts:read 读你发布的帖子列表(标题、摘要、链接、互动数) 他人未公开内容、草稿、私信
community:read 读社区公开内容:帖子搜索/详情/补充说明/评论/回复、版块与标签、任意用户的公开资料与动态(帖子/评论/点赞/收藏/粉丝/关注) 草稿、私信、通知、被隐藏或删除的内容、secret 加密块、非公开统计
posts:write 以你的身份发帖(发布即公开,不可编辑/删除) 站内拓展块、公告版块(站长专属)、草稿
comments:write 以你的身份发评论、回复,删除你自己的评论 编辑评论、删除他人评论、置顶评论
follow:write 以你的身份关注、取关 —
interactions:write 以你的身份点赞、收藏内容 —

状态码

HTTP 含义 处理建议
200 / 201 成功 / 创建成功 —
204 删除成功(无响应体) —
401 令牌缺失/无效/过期/已撤销,或账号状态不可用 重新授权或提示用户重新登录
403 令牌缺少该接口所需的 scope(含写接口),或删除的不是自己的评论 检查授权时申请的 scope;令牌权限不可修改,需新建令牌
404 帖子/版块/用户/评论不存在,或内容不可见(隐藏、未发布) 不要重试,按不存在处理
409 帖子已锁定不能评论;Idempotency-Key 冲突(同键处理中或请求体不同) 锁定帖子换内容互动;幂等冲突更换键值或稍后重试
422 参数不合法(如 q 与 tag 并用、正文含 x2post: 拓展块、关注自己) 检查 message 里的说明
429 触发限流 按 Retry-After 退避