Trim any response with fields and compact
Every GET endpoint accepts ?fields=a,b.c and ?compact=1 to return only the fields you name. Cuts a tweet page by 70 to 90 percent for LLM tool callers, with pagination and error envelopes always kept. cURL and Python samples plus the exact projection rules.
Every read endpoint returns full tweet and user objects: a tweet with its author profile is about 2 to 3 KB, and a page of 20 with quoted tweets runs 60 to 100 KB. An agent that feeds that page into a model pays for every byte. Two query parameters, accepted on every GET, let you say which fields you want so one page fits a tool budget.
The two parameters
| parameter | what it does |
|---|---|
fields=a,b.c | keep only the named dotted paths, at every depth the path names |
compact=1 | a built-in preset: ids, text, timestamps, counts, flags and the author's identity |
Both can be combined: compact=1&fields=entities.hashtags is the preset plus one more path. Neither changes the status code, the count, or what you are billed: the projection runs on the already-shaped response after billing and logging.
Rules
- A path applies to every object in a returned list (
tweets[],users[],items[]) and to nested objects.author.usernamekeeps onlyusernameinside eachauthor. - A path prefix that lands on an array applies to each element:
media.media_url_httpskeeps one field per media entry. - Naming an object as a whole keeps it whole:
fields=authorreturns the full author. - These envelope keys always survive:
next_cursor,cursor,has_more,count,partial,error,message,reason. A projected page still pages, and an error still reads as an error. - Unknown paths are ignored, never rejected, so a typo cannot turn a working call into a 400. Send
fieldsonce, comma-separated; a repeated parameter keeps the first value. - A path may start with the list's own name or not:
fields=tweets.idandfields=idmean the same on a tweets page. compact=1trims what the preset recognises and leaves alone what it would empty, so it never turns a body into{}; with explicitfieldsyou get exactly what you named.- Applies to data reads only. Control-plane GETs (account, feedback, session status, monitor other than deliveries, webhook, the stream-compat shim) return their bodies unchanged, and writes are never projected. Up to 50 paths of up to 6 segments each,
[A-Za-z0-9_]per segment. - Single-object responses (
tweet/detailreturns{ "tweet": {...} }) are projected through the nested object:fields=id,textgives{ "tweet": { "id": ..., "text": ... } }.
The compact preset
compact=1 keeps, on every tweet: id, url, text, created_at, lang, favorite_count, retweet_count, reply_count, quote_count, view_count, bookmark_count, is_retweet, is_reply, is_quote, conversation_id, in_reply_to_status_id; on its author: id, username, name, followers_count, is_blue_verified, verified; on a quoted or retweeted tweet: id, url and the author's username. On user lists it keeps id, username, name, followers_count, following_count, is_blue_verified, verified, description.
Samples
curl "https://api.twitterapis.com/twitter/tweet/advanced_search?query=ai%20agents%20min_faves%3A100&compact=1" \
-H "Authorization: Bearer $API_KEY"curl "https://api.twitterapis.com/twitter/user/tweets?username=openai&fields=id,text,created_at,favorite_count,author.username" \
-H "Authorization: Bearer $API_KEY"import os, requests
r = requests.get(
"https://api.twitterapis.com/twitter/tweet/advanced_search",
params={"query": "from:openai filter:links", "product": "Latest", "compact": "1"},
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
timeout=30,
)
page = r.json()
for t in page["tweets"]:
print(t["id"], t["author"]["username"], t["text"][:80])
print("next:", page.get("next_cursor"))When to use which
- Building a monitor or a feed:
compact=1. You get what a timeline card shows and nothing else. - Extracting one thing at scale (every media URL, every mentioned handle): a tight
fields=list. - Storing raw data for later analysis: no projection. You cannot recover a field you did not fetch.
Cost
Projection is free and changes nothing about metering: the same call costs the same with or without it, and count still reports how many items the page carried before trimming.
Post and delete tweets with a session
Register a customer session once with your X credentials, then create and delete tweets programmatically. Full cURL, Python, and Node samples with cost math.
Wire TwitterAPIs into Claude, Cursor, and Windsurf
Install the TwitterAPIs MCP server in under two minutes and let your AI agent search tweets, fetch profiles, and read timelines without writing a line of glue code.