Skip to main content

Rate Limits & Polling Best Practices

Upload-Post applies rate limits at multiple levels to protect the service and the social media platforms. This guide explains each limit and how to design your integration to work within them.

API Rate Limits​

Every authenticated API response includes rate limit headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets

When you exceed the limit, the API returns HTTP 429 Too Many Requests. Wait until the X-RateLimit-Reset timestamp before retrying.

Limits per plan​

The per-minute window depends on your plan, and grows with the number of profiles on the account (+2 requests/min and +10 requests/10 min per profile), so multi-brand accounts are not capped like a single-profile one:

PlanRequests / minuteRequests / 10 minutes
Free60300
Basic60300
Professional100500
Advanced2001,000
Business5002,500

Example: an Advanced account with 100 profiles gets 200 + 100 × 2 = 400 requests/min. Hard ceiling: 1,000 requests/min and 5,000 requests/10 min. Requests made from the dashboard (web session) use a separate, higher allowance.

The exact limit that applies to your key is always in the X-RateLimit-Limit header of every response. The first request after a long idle period may report the Free/Basic tier while the API resolves your plan; the following requests apply your tier.

Upload Status Polling​

When using async_upload=true, you need to poll the Upload Status endpoint to get the result. Here are the recommended intervals:

Polling Strategy​

1. Submit upload → get request_id
2. Wait 5 seconds (initial delay)
3. Poll GET /api/uploadposts/status?request_id=<ID>
4. If status is "pending", "queued", or "processing" → wait 10 seconds → repeat step 3
5. If status is "completed" or "failed" → done
ScenarioPoll IntervalMax Wait
Photo uploadsEvery 5–10 seconds2 minutes
Video uploads (small, < 50 MB)Every 10 seconds5 minutes
Video uploads (large, > 50 MB)Every 15 seconds10 minutes
Scheduled posts (after scheduled time)Every 30 seconds10 minutes
Queued postsEvery 60 secondsUntil next queue slot

Status Cache TTLs​

The status endpoint uses internal caching. Here is how often the status value is refreshed:

StatusCache TTLMeaning
queued2 secondsThe upload is waiting for a worker
pending2 secondsAccepted but not yet started
processing3 secondsAt least one platform is actively uploading
completed5 minutesAll platforms finished successfully
failed5 minutesAll platforms failed

Key takeaway: Polling faster than every 5 seconds for non-terminal states is unnecessary — the cache refreshes every 2–3 seconds. For terminal states (completed/failed), the result is cached for 5 minutes, so subsequent polls are fast.

Read Caches (comments and post analytics)​

Other read endpoints that would otherwise call the social platform on every request are cached per account and query string. Only successful responses are cached:

EndpointCache TTLNotes
GET /api/uploadposts/comments60 secondsCleared when the same account creates, deletes or moderates a comment through Upload-Post, so your own writes show up at once. On X, the mentions page behind it is also kept 120 seconds per X account.
GET /api/uploadposts/post-analytics?platform_post_id=5 minutesX posts older than 7 days are refreshed from X at most once a week.

Polling these faster than their TTL returns the same response and only spends your rate limit.

Alternative: Use Webhooks​

Instead of polling, configure a webhook to receive a POST notification when the upload completes. This is more efficient for high-volume integrations:

{
"channels": { "webhook": true },
"webhook_url": "https://your-server.com/webhook"
}

The webhook fires once per platform per upload, so you get immediate notification without polling.

Upload Rate Limits​

Per-Request Duplicate Protection​

The API prevents duplicate uploads using idempotency keys and rate limiting:

  • Same content to same platform: If you submit an identical upload (same user, platform, and content hash) within a short window, the API returns the existing request instead of creating a duplicate.
  • Idempotency-Key header: Send a unique Idempotency-Key or X-Idempotency-Key header to ensure exactly-once processing, even across retries.
    • The key is scoped to your account and the upload type (video, photo or text) and lasts 24 hours from the first request.
    • Resending the same key returns the original job (idempotent_replay), even if the body changed.
    • If two requests with the same key arrive at the same time, only one creates the upload. The other waits briefly for it and, if the first request is still being processed, gets 409 with code IDEMPOTENCY_KEY_IN_USE. Retry it after a few seconds and it returns the original job.

Daily Upload Caps (per platform per account)​

Each social account has a daily hard cap based on platform limits. Exceeding these returns HTTP 429:

PlatformMax posts / 24h
Instagram50
TikTok15
LinkedIn150
YouTube30
Facebook25
X (Twitter)Per plan: Free/Basic 10 · Professional 20 · Advanced/Business 30
Threads50
Pinterest20
Redditunavailable (reddit_unavailable)
Bluesky25 videos / 10 GB (video quota)

These are rolling 24-hour windows per social account, not per API key.

Pending Scheduled Posts​

Each account can keep a limited number of scheduled posts waiting to be published: Free 5,000 · Basic 20,000 · Professional 30,000 · Advanced 40,000 · Business 50,000. When the limit is reached, uploads with scheduled_date (or add_to_queue) and job_id retries with a future date return HTTP 429 with error_code: "SCHEDULED_POSTS_LIMIT", pending_scheduled_posts and max_pending_scheduled_posts. Only posts due more than 15 minutes ahead count; immediate uploads are never refused by it. Retrying does not help until some posts publish or you cancel the ones you no longer need. See Pending Scheduled Posts Limit.

X Replies, Edits and Reposts​

Writes to X outside of uploads — replies with comments/create, posts/edit and posts/repost — share one counter per X account and UTC day:

PlanReplies + edits + reposts per X account / day
Free20
Paid plans200

Over the cap they return HTTP 429 with error_code: "x_daily_write_limit", limit, retry_after and a Retry-After header (seconds until 00:00 UTC). A write that X refuses is not counted. This counter is separate from the upload caps above: replying a lot never blocks your scheduled posts.

Reading X post analytics by tweet ID also has a daily budget (5,000 distinct X posts per account per UTC day; 429 daily_limit). See Post analytics by platform ID.

Monthly API Usage​

Your plan determines how many API upload calls you can make per month:

PlanMonthly uploads
Free10
Paid plansSee pricing

Check your current usage with GET /api/uploadposts/me — the response includes api_usage.count.

API Key Brute-Force Protection​

Failed authentication attempts (invalid API keys) are rate-limited per IP:

  • After 10 consecutive failed attempts with the same invalid key, the IP is blocked for 5 minutes.
  • The API returns HTTP 429 during the block period.

Best Practices​

  1. Use webhooks instead of polling when possible — they're instant and don't consume rate limit budget.
  2. Respect X-RateLimit-Remaining — stop sending requests when it reaches 0.
  3. Use exponential backoff on 429 responses — don't hammer the API after hitting a limit.
  4. Set async_upload=true for all uploads — synchronous uploads timeout after 59 seconds anyway.
  5. Send Idempotency-Key for all upload requests — this protects you from duplicate posts if your HTTP client retries on timeout.
  6. Poll at the recommended intervals — faster polling just returns cached results and wastes your rate limit budget.