X 게시물과 프로필 JSON, 필드별 정리: 에이전트를 위한 레퍼런스

X 게시물과 프로필 JSON, 필드별 정리: 에이전트를 위한 레퍼런스
Unif Engineering team
Unif Engineering team

업데이트

UnifAPI 무료 X 엔드포인트가 게시물, 프로필, 페이지, 속도 제한, 오류에 대해 반환하는 모든 필드와 타입, 처리해야 할 예외 사례.

한마디로: 로그인 없이 무료로 쓸 수 있고 방문자별 횟수 제한이 적용되는 UnifAPI의 X 엔드포인트는 레코드 세 가지(post, profile, 그리고 목록을 감싸는 page 래퍼)와 오류 모양 하나, 속도 제한 헤더 세 개를 반환합니다. 필드 이름은 camelCase이고, id는 문자열이며(2^53을 넘습니다), 날짜는 UTC 기준 ISO 8601, 수치는 정수이고, X가 보고하지 않는 값은 0이 아니라 아예 없습니다. 이 페이지는 모든 필드를 타입과 함께, 그리고 프로그램이 처리해야 할 경우들과 함께 나열합니다. 원본 게시물에 repostedBy가 더해지는 리포스트, 한 단계만 중첩되는 인용, 수치는 반환하지만 게시물은 반환하지 않는 보호된 계정, 그리고 X가 대부분의 게시물에는 보고하지만 전부는 아닌 views입니다.

모델은 본 적 있는 JSON을 잘 읽습니다. 데이터 소스를 올바르게 쓰는 에이전트와 필드 이름을 추측하는 에이전트의 차이는, 레퍼런스가 컨텍스트에 있었는지 학습 데이터에 있었는지입니다. 이 글이 그 레퍼런스입니다. 사람용 뷰어 페이지가 렌더링하는 것과 같은 모델이므로, /tools/x-profile-viewer에서 보는 것이 정확히 /tools/x/profile?handle=…이 반환하는 것입니다.

규약

  • id는 문자열입니다. X의 id는 64비트이고, JSON 숫자는 2^53을 넘으면 정밀도를 잃습니다. URL과 커서 안을 포함해 모든 id는 문자열입니다.
  • 날짜는 ISO 8601, UTC입니다. createdAt과 joinedAt은 2026-10-05T22:33:56.000Z처럼 생겼습니다.
  • 수치는 정수입니다. 서식이 적용된 문자열도, null도 아닙니다. X가 보고하지 않은 수치는 0으로 설정되지 않고 빠집니다.
  • 선택 필드는 없을 수 있습니다. 선택으로 표시된 필드는 값이 없으면 객체에서 빠집니다. === 0이 아니라 "views" in post.metrics로 검사하세요.
  • URL은 정식 x.com URL입니다. post.url은 https://x.com/<handle>/status/<id>이고, 미디어 URL은 X의 CDN을 가리키며 절대 다시 호스팅되지 않습니다.

post

/tools/x/post에서 post로, 그리고 profile, media, search의 posts.items와 replies의 replies.items의 각 항목으로 반환됩니다.

필드타입의미
idstringPost ID
textstring전체 텍스트. 긴 게시물(노트)은 전부 반환되고, 미디어가 첨부된 경우 끝의 미디어 단축 링크는 제거됩니다
createdAtstring (ISO 8601)게시 시각
languagestring, 선택X가 감지한 BCP-47 코드 (en, ja, …)
conversationIdstring, 선택이 게시물이 속한 스레드의 루트 게시물 id
inReplyToPostIdstring, 선택답글인 경우, 이 게시물이 답하는 게시물
possiblySensitivebooleanX 자체 플래그
urlstring정식 x.com URL
authorprofile 또는 null작성자. X가 숨긴 경우에만 null
metricsobject아래 참조
mediamedia 배열없으면 빈 배열
repostedByobject 또는 null이 항목이 리포스트일 때 설정됩니다. 리포스트한 계정의 { id, handle, name }. 레코드의 나머지는 원본 게시물입니다
quotedpost 또는 null인용 게시물인 경우 인용된 게시물. 한 단계만 중첩됩니다(인용 안의 인용은 펼치지 않습니다)

metrics

필드타입의미
likesinteger
repostsinteger리포스트(리트윗). 인용은 세지 않습니다
repliesintegerX의 답글 수. 읽을 수 있는 공개 답글 수보다 클 수 있습니다
quotesinteger인용 게시물
bookmarksinteger
viewsinteger, 선택노출 수. X가 대부분의 게시물에 보고하며, 보고하지 않으면 없습니다

media

필드타입의미
kindphoto | video | animated_gif
urlstring, 선택원본 크기 이미지, 또는 동영상과 GIF의 포스터 프레임
previewUrlstring, 선택현재는 url과 같습니다. 더 작은 렌디션용으로 예약
width, heightinteger, 선택원본 크기
durationMsinteger, 선택동영상 길이
videoUrlstring, 선택X가 노출하는 최고 비트레이트 MP4, X의 CDN에 있음

profile

/tools/x/profile, /tools/x/media, /tools/x/followers에서 profile로, post.author로, 그리고 followers의 users.items의 각 항목으로 반환됩니다.

