SDKNode.js SDK

SDK

Node.js SDK

安裝 @sofia-post/node,在 Node.js 中呼叫 Sofia API:發佈、排程、上傳媒體、讀取數據洞察,回應和錯誤都帶型別。

官方 Node.js SDK 把 Sofia API v1 封裝在一個類別 Sofia 中:每個路由對應一個方法,請求和回應都有型別,所有失敗都使用同一種錯誤型別。它沒有任何相依套件,可在 Node.js 20 或更高版本上執行。

安裝

SDK 以 @sofia-post/node 套件的名稱發佈在 npm 上。import 和 require 都可以使用。

npm install @sofia-post/node

快速開始

用你的金鑰建立用戶端,找到要發佈內容的店家,然後在 Instagram 上排程發佈一篇帖文:

import { Sofia } from '@sofia-post/node';

const sofia = new Sofia(process.env.SOFIA_API_KEY);

const [establishment] = await sofia.establishments();

const post = await sofia.post({
  establishmentId: establishment.id,
  targets: [{ platform: 'instagram', text: 'Tarte tatin du jour 🍎' }],
  scheduledAt: new Date('2026-12-01T09:00:00Z'),
});

console.log(post.id, post.status);

身分驗證

建構函式接收一個個人金鑰(在設定 › API 的個人存取標籤頁中建立),如果你的應用程式代表其他 Sofia 使用者操作,則接收 OAuth 存取權杖(OAuth2)。SDK 會在每次請求中以 Authorization: Bearer … 傳送它。

用戶端預設連線到 https://api.sofia-post.com。第二個參數可以更改基礎 URL,或傳送請求所用的 fetch:

const sofia = new Sofia(apiKey, { baseUrl: 'http://localhost:3008' });

方法

方式作用
me()金鑰代表誰操作、它的 scope,以及是否為測試金鑰
platforms()各網路的規則:文案長度、媒體、格式
establishments()金鑰可存取的店家
accounts(establishmentId)已連接到店家的社群帳號
connectionLink(establishmentId, input)由 Sofia 代管的頁面,使用者可在其中連接網路
insights(establishmentId, period?)依網路查看觸及、互動和粉絲數據
post(input, options?)立即發佈、用 scheduledAt 排程發佈,或儲存為草稿
postList(filters?)一頁帖文,可依店家、狀態或日期篩選
getPost(id) · updatePost(id, input) · deletePost(id)讀取、修改或撤回一篇帖文
upload(input) · uploadFromUrl(input)把檔案或 URL 加入店家的媒體庫
mediaList(filters) · getMedia(id) · deleteMedia(id)讀取並清理媒體庫
createWebhook(input) · webhooks() · deleteWebhook(id) · testWebhook(id)在帖文發佈或失敗時收到通知

帖文

一篇帖文在每個網路上都有一個目標,各自帶有文案、媒體和格式。請先用 dryRun 檢查:不會寫入任何內容,被拒絕時會列出它違反的每條規則。傳入 idempotencyKey,重試的請求就不會重複發佈。scheduledAt 接受 Date 或 ISO 8601 字串。

import type { PublishPostInput } from '@sofia-post/node';

const input: PublishPostInput = {
  establishmentId,
  targets: [
    { platform: 'instagram', text: 'Menu du jour', media: [{ id: media.id }] },
    { platform: 'facebook', text: 'Menu du jour : tarte tatin et café' },
  ],
};

await sofia.post(input, { dryRun: true });
await sofia.post(input, { idempotencyKey: crypto.randomUUID() });

媒體

檔案只需上傳一次,然後把它的 id 放進帖文的 media。upload 接受 Buffer、Uint8Array 或 Blob,除非你指定 contentType,否則會根據檔名判斷內容類型。uploadFromUrl 則由 Sofia 自己下載檔案。

import { readFile } from 'node:fs/promises';

const media = await sofia.upload({
  establishmentId,
  file: await readFile('tarte-tatin.jpg'),
  fileName: 'tarte-tatin.jpg',
});

const imported = await sofia.uploadFromUrl({ establishmentId, url: 'https://example.com/menu.png' });

分頁

postList 和 mediaList 每次回傳一頁。把一頁的 nextCursor 作為下一次呼叫的 cursor 傳入;最後一頁沒有它。

let cursor: string | undefined;
do {
  const page = await sofia.postList({ establishmentId, status: 'published', limit: 100, cursor });
  page.data.forEach((post) => console.log(post.id));
  cursor = page.nextCursor;
} while (cursor);

錯誤

當 API 拒絕呼叫時,每個方法都會擲出 SofiaApiError。它包含 HTTP status、錯誤信封中穩定的 code、details(對被拒絕的帖文,即它違反的每條網路規則)、需要提供給支援團隊的 requestId,以及在 429 時的 retryAfterSeconds。

import { SofiaApiError } from '@sofia-post/node';

try {
  await sofia.post(input);
} catch (error) {
  if (!(error instanceof SofiaApiError)) throw error;
  if (error.code === 'post_refused') console.log(error.details);
  if (error.status === 429) await wait(error.retryAfterSeconds);
}

當 API 完全無法連線時,錯誤的 code 為 network_error,狀態為 0。SDK 從不自動重試:遇到 429 請等待 retryAfterSeconds,遇到 5xx 請放慢重試間隔。

TypeScript

該套件自帶型別:PublishPostInput、Post、Media、SocialAccount、EstablishmentInsights 等都與 Sofia 一起匯出,因此你的編輯器會自動補全每個欄位和每個列舉值。

接下來:API 參考介紹了 SDK 呼叫的每個路由,CLI 則在終端機中操控同一套 API。

這個頁面對你有幫助嗎?