@post2all / sdk
post2all REST API的类型安全TypeScript客户端。
完整的指南和例子: post2all TypeScript SDK文档.
安装
pnpm add @post2all/sdk
创建一个帖子
import { Post2allClient } from "@post2all/sdk";
const client = new Post2allClient({
apiKey: process.env.POST2ALL_API_KEY!,
});
const { post } = await client.createPost({
content: "New release shipping today 🚀",
targets: [
{
platform: "discord",
accountId: "acc_discord_123",
settings: {
channelId: "1234567890",
autoCrosspost: true,
},
},
{
platform: "threads",
accountId: "acc_threads_123",
settings: {
caption: "A shorter Threads version",
topicTag: "buildinpublic",
},
},
],
delivery: { mode: "now" },
});
对于生产创建,传递一个稳定的等幂键,这样超时可以重试,而不需要创建第二个post:
await client.createPost(input, { idempotencyKey: "customer-job-123" });
使用默认值 baseUrl, API请求不遵循HTTP重定向(redirect: "manual"),所以你 x-api-key 永远不会转发到另一个主机。一个自定义 baseUrl 保持fetch的默认值;通过 redirect: "manual" 选择加入同样的保护。
targets 是一个受歧视的工会。一次 platform , TypeScript和Zod只接受该平台支持的设置。
平台id,设置字段,固定枚举,限制,静态帐户连接元数据, publishedDeletion.available 能力和经过消毒的分析模式元数据是由私有的monorepo的公共契约生成的。不要在此存储库中编辑生成的契约文件;发布同步作业重新生成它。
从您的SaaS连接社交帐户
Post2all可以作为你自己产品的社交账户后端。您的服务器保留post2all API密钥;最终用户的浏览器只访问社交提供者授权页面和您自己的回调URL。
const started = await client.connectAccount("instagram", {
redirectUrl: "https://app.example.com/settings/social/complete",
});
// Send the user's browser to started.authorizationUrl.
console.log(started.connectionId, started.authorizationUrl);
用户会 不 需要post2all帐户、post2all登录或post2all浏览器会话。在提供者回调之后,post2all将浏览器返回到您的 redirectUrl. 从后端验证权威结果:
const connection = await client.getAccountConnection(started.connectionId);
if (connection.status === "connected") {
const account = await client.getAccount(connection.accountIds[0]);
console.log(account.account);
}
永远不要在浏览器代码中暴露post2all API密钥。浏览器重定向是一种用户体验切换;使用 getAccountConnection() 服务器端,然后再信任结果。
如果凭据过期或范围更改,稍后重新连接确切的提供者标识:
const reconnect = await client.reconnectAccount("acc_instagram_123", {
redirectUrl: "https://app.example.com/settings/social/complete",
});
如果新授权的提供者身份与现有帐户不匹配,Post2all将拒绝重新连接。
客户端和SaaS租户的配置文件
业务、代理和基于信用的工作区可以将客户、品牌或客户保存在可选的概要文件中。业务最多支持2个配置文件,代理最多支持10个配置文件,信用工作区最多支持10,000个。概要文件是组织/过滤上下文,而不是单独的API凭据或租户授权边界。
const { profile } = await client.createProfile({
name: "Acme",
externalId: "customer_123",
});
const acme = client.forProfile(profile.id);
const accounts = await acme.listAccounts();
配置文件客户端发送 x-profile-id 自动。它是一个组织/过滤上下文,而不是一个单独的安全凭据:过滤支持配置文件的列表,将新连接分配给该配置文件,并在该配置文件下组织新帖子。概要文件管理仍然是组织范围的。
转移账户 setAccountProfile(accountId, profileId) 或通过 null 清除其配置文件分配。每个帐户一次最多属于一个配置文件。移动帐户不会移动历史帖子或破坏现有的草稿、时间表、重试、分析或帖子目标。删除配置文件将保留其帐户和帖子作为无配置文件的资源。
推荐的SaaS模式是为组织级配置文件管理保留一个根客户端,然后为每个客户使用一个限定范围的客户端:
const root = new Post2allClient({
apiKey: process.env.POST2ALL_API_KEY!,
});
const { profile } = await root.createProfile({
name: "Acme",
externalId: "customer_123",
});
const acme = root.forProfile(profile.id);
const started = await acme.connectAccount("instagram", {
redirectUrl: "https://app.example.com/social/complete",
});
const { accounts } = await acme.listAccounts();
const posts = await acme.listPosts();
省略概要文件上下文意味着完整的工作空间。 externalId 是可选的,用于将post2all配置文件映射到您自己的客户或租户ID。将工作区API密钥保存在受信任的后端;工作区仍然是授权边界。
Telegram使用带有机器人代码响应的相同API,而circle直接接受凭据:
const telegram = await client.connectAccount("telegram");
const wircle = await client.connectAccount("wircle", {
credentials: {
apiKey: process.env.WIRCLE_API_KEY!,
profileHandle: "@maker",
},
});
乳齿象帐户位于独立的服务器上,因此传递帐户的句柄(或仅传递其服务器,例如 mastodon.social), handle. 服务器必须是可访问的;post2all在其上注册一个OAuth应用程序并返回服务器的授权URL:
const mastodon = await client.connectAccount("mastodon", {
handle: "[email protected]",
redirectUrl: "https://app.example.com/social/complete",
});
通过相同的 handle 选项 reconnectAccount() 当重新连接乳齿象帐户时。
交付模式
await client.createPost({
content: "Work in progress",
delivery: { mode: "draft" },
});
await client.createPost({
content: "Scheduled announcement",
targets: [
{
platform: "linkedin",
accountId: "acc_linkedin_123",
settings: {},
},
],
delivery: {
mode: "scheduled",
scheduledAt: "2026-07-20T09:00:00+05:30",
},
});
草稿可能会省略目标和不完整的发布设置。即时和计划交付需要有效的目标、媒体和所有所需的平台设置。
帐户发布选项
在编写之前加载一次选定帐户模式:
const schema = await client.getPublishingSchema([accountId]);
console.log(schema.accounts); // Fixed choices and account-specific limits, including X tiers
在渲染或提交动态设置(如Discord频道或TikTok隐私选项)之前,请使用帐户发布选项:
const options = await client.getPublishingOptions(["acc_discord_123"]);
console.log(options.accounts[0]?.destinations);
console.log(options.accounts[0]?.boards);
capability 是权威的、特定于帐户的约束集。在撰写或验证帖子之前阅读它,而不是硬编码平台限制。例如,一个X账户 capability.text.maxLength 反映该帐户是免费、基本、高级还是高级+。
不要发送固定类型的帖子。组合是从附加介质中推断出来的。混合图像/视频只允许当平台 media.allowMixedMedia 是真的。当 capability.media.altText 是存在的,每个附加的媒体项目可以包括自己的 altText;使用返回的媒体类型和最大长度。X故意不暴露媒体alt文本。
乳齿象的设置是 caption, mastodonVisibility (public, unlisted 安静的公共场所,或者 private 仅供追随者使用;默认为 public), contentWarning, sensitive (模糊附加媒体;图片和视频帖子)。每个服务器设置自己的字符限制(默认情况下为500个字符),模式以每个帐户为单位报告字符限制 capability.text.maxLength);链接计数为23个字符,内容警告计数为限制。最多可附上4张图片(每张8mb)或1段视频(40mb);图像和视频不能混合。已发布的帖子删除可用于乳齿象目标。
松弛设置是 caption, channelId (必需的;从 destinations 返回的 getPublishingOptions()), unfurlLinks (默认为 true;集 false 发布链接没有Slack预览卡)。消息最多可容纳4,000个字符和最多10个文件,原生上传到工作区:图像(GIF, JPEG, PNG, WebP)每个最多20 MB,视频(MP4, MOV, WebM)每个最多200 MB,自由混合。公共频道立即发布;首先将post2all应用程序邀请到私人频道。已发布的帖子删除可用于Slack目标。
import { mastodonSettingsSchema } from "@post2all/sdk";
await client.createPost({
content: "Release notes are up: https://example.com/changelog",
targets: [
{
platform: "mastodon",
accountId: "acc_mastodon_123",
settings: mastodonSettingsSchema.parse({
mastodonVisibility: "unlisted",
contentWarning: "Release notes",
sensitive: false,
}),
},
],
delivery: { mode: "now" },
});
TikTok需要后全管理媒体(capability.media.requiresManagedMedia):上传或导入带有 uploadMedia() / uploadMediaFromUrl() 然后通过 id;直接caller-managed url TikTok的目标媒体被拒绝。
第一个评论
X, Instagram (feed posts and reel), Facebook Pages, Threads, Bluesky和circle目标接受可选选项 firstComment 同一账户下发布的帖子,加上 firstCommentDelaySeconds (整数,0-86400)从目标发布的那一刻开始计数。检查 schema.accounts[i].firstComment 从 getPublishingSchema() 第一:当 available 是 false,展示 reason (通常必须重新连接帐户以授予评论权限)并省略这两个字段。每个平台的注释长度报告在 capability.fields.firstComment.maxLength. 没有评论的延迟将被拒绝。在X上,每条评论都是一个额外的API创建,像一个帖子一样计费。
await client.createPost({
content: "Our new pricing is live.",
targets: [
{
platform: "instagram",
accountId: "acc_instagram_123",
settings: {
firstComment: "Full breakdown: https://example.com/pricing",
firstCommentDelaySeconds: 120,
},
},
],
delivery: { mode: "now" },
});
每个已发表的目标报告 firstComment: { status, dueAt, sentAt, platformCommentId, error } 从 getPost(). 最后重试 failed 注释或取消 pending 不触碰母柱的:
await client.retryFirstComment("post_abc", "post_account_1");
await client.cancelFirstComment("post_abc", "post_account_1");
的注释 unknown 状态不能自动重试;重发前请检查平台。
信用计费和发布能力
手动登录信用账单的组织可以检查其预付费访问权限和选定帐户滚动发布能力:
const billing = await client.getBilling();
const xPricing = await client.getXApiPricing();
const limits = await client.getPublishingLimits(["acc_instagram_123"]);
getBilling() 是组织范围的,包括当期的X API计数和支出。 getXApiPricing() 返回标准的零标记X率:目前每个不带URL的帖子为15,000微博,每个包含URL的帖子为200,000微博。 getPublishingLimits() 保存 forProfile() 作用域并返回一个建议快照;发布时强制执行仍然具有权威性,并自动推迟已耗尽容量的目标。
Credit-organization人
信用工作区所有者和管理员在post2all仪表板中管理webhook端点。SDK验证传入的交付:
import { verifyWebhookSignature } from "@post2all/sdk";
const valid = verifyWebhookSignature({
rawBody,
secret: process.env.POST2ALL_WEBHOOK_SECRET!,
eventId: headers.get("x-post2all-event-id") ?? "",
timestamp: headers.get("x-post2all-timestamp") ?? "",
signature: headers.get("x-post2all-signature") ?? "",
});
指示板在端点创建后仅显示一次签名秘密。交付至少一次;存储秘密服务器端并在稳定事件ID上重复数据删除。
使用 onResponse 收集请求id和请求配额元数据,而不改变任何方法的返回形状:
const client = new Post2allClient({
apiKey: process.env.POST2ALL_API_KEY!,
onResponse: ({ requestId, rateLimit }) => console.log(requestId, rateLimit),
});
分析
阅读规范化的账户指标、时间序列、供应商指标定义和前期比较:
const analytics = await client.getAccountAnalytics("acc_instagram_123", {
startDate: "2026-08-01",
endDate: "2026-08-31",
});
console.log(analytics.metrics);
console.log(analytics.comparisons);
默认取值范围为最近30天(包括UTC天数),最大取值范围为90天。通过 refresh: true 只有当您明确需要新的提供商数据而不是正常的分析缓存时。
比较提供者范围内的岗位表现:
const posts = await client.listAccountAnalyticsPosts("acc_instagram_123", {
sortBy: "views",
sortDirection: "desc",
limit: 20,
});
受支持的平台可以返回在post2all之外发布的帖子。使用 origin 区分匹配的所有岗位 external 提供者的帖子;不匹配的外部岗位故意省略 postId 和 postAccountId.
阅读post2all帖子的每个目标的分析:
const result = await client.getPostAnalytics("post_abc");
检查每个目标的 analyticsStatus 在解释空的度量数组之前。不可用的提供者数据、重新连接需求、未发布的目标和提供者错误都不是零参与。
重试失败的post目标
重试失败或部分失败的发布,但不重新发布成功的目标。
await client.retryPost("post_abc");
在需要时,只安排失败的目标重试:
await client.retryPost("post_abc", {
scheduledAt: "2026-09-21T14:00:00+05:30",
});
例如,如果Instagram和YouTube成功了,但TikTok失败了, retryPost() 只发布失败的TikTok目标。
媒体
const { media } = await client.uploadMedia("./video.mp4");
await client.createPost({
content: "Product walkthrough",
media: [
{
id: media.id,
altText: "Product walkthrough showing the publishing workflow",
},
],
targets: [
{
platform: "youtube",
accountId: "acc_youtube_123",
settings: {
title: "Product walkthrough",
privacyStatus: "unlisted",
},
},
],
delivery: { mode: "now" },
});
如果你的应用程序已经托管了稳定的公共HTTPS媒体,你可以跳过上传,直接附加URL:
await client.createPost({
content: "Launch",
media: [
{
url: "https://cdn.example.com/launch.mp4",
altText: "Launch walkthrough",
},
],
targets,
delivery: { mode: "scheduled", scheduledAt: "2026-10-20T09:00:00Z" },
});
直接URL媒体保持调用者管理,并且必须保持公共可访问,直到每个计划的发布/重试完成。如果URL是临时的或签名的,首先安全地摄取托管副本:
const { media } = await client.uploadMediaFromUrl(
"https://temporary.example.com/launch.mp4",
"launch.mp4",
);
mediaIds 当您只需要附加托管媒体id时,仍然接受兼容性。新的集成应该更喜欢 media,它接受 { id } 或者 { url } 条目和可选的按媒体Alt文本。不要同时发送 media 和 mediaIds 在一个请求中。
API
listProfiles(input?)getProfile(profileId)createProfile(input)updateProfile(profileId, input)deleteProfile(profileId)forProfile(profileId)listAccounts()listAccountPlatforms()connectAccount(platform, input?)getAccountConnection(connectionId)getAccount(accountId)reconnectAccount(accountId, input?)disconnectAccount(accountId)setAccountProfile(accountId, profileId)getAccountAnalytics(accountId, input?)listAccountAnalyticsPosts(accountId, input?)getPublishingSchema(accountIds)getPublishingOptions(accountIds)getAccountPublishingOptions(accountId)(兼容性)getBilling()(只适用于信贷机构)getXApiPricing()(只适用于信贷机构)getPublishingLimits(accountIds)(只适用于信贷机构)uploadMedia(path)uploadMediaFromUrl(url, filename?)—安全导入公共HTTPS URL到post2all-managed storagecreateMediaUpload(input)confirmMediaUpload(mediaId)createPost(input, options?)listPosts(input?)getPost(postId)getPostAnalytics(postId, input?)updatePost(postId, input)retryPost(postId, input?)-只重试失败的目标,并可选择调度重试deletePublishedPost(postId, postAccountId)-在公共删除平台上删除一条已发布的社交帖子,同时保留post2all帖子deletePost(postId)-从post2all中删除帖子;已经发布的社交内容仍然存在cancelPost(postId)
使用 getPost(postId) 首先检查一下 target.deletion.available. 当它是 false, target.deletion.reason 解释了为什么。此运行时状态已经包括平台转出、帐户状态、提供者id和时间限制。私有推出平台永远不会通过API密钥解锁。
错误
所有API和响应验证失败都会抛出 Post2allApiError. 验证错误响应可能包括字段级问题,例如 targets.0.settings.channelId.
更新日志
请参阅存储库 更新日志 有关版本化SDK和CLI的更改、弃用和兼容性说明。