SDKNode.js SDK

SDK

Node.js SDK

Установите @sofia-post/node и вызывайте API Sofia из Node.js: публикуйте, планируйте, загружайте медиа и читайте статистику, с типизированными ошибками.

Официальный Node.js SDK оборачивает API Sofia v1 в один класс, Sofia: по одному методу на маршрут, типизированные запросы и ответы и один тип ошибки на любой сбой. У него нет зависимостей, и он работает на Node.js 20 и новее.

Установка

SDK опубликован в npm как пакет @sofia-post/node. Он работает и с 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, вкладка Личный доступ, или токен доступа OAuth, если ваше приложение действует от имени других пользователей Sofia (OAuth2). SDK отправляет его как Authorization: Bearer … в каждом запросе.

По умолчанию клиент обращается к https://api.sofia-post.com. Второй аргумент меняет базовый URL или fetch, которым отправляются запросы:

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

Методы

МетодЧто делает
me()От чьего имени действует ключ, его скоупы и является ли он тестовым
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);

Ошибки

Каждый метод выбрасывает SofiaApiError, когда API отклоняет вызов. Он содержит 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 недоступен совсем, у ошибки код network_error и статус 0. SDK никогда не повторяет запрос сам: при 429 подождите retryAfterSeconds, а при 5xx увеличивайте паузы между попытками.

TypeScript

Пакет поставляется со своими типами: PublishPostInput, Post, Media, SocialAccount, EstablishmentInsights и другие экспортируются рядом с Sofia, так что редактор подсказывает каждое поле и каждое значение перечисления.

Дальше: справочник API описывает каждый маршрут, который вызывает SDK, а CLI управляет тем же API из терминала.

Эта страница была полезной?