Rate Limits

API quotas by plan, posting velocity caps, and handling 429s.

API Request Limits

Quotas live at the workspace level: every API key, dashboard session, and MCP call in one organization draws from the same bucket. Windows slide, so each request ages out on its own and capacity trickles back continuously instead of unlocking all at once on a minute boundary.

One API key is enough, even when a single integration serves many end customers. Throughput follows the workspace plan, so extra keys buy no speed. Mint more keys to draw boundaries (a key per tenant, a read-only key for a status page), not to go faster.

PlanRequests per Minute
Free60
Pay as you go600

Per-Second Limits For Analytics

Analytics endpoints run on a tighter clock: a 1-second window instead of a minute. Your per-second budget scales off the minute budget:

requests_per_second = max(6, requests_per_minute / 60)

The 6 req/s floor exists for fan-out: a single dashboard render fires a handful of analytics calls at once, and the free tier shouldn't choke on its own overview page.

PlanRequests per MinuteRequests per Second (analytics)
Free606
Pay as you go60010

The per-second window covers:

  • GET /v1/analytics
  • GET /v1/analytics/timeline

Everything else runs on the per-minute budget above.

Rate Limit Headers

Every API response carries these headers:

HeaderDescription
X-RateLimit-LimitBudget for the window behind this endpoint (per-minute, or per-second on analytics routes)
X-RateLimit-RemainingCalls left before the window fills
X-RateLimit-ResetUnix time (seconds) when the oldest in-flight request ages out
Retry-After429 responses only: seconds to sit out before retrying

Handling Rate Limits

Over budget and the API answers 429 Too Many Requests:

{
  "error": "Rate limit exceeded. Please retry after 12 seconds.",
  "code": "RATE_LIMITED",
  "details": {
    "currentCount": 600,
    "limit": 600,
    "retryAfterSeconds": 12
  }
}

Don't fly blind: watch X-RateLimit-Remaining and ease off as it drains. On a 429, sleep for Retry-After, a relative second count that is immune to clock skew between your server and ours. The body repeats the same number as details.retryAfterSeconds. Error shape and codes are covered in Error Handling.

Both SDKs throw on non-2xx. Trap the 429 and ride out the cooldown:

import { ResponseError } from "@onepostly/sdk";

try {
  await posts.createPost({ /* … */ });
} catch (error) {
  if (error instanceof ResponseError && error.response.status === 429) {
    const retryAfter = Number(error.response.headers.get("Retry-After") ?? 60);
    await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
  }
  throw error;
}

Posting Velocity Limits

Separate from API quotas, each connected account has its own publishing speed limit. Platforms throttle (or suspend) accounts that fire too aggressively, so these caps keep every account safely under that line:

LimitValue
Velocity cap25 posts per hour per account
Daily capsInstagram 100, Facebook 100, Threads 250, X 50, Pinterest 25, 50 for every other platform

The budget only counts posts that actually left the building. Queued, scheduled, and never-sent failures don't touch it, so lining up next month's calendar can't trip today's cap.

Publish past the pace and the call fails with a 429 naming the cooldown. Scheduled posts can't answer synchronously, so they fail terminally at fire time instead. Look for VELOCITY_LIMITED on the post.platform.failed webhook.

Analytics Data Freshness

See Analytics Freshness for details.

Tips For Staying Within Limits

  • Remember the budget is shared - Every key, open dashboard tab, and MCP session in the workspace draws from the same bucket. Splitting traffic across keys buys zero headroom.
  • Page through lists - Never pull everything at once. Use limit with the list endpoint's paging parameter.
  • Cache aggressively - Keep a local copy of slow-moving data instead of re-fetching it.
  • Subscribe instead of polling - Webhooks tell you when a post publishes or fails. Polling burns quota for no reason.
  • Batch destinations into one post - One POST /v1/posts with several destinations costs a single API call. Velocity is still counted per destination.