Rate limits
OpenTweet enforces two kinds of limit on the REST API and MCP server: how many requests you can send per minute, and how many posts you can publish per day. Both scale with your plan. Go over either and the API returns HTTP 429.
Requests per minute
Every authenticated request to https://opentweet.io/api/v1 counts toward a per-minute budget tied to your subscription.
| Plan | Requests per minute | Posts per day |
|---|---|---|
| Pro | 60 | 20 |
| Advanced | 300 | 100 |
| Agency | 600 | 300 |
Need more headroom? Compare plans on the pricing page.
Daily post limits
Separately from the per-minute budget, there is a cap on how many posts publish per day. Pro allows 20 per day, Advanced 100 per day, and Agency 300 per day (see the table above). A thread counts toward this limit, and both immediate posts (publish_now) and scheduled posts (scheduled_date) count.
HTTP 429 Too Many Requests
When you exceed either limit, the API responds with status 429 Too Many Requests and a JSON body:
{
"error": "Too many requests. Slow down and retry with backoff.",
"code": "rate_limit_exceeded"
}Slow down, then retry
A 429 is temporary. Stop sending requests for a moment, then retry the same request. Do not hammer the endpoint, which only extends how long you stay rate limited.Handle 429 with exponential backoff
The right way to handle a 429 is exponential backoff: wait, retry, and double the wait each time you get another 429. Retry only 429 and 5xx responses. Permanent 4xx errors like 400 or 401 will never succeed on retry, so fix the request instead.
import time
import requests
def post_with_backoff(payload, key, max_retries=5):
url = "https://opentweet.io/api/v1/posts"
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
delay = 1.0
for attempt in range(max_retries):
resp = requests.post(url, json=payload, headers=headers)
if resp.status_code < 400:
return resp.json()
# Only retry 429 and 5xx. Fix 4xx and do not retry.
if resp.status_code == 429 or resp.status_code >= 500:
time.sleep(delay)
delay *= 2 # exponential backoff: 1s, 2s, 4s, 8s, 16s
continue
raise RuntimeError(resp.json())
raise RuntimeError("Gave up after retries")No custom rate-limit headers
OpenTweet does not return custom rate-limit headers. Drive your backoff off the HTTP status code: treat any 429 as the signal to wait and retry.Related
- • Errors reference: every status code and machine-readable error code.
- • REST API reference: endpoints, request bodies, and responses.
- • Pricing: per-minute and daily limits by plan.