社交媒体排期 API:完整指南

社交媒体排期 API:完整指南

通过 API 发布内容时排期是如何运作的:时区、状态、平台宕机时会发生什么, 以及该按什么模型来构建。

通过 API 立即发布很简单。有意思的问题都出在排期上,因为一条已排期的帖子是对未来做出的一个承诺,而未来里包含夏令时、服务中断,以及你后来改变主意的帖子。

时区:一定要显式传递

最常见的排期漏洞,是一条帖子每年偏移一小时、一年发生两次。

一个排期时间需要两样东西:作为 ISO-8601 时间戳的那个具体时刻,以及它被表达时所处的时区,用类似 America/New_York 这样的 IANA 名称表示。

await bp.posts.create({
  content: 'Morning update.',
  channels: [{ channelId: 1, platform: 'linkedin' }],
  status: 'scheduled',
  scheduledAt: '2026-04-10T14:00:00Z',
  timezone: 'America/New_York',
});

只存一个 UTC 时刻,对一次性的帖子来说没问题。但对任何周期性的任务来说都是错的,因为”每个工作日当地时间早上 9 点”在夏令时切换前后对应的是不同的 UTC 时刻。正是时区让这一点变得正确。

绝不要用一个像 -05:00 这样的原始偏移量来代替时区。偏移量会变,时区不会。

建模两种以上的状态

一条帖子不只是”已排期”或”已发布”这两种状态。至少要为以下这些状态做建模:

  • draft,已创建但尚未加入队列
  • scheduled,已加入队列,等待某个时间
  • processing,已发送给平台,结果未知
  • published,已确认成功上线
  • failed,附带原因
  • partial,部分目标发布成功,部分没有

人们常常忘记的两个是 processingpartial

processing 之所以存在,是因为好几个平台会接受一条帖子并异步发布它。收到 200 不代表已经发布,真正的结果会在之后才到来。

partial 之所以存在,是因为一条帖子通常会面向多个平台。如果三个成功、一个失败,那么”published”和”failed”都不成立,硬把它归到任何一边,都会做出一个对用户撒谎的界面。

平台宕机时会发生什么

要为此做设计,因为它确实会发生。

临时性失败应该带退避重试。 一个平台返回 503 持续两分钟,不应该让帖子就此丢失。

重试必须是安全的。 一次超时的创建请求也许其实已经成功了。盲目重试会导致帖子重复,这比原本的失败更糟糕。重试前先核对一下。

永久性失败根本不应该重试。 一个过期的 token 或一条无效的文案不会自己修好,重试只会白白消耗配额,还会延迟通知的到达。

必须有人被告知。 凌晨三点一条已排期帖子的发布失败,如果你没让它发出声音,就会悄无声息。webhook 是正确的机制。

编辑和取消

一条已排期的帖子是一个你可能需要打破的承诺。你的集成应该支持修改时间、编辑内容,以及彻底取消。

需要注意,一旦帖子已经被平台接管,各平台在是否允许这些操作上做法不一,这也是为什么在你自己这一层做排期、临近发布时刻才提交给平台,会比把一条未来日期的帖子直接交给平台表现得更好的原因之一。

队列时段与明确时间

有两种排期模型,各有各的用武之地。

明确的时间,适用于一条帖子必须在某个特定时刻落地的场景:一次发布会、一场活动、一次协调好的公告。

队列时段,适用于持续稳定地少量发布的场景。你定义一个发布节奏,下一条帖子就占用下一个空闲时段,这样你就不用给一批帖子里的每一条都手动选一个时间戳。

对批量工作来说,第二种方式要省事得多,也正是这种模型让”把三十条帖子加入队列”变成一个合理的单一操作,而不是三十个决定。

周期性排期

这和一条已排期的帖子是不同的概念。一个周期性排期是一条规则,会按某个频率持续产生帖子:每日、每周、双周或每月。

有两件事需要在设计时考虑。时区在这里比前面提到的更重要,原因和夏令时一样。而且附加在一个周期性帖子上的媒体必须保留下来,而不能在发布后被清理掉,因为下一次这个排期还会再用到它。

套餐限制

FreeProBusiness
每日 API 请求数305,00050,000
帖子数量每天 3 条每天 30 条无限
周期性排期数量10无限

简而言之

每一个排期时间戳都要附带一个 IANA 时区,尤其是任何周期性任务。把 processingpartial 建模成真实的状态,因为异步发布和多平台帖子确实会让这两种情况真实发生。对临时性失败要带退避重试,绝不盲目重试一次创建请求,并用 webhook 让凌晨三点的失败不会悄无声息。