TwexAPI で XChat DM を送信する方法
DM 送信は write action です。重要なのは request library ではなく、送信前後の workflow です。誰が承認した message なのか、どの account で送るのか、recipient は到達可能なのか、返却された message ID をどこに保存するのかを決める必要があります。
TwexAPI の Send DM (XChat v3) endpoint は、XChat encrypted chat API 経由で DM を送信します。recipient には 1:1 の user ID または @handle、既存 group conversation の g... group ID を指定できます。media_urls で画像 1 枚、または video_url で動画 1 本を添付できます。
承認済みの support follow-up、creator operations、partner communication、CRM task に使うのが適切です。blind bulk-send loop を作る用途ではありません。
Endpoint と Request Fields
アプリケーションに承認済み message がある場合、POST /v3/twitter/send-dm を使います。
| Field | Type | Required | Notes |
|---|---|---|---|
recipient | string | Yes | X user ID、@handle、または g... で始まる既存 group ID。 |
text | string | Yes | message body。送信前に validation します。 |
cookie | string | Yes | X authentication cookie または auth_token。server-side に保存します。 |
media_urls | string array or null | No | 画像 1 枚の public URL。最大 1 件。video_url と同時指定不可。 |
video_url | string or null | No | 動画 1 本の public http(s) URL。media_urls と同時指定不可。 |
pin | string or null | No | Identity PIN。API default は 1234。設定している場合は secure env から読みます。 |
proxy | string or null | No | 送信 session 用の optional HTTP proxy。 |
Docs では、この endpoint は $0.0025 per call と記載されています。これは call price であり、review なしに送ってよいという意味ではありません。
Basic Request
curl --request POST \
--url https://api.twexapi.io/v3/twitter/send-dm \
--header "Authorization: Bearer $TWEXAPI_BEARER_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"recipient": "@example_user",
"text": "Export issue の件、ありがとうございます。修正を出したので、最新 run の確認をお手伝いできます。",
"cookie": "auth_token=...; ct0=...; twid=...",
"pin": "1234"
}'成功すると data に message object が返ります。
1{
2 "code": 200,
3 "msg": "success",
4 "data": {
5 "id": "1234567890123456789",
6 "text": "Export issue の件、ありがとうございます。",
7 "time": "2024-01-01T12:00:00Z",
8 "attachment": null,
9 "attachments": null,
10 "sequence_id": "2076661179334979585",
11 "sender_id": "1234567890123456789",
12 "recipient_id": "9876543210987654321"
13 }
14}少なくとも data.id、sequence_id、sender_id、recipient_id、time、raw response を保存します。CRM action、support ticket、後続の conversation history を合わせるために必要です。
Approval State 付き Python Client
下の script は credentials を environment variables から読み、request を validate し、draft が approved の場合だけ送信します。
1import os
2from datetime import datetime, timezone
3from typing import Any
4
5import requests
6
7API_URL = "https://api.twexapi.io/v3/twitter/send-dm"
8BEARER_TOKEN = os.environ["TWEXAPI_BEARER_TOKEN"]
9X_COOKIE = os.environ["TWEXAPI_X_COOKIE"]
10XCHAT_PIN = os.environ.get("TWEXAPI_XCHAT_PIN", "1234")
11PROXY = os.environ.get("TWEXAPI_PROXY")
12
13def validate_dm_payload(
14 recipient: str,
15 text: str,
16 *,
17 media_urls: list[str] | None = None,
18 video_url: str | None = None,
19) -> None:
20 if not recipient or not recipient.strip():
21 raise ValueError("recipient is required")
22 if not text or not text.strip():
23 raise ValueError("text is required")
24 if media_urls and video_url:
25 raise ValueError("media_urls and video_url are mutually exclusive")
26 if media_urls and len(media_urls) > 1:
27 raise ValueError("media_urls supports at most one image")
28
29def send_xchat_dm(
30 recipient: str,
31 text: str,
32 *,
33 media_urls: list[str] | None = None,
34 video_url: str | None = None,
35) -> dict[str, Any]:
36 validate_dm_payload(
37 recipient,
38 text,
39 media_urls=media_urls,
40 video_url=video_url,
41 )
42
43 payload: dict[str, Any] = {
44 "recipient": recipient.strip(),
45 "text": text.strip(),
46 "cookie": X_COOKIE,
47 "pin": XCHAT_PIN,
48 }
49
50 if media_urls:
51 payload["media_urls"] = media_urls
52 if video_url:
53 payload["video_url"] = video_url
54 if PROXY:
55 payload["proxy"] = PROXY
56
57 response = requests.post(
58 API_URL,
59 headers={
60 "Authorization": f"Bearer {BEARER_TOKEN}",
61 "Content-Type": "application/json",
62 "Accept": "application/json",
63 },
64 json=payload,
65 timeout=60,
66 )
67 response.raise_for_status()
68 data = response.json()
69
70 if data.get("code") != 200:
71 raise RuntimeError(data.get("msg", "TwexAPI returned an error"))
72
73 return data
74
75def normalize_send_result(
76 draft: dict[str, Any],
77 response: dict[str, Any],
78) -> dict[str, Any]:
79 message = response.get("data") or {}
80 return {
81 "draft_id": draft["draft_id"],
82 "recipient": draft["recipient"],
83 "message_id": message.get("id"),
84 "sequence_id": message.get("sequence_id"),
85 "sender_id": message.get("sender_id"),
86 "recipient_id": message.get("recipient_id"),
87 "sent_at": message.get("time") or datetime.now(timezone.utc).isoformat(),
88 "api_code": response.get("code"),
89 "api_msg": response.get("msg"),
90 "raw_response": response,
91 }
92
93if __name__ == "__main__":
94 draft = {
95 "draft_id": "support-followup-1042",
96 "recipient": "@example_user",
97 "text": "Export issue の件、ありがとうございます。修正を出したので、最新 run の確認をお手伝いできます。",
98 "status": "approved",
99 }
100
101 if draft["status"] != "approved":
102 raise ValueError("DM draft must be approved before sending")
103
104 result = send_xchat_dm(draft["recipient"], draft["text"])
105 print(normalize_send_result(draft, result))server または trusted workstation で実行します。
TWEXAPI_BEARER_TOKEN="your_twexapi_bearer_token" \
TWEXAPI_X_COOKIE="auth_token=...; ct0=...; twid=..." \
TWEXAPI_XCHAT_PIN="1234" \
python send_xchat_dm.pybrowser や client-side app から呼ばないでください。request には account credentials が含まれ、実際に message が送信されます。
Sending Images or Videos
XChat v3 では、同じ DM に画像 1 枚または動画 1 本を添付できます。この 2 つの fields は mutually exclusive です。
image_result = send_xchat_dm(
"@example_user",
"先ほどの screenshot です。",
media_urls=["https://example.com/screenshot.jpg"],
)video_result = send_xchat_dm(
"@example_user",
"短い walkthrough です。",
video_url="https://example.com/walkthrough.mp4",
)media URL は public で、送信処理が完了するまで安定している必要があります。expiring signed URL を使う場合は送信直前に生成し、log には redacted version だけを残します。
Put It After a Reachability Check
安全な workflow は、reachability check、message approval、send、result writeback の順です。
- Preflight: reachability snapshot が必要なら、username または user ID に対して
POST /v2/dm/statusを呼びます。 - Draft:
recipient、message text、attachment choice、sender account、source workflow、owner を保存します。 - Approve: write endpoint を呼ぶ前に、人手または rule-based approval を必須にします。
- Send: 承認済み draft に対して
POST /v3/twitter/send-dmを 1 回だけ呼びます。 - Record:
message_id、sequence_id、sender、recipient、send time、raw response を保存します。 - Follow up: 保存した ID を ticket、CRM contact、campaign record に紐づけます。
これにより、各 message に送信理由が残ります。failure の原因も、recipient、content、media、cookie、platform state のどれに近いか判断しやすくなります。
Store DM State
production では message table と credential storage を分けます。
| Field | Why it matters |
|---|---|
dm_draft_id | sent message を approved draft に戻せます。 |
recipient_input | 元の @handle、user ID、group ID を保持します。 |
sender_account_id | どの X account が送信したかを識別します。 |
message_text | 承認済み本文を保存します。 |
attachment_kind | no media、image、video を区別します。 |
message_id | 返却された XChat message ID。 |
sequence_id | 後続の conversation pagination に使える場合があります。 |
sent_at | CRM、support、audit timeline に使います。 |
status | approved、sent、failed、needs_review を追跡します。 |
raw_response | original API evidence を保存します。 |
message row に full cookie を保存しないでください。secret reference または account credential ID を保存します。
Common Mistakes
- recipient が reachable か確認せず送信する。
@handleを permanent identity として扱う。可能なら返却されたrecipient_idを保存する。media_urlsとvideo_urlを同時に渡す。media_urlsに複数画像を渡す。- account cookie、auth token、full signed media URL を logs に出す。
- message が既に送信されたか確認せず unknown failure を retry する。
unknown timeout では、retry 前に conversation state を確認します。2 回目の送信は duplicate message になる可能性があります。
Wrap-up
POST /v3/twitter/send-dm は、TwexAPI で XChat v3 DM を送信する endpoint です。1:1 recipient と既存 group をサポートします。production pattern は明確です。必要に応じて reachability を確認し、draft を承認し、1 回だけ送信し、返却 message object を保存し、不確かな failure は review に回します。
これにより、DM automation の効率を保ちながら uncontrolled messaging を避けられます。