Authentication

Get an API key

Every call carries a Bearer token in the Authorization header. Sofia reads the rights behind it on each call: a person removed from a Workspace, or a revoked authorization, stops the token at the next request.

MethodForToken
Personal keyAutomating your own account, scripts, agentssofia_pk_live_…, valid until its expiry
OAuth, authorization code + PKCEA product that acts for its users, on the Workspace each one choosessofia_live_at_…, one hour, renewable
OAuth, client credentialsA server of yours that automates a Workspace you ownsofia_live_at_…, one hour

Personal keys

Create a key in Settings › API › Personal access. It acts for you on all your Workspaces: the establishment you name sets the Workspace, and your role there decides what the key may do.

bash
curl https://api.sofia-post.com/api/v1/establishments \
  -H "Authorization: Bearer sofia_pk_live_…"

OAuth: authorization code with PKCE

Register a client in Settings › API › App clients: its name, logo, privacy policy, the permissions it may ask for, and its https redirect URLs. A confidential client has a secret; a public client (mobile app, browser extension) has none and relies on PKCE alone.

Send the person to the authorization endpoint with a PKCE challenge (S256 is mandatory) and a state you keep in their session:

javascript
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();

The person signs in to Sofia, sees your name, logo and permissions, chooses a Workspace and accepts. Sofia then sends them back to your redirect URL with a code, your state and the issuer iss. Check both, then exchange the code:

bash
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
json
{
  "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_…"
}
  • The code is valid for 5 minutes, once. Replayed, it is refused and the tokens it gave stop working.
  • The access token lasts one hour and acts on the Workspace the person chose only.
  • A refresh_token is returned only when you asked for offline_access. It is single-use: keep the new one each time. Replaying a used refresh token revokes the whole authorization.
bash
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_TOKEN

OAuth: client credentials

A confidential client can also act on a Workspace its owner owns, without a person in the loop. When the client holds several Workspaces, name one with workspace_id.

bash
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

Permissions (scopes)

ScopeAllows
establishments:readList establishments
accounts:read, accounts:writeRead connected networks; create connection links
media:read, media:writeRead the media library; upload and import media
posts:read, posts:writeList and follow posts; publish, edit and delete them
insights:readRead statistics
webhooks:read, webhooks:writeList webhooks; register, test and delete them
offline_accessOAuth only: receive a refresh token

A call without the needed scope answers 403 insufficient_scope. The server metadata (RFC 8414) lists every endpoint and scope:

text
https://api.sofia-post.com/.well-known/oauth-authorization-server/api/v1/oauth