How to Quote Retweet via Twitter (X) API — Programmatic Guide
Quote-retweeting is the highest-signal engagement action on Twitter (X) — it puts a tweet in your followers' timeline with your own added context, unlike a plain retweet. Programmatic quote-retweets power scheduling tools, editorial workflows, and multi-account content amplification systems.
This guide walks the exact endpoint, the auth requirements (this is a write operation — different from read-only searches), rate-limit pacing that keeps you well below X's thresholds, and runnable Python with error handling.
Quote-retweet vs retweet vs reply
Retweet: shares the original tweet with no added text. In your followers' timeline as the original author + a small 'X retweeted' indicator. Endpoint: POST /twitter/retweet with just tweet_id.
Quote-retweet: shares the original + your added commentary above it. In your followers' timeline as your tweet with the quoted one embedded below. Endpoint: POST /twitter/create_tweet with text + quoted_tweet_url.
Reply: your tweet appears in the thread under the original, not in your followers' timelines by default. Endpoint: POST /twitter/create_tweet with text + in_reply_to_tweet_id.
Quote-retweet is the strongest signal because it (a) shows the original tweet to your followers, (b) adds your context / opinion, (c) increments the quote-retweet counter on the original (visible + attributable).
For programmatic workflows: use retweet for pure amplification, quote-retweet for editorial/opinion amplification, reply for conversation.
Auth — this is a write op
Reads (search / user info / timeline) use X-API-Key header on twitterapi.io — simple.
Writes (create tweet / quote / retweet / delete) require user-context auth — the API needs to know which X account is posting. Two paths:
twitterapi.io login endpoint: exchange login credentials for a session cookie, pass that cookie on subsequent write calls. See platform docs for the current auth flow.
X official OAuth 2.0: standard OAuth authorization code flow, get bearer token with tweet.write scope, use bearer on write calls. Per docs.x.com/x-api/authentication.
For automation-friendly workflows, twitterapi.io's session pattern is typically simpler; for polish integration into an X-official app flow, use OAuth 2.0.
Runnable — quote-retweet with commentary
Single quote-retweet with error handling. Replace SESSION_COOKIE with your authenticated session from the login flow.
import os, requests
BASE = "https://api.twitterapi.io"
SESSION_COOKIE = os.environ["TWITTERAPI_SESSION_COOKIE"] # from login flow
def quote_retweet(quoted_tweet_url: str, commentary: str) -> dict:
if len(commentary) > 280:
raise ValueError(f"commentary too long: {len(commentary)} > 280")
payload = {
"text": commentary,
"quoted_tweet_url": quoted_tweet_url,
}
r = requests.post(
f"{BASE}/twitter/create_tweet",
cookies={"session": SESSION_COOKIE},
json=payload,
timeout=15,
)
r.raise_for_status()
return r.json()
result = quote_retweet(
quoted_tweet_url="https://twitter.com/OpenAI/status/1234567890",
commentary="Interesting — this changes how I'd approach the design tradeoff for large-context workloads.",
)
print(f"quote-retweet posted: id={result.get('id')}")Rate-limit safe bulk pattern
For workflows that quote-retweet many tweets (curation feeds, scheduled amplification), pace under 1 quote per 5 seconds per account to stay well below X's write thresholds. Multi-account distributes further.
Never burst: for x in list: quote_retweet(x) at machine speed will trip X's spam heuristics + suspend the account. Add explicit sleeps + jitter.
# Bulk quote-retweet with pacing + retry.
import os, requests, time, random
BASE = "https://api.twitterapi.io"
SESSION_COOKIE = os.environ["TWITTERAPI_SESSION_COOKIE"]
def quote_retweet(quoted_tweet_url: str, commentary: str, max_retries: int = 3) -> dict:
payload = {"text": commentary, "quoted_tweet_url": quoted_tweet_url}
for attempt in range(max_retries):
try:
r = requests.post(
f"{BASE}/twitter/create_tweet",
cookies={"session": SESSION_COOKIE},
json=payload, timeout=15,
)
if r.status_code == 429: # rate-limited
wait = 60 * (attempt + 1)
print(f" rate-limited, waiting {wait}s")
time.sleep(wait); continue
r.raise_for_status()
return r.json()
except requests.RequestException as e:
print(f" attempt {attempt+1} failed: {e}")
time.sleep(5 * (attempt + 1))
raise RuntimeError("quote-retweet failed after retries")
BATCH = [
("https://twitter.com/a/status/111", "Insightful take on latency budgets."),
("https://twitter.com/b/status/222", "Contrarian view worth reading."),
("https://twitter.com/c/status/333", "This aligns with what we're seeing in production."),
]
for url, text in BATCH:
r = quote_retweet(url, text)
print(f" posted: {r.get('id')}")
time.sleep(5 + random.uniform(0, 3)) # 5-8s pacing per account
# For 100+ tweets/day per account, distribute across multiple accounts.Alternative — X official /2/tweets POST
Same intent, official X endpoint: POST /2/tweets with JSON body { "text": "your commentary", "quote_tweet_id": "1234567890" } per docs.x.com/x-api/posts/manage-posts.
Auth: OAuth 2.0 Authorization Code Flow with PKCE + tweet.write scope.
Rate-limit: per docs.x.com/x-api/rate-limits, POST /2/tweets is 200 requests / 15 min at user-level for Basic tier.
Wins when: you're building a native X integration and need X-issued OAuth tokens. Loses when: you want a simpler session-cookie flow for automation.
Comparison — 2 quote-retweet paths
What can go wrong
Text > 280 chars: X rejects with 400. Client-side length check saves a round-trip.
Quoted URL malformed: must be full https://twitter.com/user/status/N or https://x.com/user/status/N — shortened links won't resolve.
Quoted tweet deleted: post succeeds but the embed shows 'this tweet is unavailable'. Optionally pre-check the tweet exists via /twitter/tweet/info?id=N before posting.
Account suspended for burst posting: pace at 5s+ per action, distribute across multiple accounts for scale.
Duplicate content: X blocks near-identical tweets from the same account. Vary commentary per post.
# Editorial workflow — cure top tweets from a list, quote-retweet with topic-tagged commentary.
import os, requests, time, random
BASE = "https://api.twitterapi.io"
SESSION_COOKIE = os.environ["TWITTERAPI_SESSION_COOKIE"]
HEADERS_READ = {"X-API-Key": os.environ["TWITTERAPI_IO_KEY"]}
def search_top(kw: str, min_faves: int = 500, limit: int = 10) -> list:
r = requests.get(
f"{BASE}/twitter/tweet/advanced_search",
headers=HEADERS_READ,
params={"query": f"{kw} min_faves:{min_faves} -filter:retweets lang:en"},
timeout=15,
)
r.raise_for_status()
return r.json().get("tweets", [])[:limit]
def quote_retweet(url: str, commentary: str) -> dict:
r = requests.post(
f"{BASE}/twitter/create_tweet",
cookies={"session": SESSION_COOKIE},
json={"text": commentary, "quoted_tweet_url": url}, timeout=15,
)
r.raise_for_status()
return r.json()
TOPIC = "LLM evaluation"
COMMENTARY_TEMPLATE = "Sharing this — good {topic} thread worth reading in full."
top_tweets = search_top(TOPIC, min_faves=200, limit=5)
for t in top_tweets:
author = t.get("author", {}).get("userName")
tweet_id = t.get("id")
if not (author and tweet_id): continue
url = f"https://twitter.com/{author}/status/{tweet_id}"
commentary = COMMENTARY_TEMPLATE.format(topic=TOPIC)
result = quote_retweet(url, commentary)
print(f" quoted {author}/{tweet_id} → new tweet {result.get('id')}")
time.sleep(5 + random.uniform(0, 3))
# Cost per twitterapi.io/pricing: search reads at $0.00015/tweet + write ops per pricing pageQuestions readers ask
What's the maximum commentary length on a quote-retweet?
280 characters, same as any tweet. The embedded quoted tweet does not count against your 280 — it's rendered separately.
Can I quote-retweet a protected (locked) account's tweet?
Only if you follow that account AND you're posting from an account that also follows them. Public tweets from public accounts are quote-retweetable by anyone.
Does quote-retweeting notify the original author?
By default yes — the original author gets a notification (unless they've turned off notifications from you or muted your account). Consider this when doing high-volume quote workflows.
Can I delete a quote-retweet later?
Yes — same as any tweet. DELETE /twitter/delete_tweet with your tweet_id (twitterapi.io) or DELETE /2/tweets/:id (X official). Deleting your quote does not delete the original.
How is a quote-retweet counted in engagement metrics?
The original tweet's quote-count increments by 1. Your quote-retweet itself accumulates its own favorite / retweet / reply counts independently. Two separate engagement records.
What happens if I try to quote my own tweet?
Fully supported — self-quotes are common for follow-ups or corrections. No special auth needed beyond the standard write scope on your own account.
Can I schedule quote-retweets?
Both twitterapi.io and X official are immediate-post endpoints. For scheduling, wrap the call in your own cron / job scheduler with a target-time delay. See /blog/twitter-scheduler for scheduling patterns.
Continue
- twitterapi.io — pricing
- X — manage posts (quote_tweet_id field)
- X — rate limits reference
- X — OAuth 2.0 authentication
- Twitter (X) API — cluster hub
- Twitter (X) reply API programmatic tutorial
- Twitter (X) scheduler patterns
- Twitter (X) automation guide
- Twitter (X) API pricing
- twitterapi.io pricing
Stop reading. Start building.
Starter credits cover real testing on real data. Google sign-in, no card, no application queue.
Get an API key