How to Create an X Thread with TwexAPI
Long updates often work better as an X thread than as one overloaded post. Product launch notes, research summaries, incident updates, and founder commentary usually need a controlled sequence: the hook first, context next, evidence after that, and a clear closing post.
TwexAPI's Create a Tweet Thread endpoint publishes that sequence with one request. Send an ordered items array, include the X account cookie or auth_token, and the response returns the created tweet IDs in thread order.
Because this is a write endpoint, treat it like a publishing action, not a content generator. Draft the thread somewhere else, review every post, then call the API only after approval.
Endpoint and Request Fields
Use POST /v3/twitter/tweets/create-thread when you already have the final thread text and want TwexAPI to publish the posts in order.
| Field | Type | Required | Notes |
|---|---|---|---|
items | string array | Yes | Ordered list of tweet texts. The first item becomes the first post in the thread. |
cookie | string | Yes | X authentication cookie or auth_token. Store it in a server-side secret, never in client code. |
proxy | string or null | No | Optional proxy reference for the posting session, for example http://username:password@ip:port. |
The docs list this endpoint at $0.0025 per call. Your own system should still record every attempted publish, because retries against a write endpoint can create duplicate or partial threads if you do not track what already happened.
Basic Request
1curl --request POST \
2 --url https://api.twexapi.io/v3/twitter/tweets/create-thread \
3 --header "Authorization: Bearer $TWEXAPI_BEARER_TOKEN" \
4 --header "Content-Type: application/json" \
5 --data '{
6 "items": [
7 "1/ We just shipped a cleaner export flow for research teams.",
8 "2/ The new flow preserves the query, cursor, fetched_at timestamp, and raw tweet ID for every row.",
9 "3/ That makes audits easier: teams can explain where each result came from instead of trusting a spreadsheet with no source context."
10 ],
11 "cookie": "auth_token=...; ct0=...; twid=..."
12 }'A successful response returns code, msg, and data.tweets. Each item contains the created tweet id.
{
"code": 200,
"msg": "success",
"data": {
"tweets": [
{ "id": "1234567890123456789" },
{ "id": "1234567890123456790" },
{ "id": "1234567890123456791" }
]
}
}Save those IDs immediately. They are the bridge between the editorial draft, the published thread, analytics, reply monitoring, and any later deletion or correction workflow.
Python Publisher with an Approval Gate
The script below keeps credentials in environment variables and refuses to publish unless PUBLISH_THREAD=true is set. That small guard prevents local tests or CI previews from accidentally posting a live thread.
1import os
2from datetime import datetime, timezone
3from typing import Any
4
5import requests
6
7API_URL = "https://api.twexapi.io/v3/twitter/tweets/create-thread"
8BEARER_TOKEN = os.environ["TWEXAPI_BEARER_TOKEN"]
9X_COOKIE = os.environ["TWEXAPI_X_COOKIE"]
10PROXY = os.environ.get("TWEXAPI_PROXY")
11
12def validate_thread_items(items: list[str]) -> list[str]:
13 cleaned = []
14
15 for index, item in enumerate(items, start=1):
16 text = item.strip()
17 if not text:
18 raise ValueError(f"Thread item {index} is empty")
19 cleaned.append(text)
20
21 if not cleaned:
22 raise ValueError("Thread must contain at least one post")
23
24 return cleaned
25
26def create_tweet_thread(items: list[str]) -> dict[str, Any]:
27 payload: dict[str, Any] = {
28 "items": validate_thread_items(items),
29 "cookie": X_COOKIE,
30 }
31
32 if PROXY:
33 payload["proxy"] = PROXY
34
35 response = requests.post(
36 API_URL,
37 headers={
38 "Authorization": f"Bearer {BEARER_TOKEN}",
39 "Content-Type": "application/json",
40 "Accept": "application/json",
41 },
42 json=payload,
43 timeout=60,
44 )
45 response.raise_for_status()
46 data = response.json()
47
48 if data.get("code") != 200:
49 raise RuntimeError(data.get("msg", "TwexAPI returned an error"))
50
51 return data
52
53def normalize_result(draft_id: str, response: dict[str, Any]) -> dict[str, Any]:
54 tweets = response.get("data", {}).get("tweets") or []
55 return {
56 "draft_id": draft_id,
57 "published_at": datetime.now(timezone.utc).isoformat(),
58 "tweet_ids": [tweet.get("id") for tweet in tweets if tweet.get("id")],
59 "api_code": response.get("code"),
60 "api_msg": response.get("msg"),
61 "raw_response": response,
62 }
63
64if __name__ == "__main__":
65 draft_id = "launch-notes-2026-07-14"
66 thread_items = [
67 "1/ We just shipped a cleaner export flow for research teams.",
68 "2/ The new flow preserves the query, cursor, fetched_at timestamp, and raw tweet ID for every row.",
69 "3/ That makes audits easier: teams can explain where each result came from instead of trusting a spreadsheet with no source context.",
70 ]
71
72 reviewed_items = validate_thread_items(thread_items)
73
74 if os.environ.get("PUBLISH_THREAD") != "true":
75 print("Review mode only. Set PUBLISH_THREAD=true after approval.")
76 for number, text in enumerate(reviewed_items, start=1):
77 print(f"{number}: {text}")
78 raise SystemExit(0)
79
80 result = create_tweet_thread(reviewed_items)
81 print(normalize_result(draft_id, result))Run it from a server or trusted workstation:
TWEXAPI_BEARER_TOKEN="your_twexapi_bearer_token" \
TWEXAPI_X_COOKIE="auth_token=...; ct0=...; twid=..." \
PUBLISH_THREAD=true \
python publish_thread.pyIf your environment requires a proxy for the posting session, set TWEXAPI_PROXY as well.
A Practical Thread Workflow
The API call should be the last step in the publishing system. A reliable workflow usually looks like this:
- Draft: Store the thread as separate rows or blocks, not as one large paragraph.
- Validate: Check for empty posts, broken links, repeated numbering, and account-specific X posting limits.
- Approve: Require a human or campaign owner to mark the draft as ready.
- Publish: Call
POST /v3/twitter/tweets/create-threadonce for the approved version. - Record: Save the ordered
tweet_ids, the draft ID, publish time, and raw API response. - Monitor: Use the saved IDs for replies, engagement tracking, or correction decisions.
This is especially important for product launches. If the first post says "now live" but the third post contains the wrong link, you need an audit trail that explains which draft was approved and which tweet IDs were created.
Store Thread State
At minimum, keep a database row for the thread and a child row for each item.
| Field | Why it matters |
|---|---|
thread_draft_id | Connects the published thread back to the internal draft. |
account_id | Identifies which X account published the thread. |
position | Preserves thread order before and after publishing. |
text | Stores the approved text that was sent. |
tweet_id | Links the approved item to the created X post. |
status | Supports states such as draft, approved, published, and failed. |
published_at | Makes later analysis and incident review easier. |
raw_response | Preserves the original API evidence for debugging. |
Do not store the full cookie in this table. Store a reference to the credential record or secret name instead.
Retry and Failure Handling
Thread publishing is not the same as a read request. If a timeout happens after the API has already created one or more posts, blindly retrying the same payload can create duplicates.
Handle failures with a conservative process:
- Save the request payload hash before publishing.
- On success, save every returned tweet ID in order.
- On timeout or unknown failure, check the account manually or with a read endpoint before retrying.
- If the response contains fewer tweet IDs than expected, mark the thread for review instead of auto-retrying.
- Never run this endpoint from a browser or untrusted client because the request includes account credentials.
The goal is not to make posting "fully automatic." The goal is to make approved publishing reproducible and reviewable.
When To Use This Endpoint
Use the thread endpoint when the relationship between posts matters. Good examples include:
- product launch threads with feature details
- research summaries with evidence and caveats
- incident updates where every post should appear in order
- campaign narratives that need a hook, proof, and call to action
- educational threads that were already reviewed by an editor
For a single post, use the normal tweet creation endpoint. For long-form Markdown content, use X Article endpoints instead. A thread is best when each short post should be readable on its own while still belonging to a larger sequence.
Wrap-up
POST /v3/twitter/tweets/create-thread turns an approved ordered list of texts into a published X thread and returns the created tweet IDs. The strongest implementation is simple: validate the list, require approval, publish once, store the ordered IDs, and treat uncertain failures as review tasks.
That keeps thread automation useful without turning a write endpoint into an uncontrolled posting loop.