필드타입의미
idstringUser ID
handlestring@ 없이, X의 대소문자 그대로 (NASA)
namestring표시 이름
verifiedboolean모든 종류의 인증 (블루, 정부, 비즈니스)
verifiedTypestring, 선택X가 명시하는 경우 Government, Business, …
protectedboolean게시물이 공개되지 않음. 엔드포인트는 수치는 반환하지만 게시물은 반환하지 않습니다
biostring비어 있을 수 있음
locationstring자유 텍스트, 비어 있을 수 있음
websitestring, 선택t.co 단축 링크가 아닌 펼쳐진 URL
joinedAtstring (ISO 8601)
avatarUrlstring, 선택400×400 렌디션
bannerUrlstring, 선택
followersinteger
followinginteger
postsinteger누적 게시물 수
listedinteger, 선택보고되는 경우, 계정이 포함된 리스트 수
pinnedPostIdstring, 선택
urlstringhttps://x.com/<handle>

/tools/x/profile은 engagementRate를 더합니다. 페이지의 원본 게시물당 좋아요, 답글, 리포스트, 인용의 평균을 팔로워 수로 나눈 값을 유효 숫자 네 자리의 백분율로 나타낸 것입니다. 리포스트는 평균에서 제외됩니다. 팔로워 9천만 명인 계정에서는 작은 숫자(0.0058)가 나오는데, 버그가 아니라 정확한 값입니다.

page

모든 목록은 감싸여 있습니다.

{ "items": [ … ], "hasMore": true, "nextCursor": "DAAHCgABHUAq3YL__-wLAAIAAAATMj…" }
필드타입의미
itemsarraypost 레코드, followers에서는 profile 레코드, 또는 community 레코드
hasMoreboolean정확히 nextCursor가 설정된 경우에만 true
nextCursorstring 또는 null불투명. cursor=로 되돌려 보내면 다음 페이지를 받습니다

페이지 크기: profile은 게시물 10건, media는 12건, replies, search, communities는 20건, followers는 50건, 트렌드는 30건입니다. 커서는 불투명합니다. 20@처럼 생긴 것도 있고 X 자체의 DAAH… 문자열처럼 생긴 것도 있습니다. 절대 파싱하지 마세요.

트렌드와 커뮤니티

/tools/x/trends는 { woeid, locationSlug, generatedAt, trends: [ { rank, name, postCount?, url } ] }를 반환합니다. postCount는 X가 볼륨을 보고하는 트렌드에만 있습니다. 오늘날 대부분의 지역에서는 하나도 없으므로 선택 필드로 취급하세요. url은 x.com의 실시간 검색입니다.

/tools/x/communities는 { query, communities: page }를 반환하며, 각 항목은 { id, name, description, memberCount?, access?, joinPolicy?, createdAt?, url }입니다.

속도 제한 헤더

성공이든 오류든 모든 응답에 실립니다.

X-RateLimit-Limit: 20
X-RateLimit-Remaining: 17
X-RateLimit-Reset: 1791357984

Reset은 현재 10분 윈도가 끝나는 시점의 Unix 초입니다. 검색은 2유닛, 나머지는 모두 1유닛을 씁니다. 429에는 초 단위의 Retry-After가 더해집니다.

오류

2xx가 아닌 모든 응답은 다음과 같습니다.

{ "error": { "type": "not_found", "message": "X user not found: @nobody_here_123" } }
typeHTTP언제
validation_error400입력이 없거나 형식이 잘못됨 (Missing handle: pass ?handle=…)
not_found404계정이나 게시물이 없음. 정지된 계정은 메시지에 그렇게 표시됨
rate_limited429무료 제한 도달. 본문에 retryAfterSeconds와 upgrade가 더해짐
upstream_error502X의 데이터 레이어가 오류로 응답함
upstream_unavailable503타임아웃이거나 연결할 수 없음
not_configured503배포에 업스트림 자격 증명이 없음

type으로 분기하세요. message는 사람을 위한 것이고 바뀔 수 있습니다.

Markdown 모드

어느 엔드포인트에든 format=md를 붙이거나 Accept: text/markdown을 보내면 같은 레코드가 Markdown으로 렌더링됩니다. 작성자가 담긴 제목, 텍스트, 지표 한 줄, 미디어 링크, URL, 그리고 다음 커서를 알려주는 푸터입니다. 작성자 객체 안의 원시 id를 제외한 위의 모든 필드를 담고 있으며, 프로필이나 스레드를 모델의 컨텍스트에 넣는 가장 저렴한 방법입니다.

샘플이 있는 곳

각 도구의 Markdown 페이지에는 해당 엔드포인트의 캡처된 실제 응답이 몇 항목으로 잘라 담겨 있습니다. /tools/x-profile-viewer/index.md, /tools/x-post-viewer/index.md, /tools/x-search/index.md 등입니다. /llms.txt는 여덟 개 모두를 예시 URL과 함께 나열합니다. 종량제 X / Twitter API는 워크스페이스 키 뒤에서 같은 필드 이름을 쓰므로, 무료 엔드포인트 기준으로 작성한 코드는 수정 없이 옮겨 갑니다.