API keys, the x-access-key header, credits and rate limits.
Every request (except GET /v1/health) needs an API key in the x-access-key header:
curl -s https://api.betterpost.dev/v1/profiles \
-H "x-access-key: $BETTERPOST_API_KEY"sk_test_ plus 32 random letters and digits. It is shown once at creation; BetterPost stores only its
SHA-256 hash, so a lost key cannot be recovered. Create a new one and revoke the old one.sk_test_) for now. See Sandbox mode.| Situation | Status | code |
|---|---|---|
| Header missing or key unknown | 401 | unauthorized |
| Key has been revoked | 403 | key_revoked |
{ "success": false, "message": "Invalid or missing access key", "code": "unauthorized" }Use GET /v1/health/auth to check a key without side effects.
Publishing costs credits; everything else is free (reads, lists, drafts, connecting accounts, profiles, media, webhooks).
| Target | Credits |
|---|---|
| LinkedIn, Instagram or Facebook | 1 |
| X (Twitter) | 5 |
X (Twitter) when any tweet text in the target contains http:// or https:// | 50 |
platforms[]), once, when the post is accepted:
publish-now, scheduled, or a draft being published or scheduled. A scheduled post reserves its credits up front,
so it can never fail later for lack of credits.content (or the target's own content) and each
platformSpecificData.threadItems[].content.When a request needs more credits than you have, nothing is created and the API returns 402:
{ "success": false, "message": "Not enough credits: need 50, have 20", "code": "insufficient_credits" }Check your balance and history with GET /v1/usage. Sandbox posts are charged exactly like
production posts so your cost estimates hold when real publishing launches.
Each project can make 120 requests per minute (REST and MCP combined). Above that the API returns 429 with a
Retry-After header (seconds):
{ "success": false, "message": "Rate limit exceeded: 120 requests per minute", "code": "rate_limited" }JSON bodies are limited to 1 MB. Larger bodies get 413 payload_too_large. Upload media files with
presigned uploads instead of embedding them.