X-Post- und Profil-JSON, Feld für Feld: eine Referenz für Agents

Aktualisiert
Jedes Feld, das die kostenlosen UnifAPI-X-Endpunkte für Posts, Profile, Seiten, Rate Limits und Fehler liefern – mit Typen und Sonderfällen.
Kurz gesagt: Die X-Endpoints auf UnifAPI, kostenlos ohne Login nutzbar und pro Besucher begrenzt, liefern drei Datensätze (
post,profileund denpage-Wrapper um Listen) plus eine Fehlerform und drei Rate-Limit-Header. Feldnamen sind camelCase, ids sind Strings (sie überschreiten 2^53), Datumsangaben sind ISO 8601 in UTC, Zähler sind Ganzzahlen, und alles, was X nicht meldet, fehlt, statt null zu sein. Diese Seite listet jedes Feld mit seinem Typ und den Fällen, die ein Programm behandeln muss: ein Repost, der den Originalpost plusrepostedByträgt, ein Zitat, das eine Ebene tief verschachtelt ist, ein geschützter Account, der seine Zahlen, aber keine Posts liefert, undviews, die X bei den meisten Posts meldet, aber nicht bei allen.
Modelle sind gut darin, JSON zu lesen, das sie schon gesehen haben. Der Unterschied zwischen einem Agent, der eine Datenquelle korrekt nutzt, und einem, der Feldnamen rät, ist, ob die Referenz in seinem Kontext oder in seinen Trainingsdaten war. Das hier ist die Referenz. Es ist dasselbe Modell, das die Viewer-Seiten für Menschen rendern, also ist das, was Sie auf /tools/x-profile-viewer sehen, exakt das, was /tools/x/profile?handle=… liefert.
Konventionen
- Ids sind Strings. X-Ids sind 64-Bit; JSON-Zahlen verlieren oberhalb von 2^53 an Präzision. Jede
idist ein String, auch in URLs und Cursorn. - Datumsangaben sind ISO 8601, UTC.
createdAtundjoinedAtsehen aus wie2026-10-05T22:33:56.000Z. - Zähler sind Ganzzahlen. Nie formatierte Strings, nie null. Ein Zähler, den X nicht gemeldet hat, wird weggelassen, nicht auf 0 gesetzt.
- Optional heißt abwesend. Ein als optional markiertes Feld fehlt im Objekt, wenn es keinen Wert gibt. Mit
"views" in post.metricsprüfen, nicht mit=== 0. - URLs sind kanonische x.com-URLs.
post.urlisthttps://x.com/<handle>/status/<id>; Medien-URLs zeigen auf das CDN von X und werden nie neu gehostet.
post
Geliefert von /tools/x/post (als post) sowie als jedes Element von posts.items auf profile, media und search und von replies.items auf replies.
| Feld | Typ | Bedeutung |
|---|---|---|
id | string | Post-ID |
text | string | Volltext. Lange Posts (Notes) werden vollständig geliefert; der Medien-Kurzlink am Ende wird entfernt, wenn Medien angehängt sind |
createdAt | string (ISO 8601) | Veröffentlichungszeit |
language | string, optional | BCP-47-Code, den X erkannt hat (en, ja, …) |
conversationId | string, optional | Id des Wurzel-Posts des Threads, zu dem dieser Post gehört |
inReplyToPostId | string, optional | Der Post, auf den dieser antwortet, wenn es eine Antwort ist |
possiblySensitive | boolean | Das eigene Flag von X |
url | string | Kanonische x.com-URL |
author | profile oder null | Der Autor; null nur, wenn X ihn zurückgehalten hat |
metrics | object | Siehe unten |
media | Array aus media | Leer, wenn keine vorhanden |
repostedBy | object oder null | Gesetzt, wenn dieser Eintrag ein Repost ist: { id, handle, name } des Accounts, der repostet hat. Der Rest des Datensatzes ist der Original-Post |
quoted | post oder null | Der zitierte Post, wenn dies ein Zitat-Post ist, eine Ebene tief verschachtelt (ein Zitat in einem Zitat wird nicht aufgelöst) |
metrics
| Feld | Typ | Bedeutung |
|---|---|---|
likes | integer | |
reposts | integer | Reposts (Retweets), ohne Zitate |
replies | integer | Die Antwortzahl von X; kann über der Zahl der lesbaren öffentlichen Antworten liegen |
quotes | integer | Zitat-Posts |
bookmarks | integer | |
views | integer, optional | Impressionen. X meldet sie bei den meisten Posts; fehlt, wenn nicht |
media
| Feld | Typ | Bedeutung |
|---|---|---|
kind | photo | video | animated_gif | |
url | string, optional | Bild in voller Größe oder das Vorschaubild für Video und GIF |
previewUrl | string, optional | Heute identisch mit url; reserviert für eine kleinere Variante |
width, height | integer, optional | Originalabmessungen |
durationMs | integer, optional | Videolänge |
videoUrl | string, optional | MP4 mit der höchsten Bitrate, die X bereitstellt, auf dem CDN von X |
profile
Geliefert von /tools/x/profile, /tools/x/media und /tools/x/followers (als profile), als post.author und als jedes Element von users.items auf followers.
| Feld | Typ | Bedeutung |
|---|---|---|
id | string | Nutzer-ID |
handle | string | Ohne das @, in der Schreibweise von X (NASA) |
name | string | Anzeigename |
verified | boolean | Jede Art von Verifizierung (blau, Regierung, Unternehmen) |
verifiedType | string, optional | Government, Business, … wenn X eine benennt |
protected | boolean | Posts sind nicht öffentlich. Die Endpoints liefern Zahlen, aber keine Posts |
bio | string | Kann leer sein |
location | string | Freitext, kann leer sein |
website | string, optional | Aufgelöste URL, nicht der t.co-Kurzlink |
joinedAt | string (ISO 8601) | |
avatarUrl | string, optional | Variante in 400×400 |
bannerUrl | string, optional | |
followers | integer | |
following | integer | |
posts | integer | Gesamtzahl der Posts |
listed | integer, optional | Listen, auf denen der Account steht, wenn gemeldet |
pinnedPostId | string, optional | |
url | string | https://x.com/<handle> |
/tools/x/profile ergänzt engagementRate: der Durchschnitt aus Likes, Antworten, Reposts und Zitaten pro Originalpost auf der Seite, geteilt durch die Follower, als Prozentwert mit vier signifikanten Stellen. Reposts sind vom Durchschnitt ausgenommen. Für einen Account mit 90 Millionen Followern ist das eine kleine Zahl (0.0058), was korrekt ist und kein Fehler.
page
Jede Liste ist eingepackt:
{ "items": [ … ], "hasMore": true, "nextCursor": "DAAHCgABHUAq3YL__-wLAAIAAAATMj…" }
| Feld | Typ | Bedeutung |
|---|---|---|
items | array | post-Datensätze, oder profile-Datensätze auf followers, oder community-Datensätze |
hasMore | boolean | Genau dann true, wenn nextCursor gesetzt ist |
nextCursor | string oder null | Opak. Als cursor= zurückgeben, um die nächste Seite zu bekommen |
Seitengrößen: 10 Posts auf profile, 12 auf media, 20 auf replies, search und communities, 50 auf followers, 30 Trends. Cursor sind opak; manche sehen aus wie 20@, manche wie die DAAH…-Strings von X selbst. Nie parsen.
Trends und Communities
/tools/x/trends liefert { woeid, locationSlug, generatedAt, trends: [ { rank, name, postCount?, url } ] }. postCount ist nur bei den Trends vorhanden, für die X ein Volumen meldet; für die meisten Standorte sind das heute keine, also als optional behandeln. url ist die Live-Suche auf x.com.
/tools/x/communities liefert { query, communities: page }, wobei jedes Element { id, name, description, memberCount?, access?, joinPolicy?, createdAt?, url } ist.
Rate-Limit-Header
In jeder Antwort, ob Erfolg oder Fehler:
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 17
X-RateLimit-Reset: 1791357984
Reset sind Unix-Sekunden, zu denen das aktuelle 10-Minuten-Fenster endet. Eine Suche kostet 2 Einheiten, alles andere 1. Ein 429 ergänzt Retry-After in Sekunden.
Fehler
Jede Nicht-2xx-Antwort ist:
{ "error": { "type": "not_found", "message": "X user not found: @nobody_here_123" } }
type | HTTP | Wann |
|---|---|---|
validation_error | 400 | Fehlende oder fehlerhafte Eingabe (Missing handle: pass ?handle=…) |
not_found | 404 | Kein solcher Account oder Post; gesperrte Accounts werden in der Meldung genannt |
rate_limited | 429 | Kostenloses Limit erreicht; der Body ergänzt retryAfterSeconds und upgrade |
upstream_error | 502 | Die Datenschicht von X hat mit einem Fehler geantwortet |
upstream_unavailable | 503 | Timeout oder nicht erreichbar |
not_configured | 503 | Das Deployment hat keine Upstream-Zugangsdaten |
Nach type verzweigen; message ist für Menschen und kann sich ändern.
Markdown-Modus
Mit format=md oder dem Header Accept: text/markdown an einem beliebigen Endpoint wird derselbe Datensatz als Markdown gerendert: eine Überschrift mit dem Autor, der Text, eine Zeile Metriken, Medien-Links, die URL und eine Fußzeile mit dem nächsten Cursor. Er trägt jedes Feld von oben außer den rohen ids im Autor-Objekt und ist der günstigste Weg, ein Profil oder einen Thread in den Kontext eines Modells zu bringen.
Wo die Beispiele liegen
Die Markdown-Seite jedes Tools enthält eine aufgezeichnete echte Antwort für ihren Endpoint, gekürzt auf wenige Elemente: /tools/x-profile-viewer/index.md, /tools/x-post-viewer/index.md, /tools/x-search/index.md und so weiter. /llms.txt listet alle acht mit je einer Beispiel-URL. Die abgerechnete X / Twitter API verwendet hinter einem Workspace-Key dieselben Feldnamen, sodass Code, der gegen die kostenlosen Endpoints geschrieben wurde, ohne Änderungen umzieht.