Authentication & permissions
The REST API accepts one kind of credential: a long-lived Bearer credential issued by a workspace admin in Settings. It acts for the whole workspace and its permissions are fixed at issue time — scopes decide which endpoints you may call, publish tiers decide how far a post may go.
Sending the credential
Authorization: Bearer popkit_it_••••••••Send this header on every request. Credentials start with popkit_it_; a missing, malformed, disabled or expired one returns 401 (unauthenticated) with WWW-Authenticate: Bearer realm="popkit-api". Never put the credential in front-end code, public repositories or URLs.
Issuing, expiry and revocation
- Where: popkit → Settings → Integrations → Long-lived credentials. Only workspace admins can issue; in a personal space, the owner.
- At issue time you choose: name, scopes, publish tiers, expiry (indefinite or N days). The key is shown exactly once; only a hash is stored, so a lost key must be revoked and re-issued.
- Revoking / disabling takes effect immediately: every request re-validates against the database, so the next call gets 401. Credentials with an expiry remind admins 7 days / 1 day before.
- A credential is attributed to its issuer: if they leave the workspace, are removed or banned, the credential stops working (
workspace_not_found). - Audit: every write made through a credential (publish, schedule, reschedule, reply, submit) is logged in the workspace audit as "via integration <name>", with a per-credential invocation log.
Scopes and endpoints
Missing the scope an endpoint requires returns 403 (forbidden, params.scope names it). The issuer's workspace role must also allow the action — scopes can only narrow, never exceed the role matrix.
| scope | Meaning | Endpoints |
|---|---|---|
| workspace:read | Workspace info, member count, quota left | GET /workspace |
| accounts:read | Connected social accounts and their auth status | GET /accounts |
| posts:read | Drafts, schedules, publish history | GET /posts、GET /posts/{postId}、POST /posts/precheck |
| posts:write | Create / edit drafts, upload media | POST /posts、PATCH /posts/{postId}、POST /posts/{postId}/reschedule、POST /posts/{postId}/cover-suggestions、POST /posts/{postId}/cover、POST /media |
| approvals:write | Submit drafts for approval | POST /posts/{postId}/submit |
| schedule:write | Schedule posts | POST /posts、PATCH /posts/{postId}、POST /posts/{postId}/reschedule、POST /posts/{postId}/publish |
| publish:execute | Publish immediately | POST /posts、PATCH /posts/{postId}、POST /posts/{postId}/confirm、POST /posts/{postId}/publish |
| comments:read | Read comments on published posts | GET /comments |
| comments:write | Reply to comments as the workspace's accounts | POST /comments/{commentId}/replies |
| analytics:read | Metrics and trends | GET /analytics/summary |
| ideas:read | Read the idea board | GET /ideas |
| ideas:write | Write ideas to the board | POST /ideas、PATCH /ideas/{ideaId} |
Publish tiers
Post-writing endpoints choose a tier with action: draft, schedule, or publish now. Tiers are ticked per credential at issue time and none is granted by default; asking for a tier that is not on the allow-list returns 403 (params.action).
| Tier | Scope needed | Meaning & guardrails |
|---|---|---|
| draft | posts:write | Saves a draft; prechecks only warn. |
| schedule | schedule:write | Sent by the scheduler when due; monthly quota and hard prechecks apply. |
| publish | publish:execute | Sends now; hard prechecks, rate caps and a per-credential daily cap (default 20/day, adjustable per credential). |
Long-lived credentials default to pre-authorised mode (unattended: action: "publish" goes out in one call). If a credential is set to two-step confirmation, create / update returns a draft plus confirm.token, and only confirm publish within ten minutes actually sends. Check for the confirm field in the response.
Security notes
- One credential per system, least-privilege scopes; a reporting script should not hold a publish-capable key.
- Keep it in a secret manager / environment variable; when rotating, issue the new one before disabling the old.
- Always send
Idempotency-Keyon writes so network retries never turn into duplicate posts. needs_reauth/no_accountmean a person must act on the account; do not retry in a loop.