El JSON de publicaciones y perfiles de X, campo por campo: una referencia para agentes

Actualizado
Cada campo que devuelven los endpoints gratis de X de UnifAPI para posts, perfiles, páginas, límites y errores, con tipos y casos límite.
En resumen: los endpoints de X en UnifAPI, gratis, sin iniciar sesión y con límite por visitante, devuelven tres registros (
post,profiley el envoltoriopagede las listas) más una forma de error y tres encabezados de límite de uso. Los nombres de campo van en camelCase, los ids son cadenas (superan 2^53), las fechas son ISO 8601 en UTC, los recuentos son enteros y todo lo que X no informa está ausente, no a cero. Esta página lista cada campo con su tipo y los casos que un programa tiene que manejar: un repost que trae la publicación original másrepostedBy, una cita que se anida un nivel, una cuenta protegida que devuelve sus recuentos pero no sus publicaciones, yviews, que X informa en la mayoría de las publicaciones pero no en todas.
Los modelos leen bien el JSON que ya han visto. La diferencia entre un agente que usa una fuente de datos correctamente y uno que adivina nombres de campo está en si la referencia estaba en su contexto o en sus datos de entrenamiento. Esta es esa referencia. Es el mismo modelo que renderizan las páginas de los visualizadores para personas, así que lo que ves en /tools/x-profile-viewer es exactamente lo que devuelve /tools/x/profile?handle=….
Convenciones
- Los ids son cadenas. Los ids de X son de 64 bits; los números JSON pierden precisión por encima de 2^53. Todo
ides una cadena, también en las URLs y los cursores. - Las fechas son ISO 8601, UTC.
createdAtyjoinedAttienen la forma2026-10-05T22:33:56.000Z. - Los recuentos son enteros. Nunca cadenas formateadas, nunca nulos. Un recuento que X no informó se omite, no se pone a 0.
- Opcional significa ausente. Un campo marcado como opcional falta en el objeto cuando no hay valor. Comprueba con
"views" in post.metrics, no con=== 0. - Las URLs son URLs canónicas de x.com.
post.urleshttps://x.com/<handle>/status/<id>; las URLs de medios apuntan al CDN de X y nunca se vuelven a alojar.
post
Lo devuelve /tools/x/post (como post), y es cada elemento de posts.items en profile, media y search, y de replies.items en replies.
| Campo | Tipo | Significado |
|---|---|---|
id | string | ID de la publicación |
text | string | Texto completo. Las publicaciones largas (notas) se devuelven enteras; el enlace corto de medios del final se elimina cuando hay medios adjuntos |
createdAt | string (ISO 8601) | Hora de publicación |
language | string, opcional | Código BCP-47 detectado por X (en, ja, …) |
conversationId | string, opcional | Id de la publicación raíz del hilo al que pertenece esta |
inReplyToPostId | string, opcional | La publicación a la que responde esta, cuando es una respuesta |
possiblySensitive | boolean | La marca de la propia X |
url | string | URL canónica de x.com |
author | profile o null | El autor; null solo cuando X lo ha retenido |
metrics | object | Ver abajo |
media | array de media | Vacío cuando no hay |
repostedBy | object o null | Presente cuando esta entrada es un repost: { id, handle, name } de la cuenta que lo reposteó. El resto del registro es la publicación original |
quoted | post o null | La publicación citada cuando esta es una cita, anidada un nivel (una cita dentro de una cita no se expande) |
metrics
| Campo | Tipo | Significado |
|---|---|---|
likes | integer | |
reposts | integer | Reposts (retweets), sin contar las citas |
replies | integer | El recuento de respuestas de X; puede superar el número de respuestas públicas legibles |
quotes | integer | Publicaciones que citan |
bookmarks | integer | |
views | integer, opcional | Impresiones. X las informa en la mayoría de las publicaciones; ausente cuando no lo hace |
media
| Campo | Tipo | Significado |
|---|---|---|
kind | photo | video | animated_gif | |
url | string, opcional | Imagen a tamaño completo, o el fotograma de portada para video y GIF |
previewUrl | string, opcional | Hoy es igual que url; reservado para una versión más pequeña |
width, height | integer, opcional | Dimensiones originales |
durationMs | integer, opcional | Duración del video |
videoUrl | string, opcional | El MP4 de mayor bitrate que expone X, en el CDN de X |
profile
Lo devuelven /tools/x/profile, /tools/x/media y /tools/x/followers (como profile), es post.author y es cada elemento de users.items en followers.
| Campo | Tipo | Significado |
|---|---|---|
id | string | ID de usuario |
handle | string | Sin la @, con las mayúsculas y minúsculas de X (NASA) |
name | string | Nombre visible |
verified | boolean | Cualquier verificación (azul, gobierno, empresa) |
verifiedType | string, opcional | Government, Business, … cuando X indica uno |
protected | boolean | Las publicaciones no son públicas. Los endpoints devuelven los recuentos pero no las publicaciones |
bio | string | Puede estar vacía |
location | string | Texto libre, puede estar vacío |
website | string, opcional | URL expandida, no el enlace corto t.co |
joinedAt | string (ISO 8601) | |
avatarUrl | string, opcional | Versión de 400×400 |
bannerUrl | string, opcional | |
followers | integer | |
following | integer | |
posts | integer | Recuento de publicaciones de toda la vida de la cuenta |
listed | integer, opcional | Listas en las que aparece la cuenta, cuando se informa |
pinnedPostId | string, opcional | |
url | string | https://x.com/<handle> |
/tools/x/profile añade engagementRate: la media de me gusta, respuestas, reposts y citas por publicación original de la página, dividida entre los seguidores, como porcentaje con cuatro cifras significativas. Los reposts quedan fuera de la media. Para una cuenta con 90 millones de seguidores es un número pequeño (0.0058), lo cual es correcto, no un error.
page
Toda lista va envuelta:
{ "items": [ … ], "hasMore": true, "nextCursor": "DAAHCgABHUAq3YL__-wLAAIAAAATMj…" }
| Campo | Tipo | Significado |
|---|---|---|
items | array | registros post, o registros profile en followers, o registros community |
hasMore | boolean | True exactamente cuando nextCursor está presente |
nextCursor | string o null | Opaco. Devuélvelo como cursor= para obtener la página siguiente |
Tamaños de página: 10 publicaciones en profile, 12 en media, 20 en replies, search y communities, 50 en followers, 30 tendencias. Los cursores son opacos; algunos tienen la forma 20@, otros son las cadenas DAAH… de la propia X. Nunca los analices.
Tendencias y comunidades
/tools/x/trends devuelve { woeid, locationSlug, generatedAt, trends: [ { rank, name, postCount?, url } ] }. postCount solo está presente en las tendencias para las que X informa un volumen; hoy, en la mayoría de las ubicaciones, no es ninguna, así que trátalo como opcional. url es la búsqueda en vivo en x.com.
/tools/x/communities devuelve { query, communities: page }, donde cada elemento es { id, name, description, memberCount?, access?, joinPolicy?, createdAt?, url }.
Encabezados de límite de uso
En cada respuesta, con éxito o con error:
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 17
X-RateLimit-Reset: 1791357984
Reset son los segundos Unix del momento en que termina la ventana actual de 10 minutos. Una búsqueda cuesta 2 unidades; todo lo demás, 1. Un 429 añade Retry-After en segundos.
Errores
Toda respuesta que no sea 2xx es:
{ "error": { "type": "not_found", "message": "X user not found: @nobody_here_123" } }
type | HTTP | Cuándo |
|---|---|---|
validation_error | 400 | Entrada ausente o mal formada (Missing handle: pass ?handle=…) |
not_found | 404 | No existe la cuenta o la publicación; las cuentas suspendidas lo indican en el mensaje |
rate_limited | 429 | Límite gratuito alcanzado; el cuerpo añade retryAfterSeconds y upgrade |
upstream_error | 502 | La capa de datos de X respondió con un error |
upstream_unavailable | 503 | Tiempo de espera agotado o inalcanzable |
not_configured | 503 | El despliegue no tiene credenciales aguas arriba |
Ramifica según type; message es para personas y puede cambiar.
Modo Markdown
Añade format=md o envía Accept: text/markdown a cualquier endpoint y el mismo registro se renderiza como Markdown: un encabezado con el autor, el texto, una línea de métricas, enlaces a los medios, la URL y un pie que indica el cursor siguiente. Lleva todos los campos de arriba salvo los ids en bruto dentro del objeto del autor, y es la forma más barata de meter un perfil o un hilo en el contexto de un modelo.
Dónde están las muestras
La página Markdown de cada herramienta trae una respuesta real capturada de su endpoint, recortada a unos pocos elementos: /tools/x-profile-viewer/index.md, /tools/x-post-viewer/index.md, /tools/x-search/index.md, etc. /llms.txt lista los ocho con una URL de ejemplo cada uno. La API de X / Twitter con medición de uso usa los mismos nombres de campo detrás de una clave de workspace, así que el código escrito contra los endpoints gratuitos se traslada sin cambios.