Search

Search the docs…

API

Errors & limits

Errors are plain JSON with a human-readable English message, the same text an AI sees over MCP, so it can explain or fix the problem by itself.

Error format

400 Bad Request
{
  "error": "That time has already passed",
  "code": "date_past",
  "hint": "Pick a future time in the project's local time (see now in list_projects)."
}

Every error has a stable code (snake_case) to branch on, and some add links. Messages can change; codes don't.

402 Payment Required
{
  "error": "The user's Postika subscription is not active (canceled), so this connection can't read or schedule anything in the project \"Acme\". Tell the user to activate it at https://postika.app/billing; it works again right away, without reconnecting.",
  "code": "subscription_inactive",
  "billing_url": "https://postika.app/billing",
  "project_id": "3f6a1d2e-…",
  "subscription_status": "canceled"
}

Validation errors also list the fields that failed:

400 Bad Request
{
  "error": "Invalid data",
  "issues": [
    {
      "path": "when",
      "message": "Format \"YYYY-MM-DD HH:MM\""
    },
    {
      "path": "channel_ids",
      "message": "Too small: expected array to have >=1 items"
    }
  ]
}

Status codes

StatusWhen
200Success. The result is in data.
400Invalid data, or the request breaks a rule (past date, too long for a network, unknown channel…).
401Missing, unknown or expired credential. Includes a WWW-Authenticate header pointing to the OAuth metadata.
402The subscription of the project's owner isn't active (subscription_inactive). Checked per project on every request; /projects and /account still answer.
403The role doesn't allow it, e.g. an editor approving (approval_forbidden).
404The account has no projects yet (no_projects).
409The project has no channels (no_channels) or a channel needs reconnecting (channel_disconnected).
429Rate limit exceeded.
500Something went wrong on our side. Safe to retry.

Error messages

StatusMessageFix
401Missing API key (Authorization: Bearer ptk_…)Send Authorization: Bearer ptk_… (or ptat_…).
401Invalid API keyThe key was deleted, or the access token expired: refresh it.
402…subscription is not active… (subscription_inactive)Activate it at /billing, or ask the project owner.
429Too many requests: wait a minuteWait Retry-After seconds.
400Pass the project (project_id): you have several. Use list_projects to see them.Pass project_id.
400That project doesn't exist or you don't have accessCheck the ID with GET /projects.
400Pick at least one channelSend at least one channel_id.
400A channel doesn't exist in this projectUse IDs from GET /channels of the same project.
400Pick a date and timeSend when for schedule and approval.
400That time has already passedPick a future time (project local time).
400X: maximum 280 characters (you have 312)Shorten it, or choose another channel.
400Instagram needs a photo or videoSend media_urls with a public https link to the photo or video.
400media_urls[0] (host) can't be used: … (media_fetch_failed)Use a public https link straight to a JPG, PNG, WebP, GIF, MP4 or MOV.
400The post no longer existsThe post was already deleted.
400It's being published right nowTry again in a few seconds.
500Something went wrong. Please try again.Retry with backoff.

OAuth errors

The OAuth endpoints follow RFC 6749 and return { error, error_description }.

ErrorStatusMeaning
invalid_request400code, code_verifier or refresh_token missing.
invalid_request400client_id missing (it is always required).
invalid_grant400Code expired or used, PKCE failed, redirect_uri or client mismatch, refresh token expired, already used or issued to another client.
invalid_target400resource isn't this MCP server's URL (RFC 8707).
invalid_client401Unknown client_id, or wrong or missing client secret for an app with a secret.
unsupported_grant_type400Only authorization_code and refresh_token are supported.
invalid_redirect_uri400Registration: 1 to 5 redirect URIs, each https, loopback or an app scheme.
invalid_client_metadata400Registration: unsupported grant or response types, or metadata too large.
temporarily_unavailable429Registration limit reached (20 per IP per hour). Retry later.

MCP errors

Only authentication (401, with WWW-Authenticate) and rate limiting (429) are HTTP errors, as a JSON-RPC error with code -32001. Everything else, including an inactive subscription, is a tool result with isError: true and the text Error (<code>): <message>, so the AI can read it, tell the user what to do and correct itself. initialize and tools/list always succeed.

{
  "content": [
    {
      "type": "text",
      "text": "Error (too_long): X: maximum 280 characters (you have 312). Shorten the text, or create a separate post for this channel."
    }
  ],
  "isError": true
}

Rate limits

120 requests per minute for each API key or OAuth access token, counted per clock minute (and 60 per IP for requests without a valid credential). REST and MCP requests share the same budget. Requests over the limit get 429 until the minute rolls over.

Every 429 response carries a Retry-After header with the seconds left until the next minute (1 to 60). Wait that long before retrying; the header is exposed to browsers through CORS.

429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 23
Content-Type: application/json

{ "error": "Too many requests: wait a minute" }
Batch work in one MCP conversation or one script run instead of polling. To follow the calendar, call GET /posts once with a wider days range.

Limits

LimitValue
Post content1 – 5000 chars
Channels per post≥ 1
days in GET /posts1 – 62
API keys per project20
OAuth apps per user20
Redirect URIs per client5 (registration) · 10 (Developers apps)
media_urls per post10 · photos 15 MB · videos 100 MB
MCP request body1 MB
Requests without a valid credential60 / minute / IP
Access token1 hour
Refresh token60 days
Authorization code5 minutes

Network limits

Checked when a post is scheduled, published or approved. The tightest channel in a post decides.

NetworkCharactersMedia
Instagram2,200Photo or video required
TikTok2,200Photo or video required
Facebook63,206Optional
YouTube5,000Video required
X280Optional
LinkedIn3,000Optional
Threads500Optional
Pinterest500Photo or video required