Api Authentication

Authentication and scopes

Every request carries the key as a Bearer token:

Authorization: Bearer bskc_a1b2c3d4_yourSecretHere

Bearer only. There is deliberately no ?api_key= form: query strings end up in server logs, proxy logs and Referer headers, which is not where a credential belongs.

Scopes

Scope Can do Cannot do
read Analytics, stored suggestions, prompt export Change anything, spend AI credit
write Everything above, plus drafts, scheduling, and the AI actions

The AI actions need write even though they feel like reads. They spend your own provider credit, and "my read-only key ran up an Anthropic bill" is a worse surprise than "my read-only key would not rewrite a post". The prompt-export routes, which cost nothing, work fine with a read key.

Response shape

Success:

{"status": "success", "message": "...", "data": {"...": "..."}}

Error:

{"status": "error", "error": "insufficient_scope", "message": "..."}

The error values are stable, so code can branch on them.

Code HTTP Meaning
unauthorized 401 Key missing, malformed, revoked or expired
api_access_required 403 Account is not on the paid plan
insufficient_scope 403 Read-only key used for a write
feature_required 403 Plan lacks a feature the route needs
no_ai_key 403 No Anthropic/OpenAI key configured
confirmation_required 400 Publishing needs {"confirm": true}
bluesky_not_connected 409 No Bluesky credentials stored
scheduled_in_past 409 The requested time has passed
rate_limited 429 Slow down; see Retry-After
bad_request 400 Something in the request is wrong
not_found 404 No such route or resource

Rate limits

Three separate per-key buckets over a sliding one-hour window:

Bucket Limit Covers
general 600 every request
AI 60 the two routes that call an LLM
write 120 routes that change state or call Bluesky

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Window. A 429 also carries Retry-After.

The AI bucket is not a spend cap — your own provider key pays, and your provider has its own limits. It is there to stop an agent stuck in a loop from running up a bill overnight.

GET /me/

The first call anything should make. It reports which account the key drives, what it may do, and what is configured:

{"status": "success", "data": {
  "handle": "alice.bsky.social",
  "timezone": "Europe/Lisbon",
  "scope": "write",
  "features": {"scheduling": true, "api_access": true},
  "ai_key": {"configured": true, "provider": "anthropic", "is_valid": true},
  "rate_limits": {"default": {"limit": 600, "remaining": 598, "window_seconds": 3600}}
}}

timezone matters: it is how a scheduled time without an offset gets interpreted. Read it before scheduling anything.