| name | x-api |
| description | 트윗, 스레드 게시, 타임라인 조회, 검색, 분석을 위한 X/Twitter API 통합입니다. OAuth 인증 패턴, 레이트 리밋, 플랫폼 네이티브 콘텐츠 게시를 다룹니다. 사용자가 X를 코드로 다루고 싶을 때 사용합니다. |
| origin | ECC |
X API
게시, 조회, 검색, 분석을 위한 X(Twitter) 프로그래매틱 연동입니다.
사용 시점
- 사용자가 트윗이나 스레드를 코드로 게시하고 싶을 때
- X에서 타임라인, 멘션, 사용자 데이터를 읽고 싶을 때
- X에서 콘텐츠, 트렌드, 대화를 검색할 때
- X 연동 기능이나 봇을 만들 때
- 분석 및 참여도 추적이 필요할 때
- 사용자가
"post to X", "tweet", "X API", "Twitter API"라고 말할 때
인증
OAuth 2.0 Bearer Token(앱 전용)
적합한 용도: 읽기 중심 작업, 검색, 공개 데이터 조회
export X_BEARER_TOKEN="your-bearer-token"
import os
import requests
bearer = os.environ["X_BEARER_TOKEN"]
headers = {"Authorization": f"Bearer {bearer}"}
resp = requests.get(
"https://api.x.com/2/tweets/search/recent",
headers=headers,
params={"query": "claude code", "max_results": 10}
)
tweets = resp.json()
OAuth 1.0a(사용자 컨텍스트)
필요한 용도: 트윗 게시, 계정 관리, DM, 모든 쓰기 작업
export X_CONSUMER_KEY="your-consumer-key"
export X_CONSUMER_SECRET="your-consumer-secret"
export X_ACCESS_TOKEN="your-access-token"
export X_ACCESS_TOKEN_SECRET="your-access-token-secret"
예전 구성에서는 X_API_KEY, X_API_SECRET, X_ACCESS_SECRET 같은 레거시 별칭이 있을 수 있습니다. 새 흐름을 문서화하거나 연결할 때는 X_CONSUMER_*, X_ACCESS_TOKEN_SECRET 이름을 우선합니다.
import os
from requests_oauthlib import OAuth1Session
oauth = OAuth1Session(
os.environ["X_CONSUMER_KEY"],
client_secret=os.environ["X_CONSUMER_SECRET"],
resource_owner_key=os.environ["X_ACCESS_TOKEN"],
resource_owner_secret=os.environ["X_ACCESS_TOKEN_SECRET"],
)
핵심 작업
트윗 게시
resp = oauth.post(
"https://api.x.com/2/tweets",
json={"text": "Hello from Claude Code"}
)
resp.raise_for_status()
tweet_id = resp.json()["data"]["id"]
스레드 게시
def post_thread(oauth, tweets: list[str]) -> list[str]:
ids = []
reply_to = None
for text in tweets:
payload = {"text": text}
if reply_to:
payload["reply"] = {"in_reply_to_tweet_id": reply_to}
resp = oauth.post("https://api.x.com/2/tweets", json=payload)
tweet_id = resp.json()["data"]["id"]
ids.append(tweet_id)
reply_to = tweet_id
return ids
사용자 타임라인 읽기
resp = requests.get(
f"https://api.x.com/2/users/{user_id}/tweets",
headers=headers,
params={
"max_results": 10,
"tweet.fields": "created_at,public_metrics",
}
)
트윗 검색
resp = requests.get(
"https://api.x.com/2/tweets/search/recent",
headers=headers,
params={
"query": "from:affaanmustafa -is:retweet",
"max_results": 10,
"tweet.fields": "public_metrics,created_at",
}
)
보이스 모델링용 최근 원문 게시물 수집
resp = requests.get(
"https://api.x.com/2/tweets/search/recent",
headers=headers,
params={
"query": "from:affaanmustafa -is:retweet -is:reply",
"max_results": 25,
"tweet.fields": "created_at,public_metrics",
}
)
voice_samples = resp.json()
사용자명으로 사용자 조회
resp = requests.get(
"https://api.x.com/2/users/by/username/affaanmustafa",
headers=headers,
params={"user.fields": "public_metrics,description,created_at"}
)
미디어 업로드 후 게시
media_resp = oauth.post(
"https://upload.twitter.com/1.1/media/upload.json",
files={"media": open("image.png", "rb")}
)
media_id = media_resp.json()["media_id_string"]
resp = oauth.post(
"https://api.x.com/2/tweets",
json={"text": "Check this out", "media": {"media_ids": [media_id]}}
)
레이트 리밋
X API의 레이트 리밋은 엔드포인트, 인증 방식, 계정 티어에 따라 달라지고 시간에 따라 바뀝니다. 항상 다음을 지킵니다.
- 현재 X 개발자 문서를 확인한 뒤 가정을 코드에 박습니다.
- 런타임에서
x-rate-limit-remaining, x-rate-limit-reset 헤더를 읽습니다.
- 정적인 표에 의존하지 말고 자동 백오프를 구현합니다.
import time
remaining = int(resp.headers.get("x-rate-limit-remaining", 0))
if remaining < 5:
reset = int(resp.headers.get("x-rate-limit-reset", 0))
wait = max(0, reset - int(time.time()))
print(f"Rate limit approaching. Resets in {wait}s")
오류 처리
resp = oauth.post("https://api.x.com/2/tweets", json={"text": content})
if resp.status_code == 201:
return resp.json()["data"]["id"]
elif resp.status_code == 429:
reset = int(resp.headers["x-rate-limit-reset"])
raise Exception(f"Rate limited. Resets at {reset}")
elif resp.status_code == 403:
raise Exception(f"Forbidden: {resp.json().get('detail', 'check permissions')}")
else:
raise Exception(f"X API error {resp.status_code}: {resp.text}")
보안
- 토큰 하드코딩 금지. 환경 변수나
.env 파일을 사용합니다.
.env 파일 커밋 금지. .gitignore에 추가합니다.
- 노출 시 토큰 교체. developer.x.com에서 다시 발급합니다.
- 쓰기 권한이 필요 없으면 읽기 전용 토큰 사용.
- OAuth 시크릿은 안전하게 보관. 소스 코드나 로그에 두지 않습니다.
Content Engine과의 연계
brand-voice와 content-engine으로 플랫폼 네이티브 콘텐츠를 만든 뒤 X API로 게시합니다.
- 보이스 매칭이 중요하면 최근 원문 게시물을 먼저 수집합니다.
VOICE PROFILE을 만들거나 재사용합니다.
content-engine으로 X 네이티브 형식의 콘텐츠를 생성합니다.
- 길이와 스레드 구조를 검증합니다.
- 사용자가 지금 바로 게시하라고 명시하지 않았다면 승인용 초안을 먼저 반환합니다.
- 승인 후에만 X API로 게시합니다.
public_metrics로 참여도를 추적합니다.
관련 스킬
brand-voice — 실제 X 및 사이트/소스 자료에서 재사용 가능한 보이스 프로필 생성
content-engine — X용 플랫폼 네이티브 콘텐츠 생성
crosspost — X, LinkedIn 등 여러 플랫폼에 콘텐츠 배포
connections-optimizer — 네트워크 기반 아웃리치 초안 전 X 그래프 정리