Authentication
API keys, scopes, and workspace binding.
Every request to the FoPost API carries an API key in the X-API-Key header.
curl https://api.fopost.com/v1/accounts \
-H "X-API-Key: $FOPOST_API_KEY"There is no Authorization: Bearer path for API keys. A bearer token is either a session token the dashboard issues to itself, or an OAuth access token a third-party app obtained from a user (see OAuth for third-party apps below). Your own integration uses an API key.
Creating a key
Open fopost.com/dashboard and go to Settings → API Keys. When you create a key you choose two things:
- Scopes, which decide what the key may touch
- A workspace, optionally, which confines the key to that workspace
The key is shown once, at creation. It is stored hashed, so nobody, including us, can read it back. Lost a key, regenerate it.
Scopes
A key can only reach endpoints covered by the scopes you gave it. Ask for the narrowest set that does the job.
| Scope | Covers |
|---|---|
posts | Read and write posts, media, and content blocks |
publish | Publish, retry, and cancel a post; launch, boost, pause, or delete an ad |
deliveries | Per-account delivery results for a post |
accounts | Connected social accounts and their health |
workspaces | List and manage workspaces |
labels | Labels used to organise posts |
analytics | Post, account, and workspace metrics |
automations | Automation rules and their run history |
webhooks | Webhook endpoints and test deliveries |
inbox | Comments, mentions, and messages across connected accounts |
ads | Meta ads, audiences, and lead forms. Spending money also needs publish |
ai | AI captions and the credit balance. Spends credits, so it is never bundled into another scope |
extension | Reserved for the browser extension |
Call an endpoint outside your scopes and you get 403 with error: "insufficient_scope". Each endpoint in this reference names the scope it needs.
Workspace-bound keys
A key created against a single workspace is confined to it. Naming any other workspace returns 403, and list endpoints return only that workspace's rows, whether or not you pass workspace_id. A key created without a workspace can reach every workspace on the account.
Bind the key when an integration only ever serves one brand or client. It turns a scoping mistake in your own code into a 403 instead of a cross-client post.
Rotating and revoking
Keys can be regenerated or deleted at any time from the same screen, and both take effect immediately. Use separate keys per environment so rotating production does not break your staging job.
Errors
| Status | error | Cause |
|---|---|---|
| 401 | unauthorized | Header missing, or the key does not match |
| 403 | insufficient_scope | Key is valid but lacks the scope |
| 403 | forbidden | Resource belongs to a workspace the key cannot reach |
| 402 | subscription_required | The account behind the key has no active plan |
OAuth for third-party apps
Building something other FoPost customers install? Do not ask them for an API key. Register an OAuth client and let each user approve your app on a consent screen, where they pick one workspace and see exactly which scopes you asked for. You get an access token confined to that workspace and those scopes, and the user can cut you off at any time from Settings → Connected Apps.
The server follows OAuth 2.1: authorization code flow only, PKCE with S256 on every request, exact redirect_uri matching, and refresh tokens that rotate on use. Everything is discoverable at https://api.fopost.com/.well-known/oauth-authorization-server.
1. Register a client
Registration needs your own FoPost account: send your API key (any key with the workspaces scope). The client belongs to your account.
curl -X POST https://api.fopost.com/oauth/register \
-H "X-API-Key: $FOPOST_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_name": "Acme Scheduler",
"client_uri": "https://acme.example",
"redirect_uris": ["https://app.acme.example/oauth/callback"]
}'The response carries your client_id. client_uri is your site, and every redirect URI must be https on that host or a subdomain of it, matched character for character; loopback http://localhost is allowed for native and local clients. The client name may not use the product name, since users see it on the consent screen. Leave token_endpoint_auth_method at its default of none for a browser, mobile or desktop app; a server-side app may set it to client_secret_basic or client_secret_post to receive a client_secret, shown once.
2. Send the user to authorize
Generate a random code_verifier (43 to 128 characters), derive code_challenge = BASE64URL(SHA256(code_verifier)), and open:
https://api.fopost.com/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://acme.example/oauth/callback
&scope=posts%20accounts
&state=RANDOM_STATE
&code_challenge=CHALLENGE
&code_challenge_method=S256scope is a space-separated list using the same names as API-key scopes above. The user signs in if needed, picks a workspace and approves. The browser comes back to your redirect_uri with code and state, or with error=access_denied if they declined. Always check state.
3. Exchange the code
curl -X POST https://api.fopost.com/oauth/token \
-d grant_type=authorization_code \
-d client_id=YOUR_CLIENT_ID \
-d code=CODE_FROM_CALLBACK \
-d redirect_uri=https://acme.example/oauth/callback \
-d code_verifier=VERIFIER{
"access_token": "oa_...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "or_...",
"scope": "posts accounts"
}A code is single-use and expires after ten minutes. A wrong code_verifier, a reused code or a different redirect_uri all answer 400 with error: "invalid_grant".
4. Call the API
curl https://api.fopost.com/v1/posts \
-H "Authorization: Bearer oa_..."The token behaves like a workspace-bound API key: it reaches only the workspace the user approved, list endpoints return only that workspace's rows, and naming any other workspace answers 403. An endpoint outside the granted scopes answers 403. A revoked or expired token answers 401.
5. Refresh and revoke
Access tokens last an hour. Refresh with grant_type=refresh_token; the response carries a new access token and a new refresh token, and the old refresh token stops working. Refresh tokens last thirty days from their last rotation.
curl -X POST https://api.fopost.com/oauth/token \
-d grant_type=refresh_token \
-d client_id=YOUR_CLIENT_ID \
-d refresh_token=or_...To disconnect, send either token to /oauth/revoke with your client_id; the whole grant is revoked and the endpoint answers 200 either way. The user can do the same from Settings → Connected Apps.
Keeping a key safe
- Keep it server side. A key in browser or mobile code is public the moment you ship it
- Read it from an environment variable or a secrets manager, never from source control
- One key per integration, so you can revoke one thing without breaking the rest
Related documentation
- API Overview
Base URL, envelopes, pagination, and errors for the FoPost REST API.
- Publishing
Create a post, target accounts, publish it, and read the per-account result.
- Scheduling
Schedule a post, repeat it, and import a batch from a spreadsheet.
- Media
Upload files, list the media library, and attach media to a post.
- Validation
Check content, text length, and media against platform rules before a post exists.
- Accounts
List connected social accounts, check their health, and refresh credentials.
- Workspaces
Workspaces, labels, and how isolation works across them.
- Analytics
Overview totals, time series, top posts, demographics, and label roll-ups.