Аутентификация
Получить ключ APIКаждый вызов несёт Bearer-токен в заголовке Authorization. Sofia перечитывает связанные с ним права при каждом вызове: если человека удалили из Workspace или авторизацию отозвали, токен перестаёт работать со следующего запроса.
| Способ | Для | Токен |
|---|---|---|
| Личный ключ | Автоматизация собственного аккаунта, скрипты, агенты | sofia_pk_live_…, действует до истечения срока |
| OAuth, authorization code + PKCE | Продукт, действующий от имени пользователей в выбранном каждым Workspace | sofia_live_at_…, один час, продлевается |
| OAuth, client credentials | Ваш сервер, автоматизирующий принадлежащий вам Workspace | sofia_live_at_…, один час |
Личные ключи
Создайте ключ в Настройки › API › Личный доступ. Он действует от вашего имени во всех ваших Workspace: указанное заведение определяет Workspace, а ваша роль в нём определяет, что ключу разрешено.
curl https://api.sofia-post.com/api/v1/establishments \
-H "Authorization: Bearer sofia_pk_live_…"OAuth: authorization code с PKCE
Зарегистрируйте клиент в Настройки › API › Клиенты приложений: название, логотип, политика конфиденциальности, разрешения, которые он может запрашивать, и https-адреса перенаправления. У конфиденциального клиента есть секрет; у публичного (мобильное приложение, расширение браузера) его нет, и он опирается только на PKCE.
Отправьте человека на эндпоинт авторизации с PKCE-challenge (S256 обязателен) и state, который вы храните в его сессии:
import { createHash, randomBytes } from 'node:crypto';
const verifier = randomBytes(32).toString('base64url');
const challenge = createHash('sha256').update(verifier).digest('base64url');
const state = randomBytes(16).toString('base64url');
const url = new URL('https://api.sofia-post.com/api/v1/oauth/authorize');
url.search = new URLSearchParams({
response_type: 'code',
client_id: process.env.SOFIA_CLIENT_ID,
redirect_uri: 'https://app.example.com/oauth/callback',
scope: 'establishments:read posts:read posts:write offline_access',
state,
code_challenge: challenge,
code_challenge_method: 'S256',
}).toString();Человек входит в Sofia, видит ваше название, логотип и разрешения, выбирает Workspace и подтверждает. Затем Sofia возвращает его на ваш адрес перенаправления с code, вашим state и издателем iss. Проверьте оба значения и обменяйте code:
curl -X POST https://api.sofia-post.com/api/v1/oauth/token \
-u "$SOFIA_CLIENT_ID:$SOFIA_CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code=$CODE \
-d redirect_uri=https://app.example.com/oauth/callback \
-d code_verifier=$VERIFIER{
"access_token": "sofia_live_at_…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "establishments:read posts:read posts:write offline_access",
"refresh_token": "sofia_live_rt_…"
}- Code действует 5 минут и только один раз. При повторном использовании он отклоняется, а выданные по нему токены перестают работать.
- Access-токен живёт один час и действует только в выбранном человеком Workspace.
refresh_tokenвозвращается, только если вы запросилиoffline_access. Он одноразовый: каждый раз сохраняйте новый. Повторное использование уже использованного refresh-токена отзывает всю авторизацию.
curl -X POST https://api.sofia-post.com/api/v1/oauth/token \
-u "$SOFIA_CLIENT_ID:$SOFIA_CLIENT_SECRET" \
-d grant_type=refresh_token \
-d refresh_token=$REFRESH_TOKENOAuth: client credentials
Конфиденциальный клиент может также действовать в Workspace, которым владеет его владелец, без участия человека. Если у клиента несколько Workspace, укажите нужный через workspace_id.
curl -X POST https://api.sofia-post.com/api/v1/oauth/token \
-u "$SOFIA_CLIENT_ID:$SOFIA_CLIENT_SECRET" \
-d grant_type=client_credentials \
-d workspace_id=$WORKSPACE_IDРазрешения (scopes)
| Scope | Позволяет |
|---|---|
establishments:read | Получать список заведений |
accounts:read, accounts:write | Читать подключённые сети; создавать ссылки для подключения |
media:read, media:write | Читать медиатеку; загружать и импортировать медиа |
posts:read, posts:write | Получать список публикаций и следить за ними; публиковать, изменять и удалять |
insights:read | Читать статистику |
webhooks:read, webhooks:write | Получать список webhook; регистрировать, тестировать и удалять их |
offline_access | Только OAuth: получить refresh-токен |
Вызов без нужного scope отвечает 403 insufficient_scope. Метаданные сервера (RFC 8414) перечисляют все эндпоинты и scopes:
https://api.sofia-post.com/.well-known/oauth-authorization-server/api/v1/oauth