x-undocumented-api
Skill9 starsChanged 4 months agoMITView on GitHub
Manual-only; never auto-load. Use only when explicitly named (x-undocumented-api / x-api-skill).
In this repository33 other files it gives its agents.
- AGENTS.mdAGENTS.md
- agentic-scaffoldingSkill
- annas-archive-ebooksSkill
- ansi-artSkill
- clarifySkill
- conjecture-cascadeSkill
- crystallizeSkill
- dianalokadaSkill
- duris-game-knowledgeSkill
- duris-group-combatSkill
- ebook-extractorSkill
- failure-modesSkill
- gpt-pro-loopSkill
- graph-researcherSkill
- improve-codebaseSkill
- jevSkill
- julian-writingSkill
- kalshi-prediction-marketSkill
- lemmaSkill
- medium-paywall-bypassSkill
- ml-learning-methodsSkill
- name-reviewSkill
- no-process-pornSkill
- pm-deep-analysisSkill
- pm-market-analysisSkill
- pm-research-methodologiesSkill
- pm-situation-framingSkill
- prediction-drillSkill
- probe-driven-designSkill
- refine-testsSkill
- remove-ai-sinsSkill
- show-usageSkill
- writing-claude-skillsSkill
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 4 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 17
Use this skill for X.com's frontend web API: GraphQL operations under https://x.com/i/api/graphql, supporting REST-like web endpoints under …
- Distinctive: line 21
Verify operation names and query IDs against the current X web bundle.
- Very specific: line 22
Treat operationName as the durable conceptual endpoint, and queryId as rotating bundle metadata.
- Very specific: line 23
Never print raw cookies, auth_token, ct0, bearer tokens, proxy credentials, or full upstream payloads.
- Distinctive: line 25
Do not test mutations against live accounts unless the user explicitly asks for that mutation and understands the effect.
- Distinctive: line 26
Keep endpoint evidence with exact dates, operation IDs, variables, feature flags, response paths, account/access scope, and result counts.
- Distinctive: line 31
Read only what the task needs:
- Very specific: line 116
Search author-query cursors appear risky across account rotation.
- Very specific: line 152
Do not use SearchTimeline presence as the source of truth for reply visibility.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
X Undocumented API
Overview
Use this skill for X.com's frontend web API: GraphQL operations under https://x.com/i/api/graphql, supporting REST-like web endpoints under https://x.com/i/api, and the browser headers/cookies those calls require.
First Rules
- Verify operation names and query IDs against the current X web bundle; query IDs rotate.
- Treat
operationNameas the durable conceptual endpoint, andqueryIdas rotating bundle metadata. - Never print raw cookies,
auth_token,ct0, bearer tokens, proxy credentials, or full upstream payloads. - Generate
x-client-transaction-idfrom the current X web page/bundle material and the exact request method/path. - Do not test mutations against live accounts unless the user explicitly asks for that mutation and understands the effect.
- Keep endpoint evidence with exact dates, operation IDs, variables, feature flags, response paths, account/access scope, and result counts.
- Separate upstream variables from local caller filters. A runtime or CLI
itemFiltercan be an application-side filter rather than a proven GraphQL variable.
Reference Map
Read only what the task needs:
- runtime-and-auth.md: browser auth, cookies, bearer tokens, CSRF, transaction IDs, headers, guest tokens, and error classes.
- graphql-discovery.md: extracting operation names, query IDs, feature flags, field toggles, and endpoint inventories from X web bundles.
- endpoint-patterns.md: request/response shapes for SearchTimeline, user/list/follower/tweet timelines, timeline instructions, and search operators.
- community-timelines.md: X Communities operations, variables, ranking modes, response paths, and community-search caveats.
- trends-and-explore.md: authenticated trend collection, Explore tabs, topic aliases, story history, locations, personalization, and measured count/cursor limits.
- story-search.md: story-search limits, official News search versus web access, and Relay news/topic operations missed by older inventories.
- geography.md: working per-request WOEID trends, coordinate lookup, city/country overlap, location-name ambiguity, and geography controls.
- geographic-post-search.md: keyword and place-tag searches, cursor depth, volume measurement, query-window omissions, and historical city-filter false negatives.
- cursor-behavior.md: X timeline cursor semantics, pagination risks, fan-out caveats, and evidence standards.
- reply-visibility-research.md: high-fidelity notes from the 2026-05 reply visibility investigation, including observed failure modes, experiments, current best thinking, and next discriminators.
Reusable script:
scripts/extract-x-graphql-endpoints.ts: fetch current X web bundles and save a JSON/CSV operation inventory.
Investigation Workflow
- Clarify whether the user needs an API explanation, a current endpoint inventory, a request shape, or a live read-only probe.
- Extract or inspect the current X web bundle before relying on query IDs, variables, features, or response paths.
- For unknown GraphQL operations, locate nearby bundle code for variable names, feature flags, field toggles, and response normalization paths.
- For author-corpus work, compare native timeline operations against
SearchTimelineauthor queries and record lane yield per page, not just total pages. - For live read probes, use secret-safe output: status code, top-level keys, response path presence, item counts, cursor presence, and example public IDs only.
- For pagination behavior, record request cursor, returned cursors, item IDs in order, item count, first/last sort index, endpoint, variables, and observed time.
- Save dated findings outside the skill unless the user explicitly asks to update this skill.
GraphQL Request Shape
X web GraphQL paths have this form:
https://x.com/i/api/graphql/<queryId>/<operationName>?variables=<json>&features=<json>Some operations also use fieldToggles=<json>.
Authenticated reads commonly need these headers:
authorization: Bearer <X web bearer token>
x-csrf-token: <ct0>
cookie: ct0=<ct0>; auth_token=<auth_token>
x-client-transaction-id: <generated for method + full path>
x-twitter-active-user: yes
x-twitter-auth-type: OAuth2Session
x-twitter-client-language: en
origin: https://x.com
referer: https://x.com/The transaction ID path must include the query ID:
/i/api/graphql/<queryId>/<operationName>Diagnostics
| Symptom | Likely cause | Next check |
| HTTP 401 or 403 | Expired cookies, missing ct0, bad bearer token, access restriction, account challenge | Refresh browser session material; do not print secrets |
| Empty HTTP 404 | Missing/invalid x-client-transaction-id or stale query ID | Verify full path includes query ID and regenerate transaction ID from current X material |
| HTTP 429 | Rate limited account, IP, or operation | Inspect X rate-limit headers and retry windows |
| HTTP 400 | Variable, feature, or field-toggle mismatch | Compare request payload with current bundle caller code |
| HTTP 200 with empty timeline | Access limitation, wrong response path, stale variables, logged-out limitation, or empty source | Inspect top-level keys and instruction path without dumping payload |
| Data is stale or incomplete | Search index behavior or ranking product choice | Prefer native timeline operations when available |
| Mutation returns HTTP 200 but no send captured in the HTTP log, yet the action took effect | The action rode a WebSocket, not an HTTP mutation (X Chat sends are WS frames to wss://chat-ws.x.com/ws) | Use a WebSocket frame capture (CDP WebSocketFrameSent/Received), not request logging. HTTP GraphQL capture will never see these sends |
| Reply verification mismatch after REST or fallback send | X may prepend the leading @handle; the visible draft text is often the display_text_range slice | Compare against legacy.full_text.slice(display_text_range) when available |
Current High-Value Facts
- Geographic post search uses
place:<hexadecimal post-place ID>orplace_country:<country code>, not trend WOEIDs or Explore place IDs. SFplace:5a110d312052166fworked alone and with keywords. Treat returned place metadata as a label, not verified physical presence. - Geographic search counts are observed lower bounds. An SF study retrieved 3,020 cursor-linked posts, but a smaller keyword/day query recovered a weekly post missed by the broad crawl. Historical city-filter queries excluded a known 2019 SF-tagged post that remained visible without that filter. Do not turn empty older city searches into zero-volume measurements.
- For broad trend discovery, test
GET /i/api/2/guide.jsonwithcandidate_source=trendsbefore relying onExplorePagepagination. In 2026-09-04 probes,count=200returned about 120 trends, while the GraphQL Trending tab returned 30 ordinary trends and one promoted item regardless of counts 1, 100, or 500. - Preserve
groupedTrendsaliases separately from ranked parent trends. Three sampled accounts produced 122 distinct parent trends and 144 terms including aliases. Account rotation added little in that sample. - A returned or changed cursor does not prove more data exists. All five Explore tab continuations returned no content; the guide's
DefaultBottomCursorValuealso returned an empty page. Stop on zero new items. TrendHistoryreturns timestamped story summaries, not volume history.TrendRelevantUsersreturned three users per tested AI trend. Neither supplies a posts-per-hour baseline.- Full story pages use
AiTrendByRestId, discovered in lazybundle.LiveEvent. Itspagereturns the summary, update time, and Top/Latest post timeline IDs. Read those withGenericTimelineById; story-feed pagination returned more posts even when Explore-tab pagination was empty. See the Trends reference for variables and response paths. - AI story discovery items carry
social_context.textwith displayed age/category/post counts. Preserve that field; rounded counts have no verified time window and are not geographic traffic totals. - For per-request geographic trends,
GET /i/api/1.1/trends/place.json?id=<WOEID>works with authorized web sessions. September 5 probes across 16 cities/countries/worldwide yielded 321 distinct names. This does not require changing Explore settings.trends/closest.jsonmapslatandlongto a supported WOEID. - Location discovery uses both WOEIDs and separate signed-string
place_idvalues. Their catalogues differ. Request-only location overrides failed to establish control onguide, but the separatetrends/placereader works. Keep all account-settings mutations outside read-only probes. - The bundle extractor now starts at
https://x.com/explore. The logged-out homepage uses a differentx-webapp. Public webpack runtime maps can reveal lazy bundles without login; derive filenames from the current resolver. SearchTimelineusesrawQuery,product,count, optionalcursor, and promoted-content controls.SearchTimelineauthor queries can outperform native user timelines for corpus collection. In live xpool probes on 2026-06-18,from:<handle> -filter:replies -filter:retweetsandfrom:<handle> filter:repliesreached 100 lane items in 5 pages for sampled accounts where native timeline crawls hit only 39-47 items after 20 pages.- Search author-query cursors appear risky across account rotation. In live xpool profile-sample probes, later-page
SearchTimelinecontinuations under rotating accounts produced concentrated 404 / timeout / network failures; pinning one account per lane materially reduced that failure mix, though it did not remove empty-page degeneration. - Native list recency is
ListLatestTweetsTimeline, notSearchTimeline list:<id>. - Native community posts are
CommunityTweetsTimeline, not aSearchTimelinecommunity operator. - Direct messages are now "X Chat": end-to-end-encrypted, PIN-gated, and sent over WebSocket (
wss://chat-ws.x.com/ws?token=<JWT>), not a GraphQL/REST mutation. Legacy DM mutations (useSendMessageMutation, RESTdm/new2.json) are gone from current bundles. See the 2026-06-18 notes below. UserTweetsAndReplieslocalitemFilterhandling is not proof of an upstream GraphQL variable. In the 2026-06-18 bundle scan,itemFilter,authored_posts, andauthored_repliesstrings were absent from the current client-web bundle.UserTweetscan include repost surfaces; do not treat it as pure authored root-post history without checking surface kind or local filters. In 2026-06-18 live xpool probes, nativeUserTweetsrecovered materially more root-post items than author-search for some post-light accounts (64vs20,100vs74,22vs2in early comparisons, later22vs2,1vs1, and18vs0on three more post-light accounts), so a post lane may need native-timeline preference even when reply lanes stay on search.- Low-yield native post
cursor_loopis often a corpus-shape signal, not a pure transport failure. In one fresh xpool worker slice, low-yield post loops split into two buckets: sparse accounts where replies also stopped early (average lifetime tweet count about200) and reply-heavy accounts where replies still reached target (average lifetime tweet count about4300while root-post yield stayed near7). - In a larger hybrid-worker slice after the posts=
UserTweets/ replies=SearchTimelinerollout (1,534 samples since the 2026-06-18T21:39:50Z boot), reply lanes were dominated bytarget_items_reachedandsource_exhausted, while posts still split acrosstarget_items_reached,max_pages_reached, andcursor_loop. Treat that as evidence for a hybrid endpoint choice, not a single universally best authored-corpus endpoint. - A short
runner_terminatedburst immediately after a PM2 restart can be rollover noise from in-flight work rather than a steady-state cursor signal. In the same 2026-06-18 investigation, all freshrunner_terminatedreply-lane rows landed within about one second, 44-45 seconds after restart, with none afterward. TimelineTimelineCursorentries commonly carryTopandBottomcursor values.countis not always honored by timeline operations; observe returned item counts. Current live author-search probes emitted about 20 items/page even when higher counts were requested.
2026-06-18 Direct Messages / X Chat E2E Notes
These notes came from a live investigation (logged-in managed sessions via a CDP-backed browser tool, with WebSocket frame capture). Treat them as the current DM reality, superseding any older "send a DM via GraphQL" assumption.
- Legacy DM mutations are gone.
useSendMessageMutation(query idMaxK2PKX1F9Z-9SwqwavTwin the 2023-eratwitter-api-clientregistry) and the REST fallbackdm/new2.jsonare absent from every current X web bundle chunk. Do not reuse them; they will not work. - X has replaced DMs with "X Chat": end-to-end-encrypted and PIN-gated. Rolled out from Nov 2025 ("X Chat replacing DMs for some X users"). Authenticated
/messagesredirects to/i/chat/pin/newuntil the account is provisioned. - Send is a WebSocket frame, not an HTTP mutation. The send rides
wss://chat-ws.x.com/ws?token=<JWT>. HTTP GraphQL/REST capture during a real send observed zero send calls. There is no sendoperationNameto extract — bundle extraction can never surface a DM send query id, by design, not by capture gap. - PIN derives encryption keys client-side. Provisioning the passcode generated no server request carrying the PIN; keys are produced locally from it. A fresh browser context (no local key material) is redirected to
/i/chat/pin/recoveryand must re-enter the PIN to re-derive keys before any read or send. Cookie-only / headless sessions are therefore insufficient for X Chat without PIN re-entry. - DM-adjacent HTTP mutations that DO remain in current bundles:
dmBlockUser(IYw9u1KEhrS-t-BXsau4Uw),dmUnblockUser(Krbs6Nak_o7liWQwfV1jOQ),DmNsfwMediaFilterUpdate(of_N6O33zfyD4qsFJMYFxA),ConversationControlChange(57WYJNnWH0vM3Ip_gm8B2g),ConversationControlDelete(OoMO_aSZ1ZXjegeamF9QmA). These are block/unblock/control, not send. - Capture tooling caveats: CDP
Network.enabledoes not capture POST bodies unlessmax_post_data_sizeis set; and WebSocket frames need dedicatedWebSocketCreated/WebSocketFrameSent/WebSocketFrameReceivedhandlers — request handlers never see them. A CDP tool without WS handlers is blind to X Chat. - Reachability: accounts that have never followed / accepted a message request from each other cannot exchange DMs — recipient search at
/i/chatcompose returns only the sender, and a typed message becomes a self-chat ("You:<text>") the other account never receives.
2026-05-20 Reply Publish Visibility Notes
These notes came from a live, user-approved xpool reply probe plus current X web bundle inspection. Treat query IDs as dated facts and regenerate before reusing.
- Current observed
CreateTweetquery ID was5CdvsV_zjv4L64XFifAglw; current observedTweetDetailquery ID wasoCon7R-cgWRFy6EfZjaKfg. - A patched direct GraphQL reply send used
POST /i/api/graphql/5CdvsV_zjv4L64XFifAglw/CreateTweet, returned HTTP 200, had no top-level GraphQL errors, and returneddata.create_tweet.tweet_results. - Useful mutation evidence, without secrets: method, path, operation name, query ID, transaction-id state, HTTP status, content type, GraphQL error presence, response path,
ct0rotation boolean, rate-limit headers, body key names, created public tweet ID, parent tweet ID, and verifier result. - For replies, native-like variables include
tweet_text,media,semantic_annotation_ids, andreply.in_reply_to_tweet_idwithexclude_reply_user_ids. - Current web metadata includes
fieldTogglesonCreateTweet; include the current toggles when the bundle advertises them. - Native
engagement_requestis conditional, not universal. X web emitted it only when composer/source state had promoted/impression content with bothdisclosure_typeandimpression_id; missing it is a source-context gap for impression-backed targets, not proof every direct reply is non-native. TweetDetailparent-thread visibility can lag or paginate. In the live probe, the created reply was initially behind aShowMoreThreadscursor inrankingMode=Relevance, then appeared on page 1 a few minutes later.SearchTimelinecan be a false negative for newly created replies. In the live probe, the reply was visible through parentTweetDetail Relevance, whileSearchTimelinemissed it by bothconversation_id:<parent_id>and exact-text search.- Do not use
SearchTimelinepresence as the source of truth for reply visibility. It is a discoverability/indexing signal only. - First-party hidden replies are a separate surface. Check
ModeratedTimelinefor the parent before labeling a reply hidden; in the live probe it returned a valid empty hidden-replies timeline while parentTweetDetailshowed the reply. - Visibility verification should be a vector, not one boolean: direct lookup visible, author replies visible with cursor depth, parent
TweetDetailseen with ranking mode/page/cursor, search discoverable,ModeratedTimelinepresent/absent, policy wrapper/tombstone/limited-action state. - Later native-browser, real-Google-Chrome, and graph-connected xpool experiments are summarized in reply-visibility-research.md. The short version: accepted replies can be direct-visible to other viewers while absent from those viewers' parent
TweetDetail; a one-way poster-follows-parent-author edge did not clear that threshold in the sampled runs.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

