Authentication

Every request to the PostFuze API is authenticated with an API key, sent as a bearer token. A key belongs to a single org and scopes every read and write to that org's data. There is no other credential — no OAuth tokens, no session cookies — on the developer API.

API keys

PostFuze keys are prefixed so you can tell at a glance which environment they target:

PrefixModeUse for
sk_live_…liveProduction traffic that publishes real content.
sk_test_…testDevelopment and testing. Test keys can create drafts but cannot schedule or publish real content.

The prefix is functional, not cosmetic: the API-key middleware derives the request mode (live or test) from it, and the posts API blocks test keys from queueing or scheduling real publishes. Anything that does not start with Bearer sk_ is rejected before any lookup.

Scopes

API-key scopes are enforced on write operations. A key with no scopes can still read resources in its own organization, but cannot create, update, delete, connect, publish, or otherwise mutate data. Grant * for full access, or grant the specific write scopes used by the route, such as posts:write, media:write, accounts:write, webhooks:write, team:write, profiles:write, and scheduling:write.

The Authorization header

Send your key on every request as a bearer token:

Authorization header
Authorization: Bearer sk_live_…
curl
curl https://api.postfuze.com/api/v1/social-accounts \
  -H "Authorization: Bearer sk_live_…"

The only unauthenticated routes are the health check (GET /health) and the OAuth callback / page-selection flow under /connect and /social-accounts/pending, which are authenticated by signed state and session tokens instead. Everything else requires a valid key.

Failure responses

Missing, malformed, revoked or expired keys return 401 Unauthorizedas an RFC 9457 problem document:

401 Unauthorized
{
  "type": "about:blank",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Invalid or expired API key."
}

If no bearer token is present at all, detail reads "Provide your API key as a Bearer token." instead.

Creating, rotating and revoking keys

API keys are managed in the dashboard at /app — there is no API endpoint that mints keys, by design (a leaked key cannot mint more keys).

Create

Generate a key from the dashboard and copy it immediately. The full key is shown exactly once; PostFuze keeps only a hash, so it can never be displayed again. You may set an optional expiry at creation time.

Rotate

To rotate a key without downtime:

  1. Create a new key in the dashboard.
  2. Deploy it to your services and confirm traffic is flowing on the new key.
  3. Revoke the old key once it shows no recent usage.

Each key records a last_used_attimestamp (written lazily, at most once per minute, so reads don't amplify into writes) — use it to confirm an old key is idle before you revoke it.

Revoke

Revoking a key takes effect immediately on the next request. The middleware only matches keys whose revoked_at is null and whose expires_at is either unset or in the future, so a revoked or expired key fails closed with a 401.

Connecting end-user accounts

Your API key authenticates you. To publish on behalf of your customers, each of them connects their own social account through PostFuze's hosted BYOK OAuth flow. Your backend requests an auth URL, redirects the customer to the platform, and PostFuze exchanges the code and stores the encrypted token at its /connect/callback — your key never leaves your server and you never handle the platform tokens. See Backend integration for the full request reference.

1
Your app → PostFuze
Request an auth URL for the platform
POST /social-networks/{platform}/auth-url with your API key and the customer's tenant_id. PostFuze returns an auth_url carrying signed state.
2
Your app → Customer
Redirect the customer to the auth URL
They review and approve the requested scopes on the platform.
3
Platform → PostFuze
Platform calls PostFuze’s callback
PostFuze exchanges the code for access + refresh tokens, encrypts them, and stores the social account.
4
PostFuze → Customer → your app
Customer is bounced back to your redirect_uri
The redirect includes status=connected and an account_id — persist it to use in accounts[] when publishing.

Security

  • Hashed at rest. PostFuze never stores your raw key. Incoming keys are hashed and compared against the stored key_hash, so a database compromise does not leak usable credentials.
  • Server-side only. Treat keys like passwords. Never embed a key in client-side code, a mobile app, or a public repository. Call PostFuze from your backend — see Backend integration.
  • Scoped to one org.A key can only read and write its own org's data; tenant isolation is enforced at the database layer by row-level security, independent of application code.
  • Optionally scoped to one profile.When you create a key you can pin it to a single profile (a brand/client “profile group”). A scoped key can only read and write that profile's accounts, posts, and media — and connecting an account with it lands the account in that profile — while it cannot manage profiles or the org's OAuth apps. Leave it unscoped for an org-wide key.
  • Expiry and revocation fail closed. Both revocation and expiry are checked on every request; there is no grace window.
  • Rotate on suspicion. If a key may have leaked, create a replacement and revoke the old one. There is no penalty for holding multiple active keys.

Next steps

  • Quickstart — your first connected account and published post.
  • Backend integration — where to store keys and account IDs.
  • Webhooks — verify signed deliveries with a per-endpoint secret.