X(Twitter)發佈

了解如何連結 X(Twitter)帳號,並發佈含文字、圖片與影片的推文。

⚠️ 僅限 Ultra 方案。 連結 X 帳號所有方案皆可使用,但 發佈到 X 需要 Ultra 方案(價格為 Pro 的 2 倍)。Ultra 每月可發佈最多 60 則 X 貼文

連結 X 帳號

前置需求

連結步驟

  1. 在控制台按下 「Connect X (Twitter)」
  2. 於 X(Twitter)上 授權此應用程式
  3. 檢視並授予必要權限
    • tweet.read:讀取推文
    • tweet.write:發佈與刪除推文
    • users.read:讀取個人資料
    • media.write:上傳圖片與影片
    • offline.access:維持長期存取
  4. 點擊 「Authorize app」 完成連結

完成後,帳號會顯示於「Authorized Accounts」列表:

權杖資訊

支援的內容類型

X(Twitter)支援含多種媒體的推文:

功能 說明 是否必填 限制
文字 推文文字 否* 最多 280 字元
圖片 附加照片 最多 4 張,每張 5MB
影片 附加影片 最多 1 支,512MB

*必須包含文字或媒體至少一種

發佈範例

1. 純文字推文

{
  "post": {
    "accountId": "your-x-account-id",
    "content": {
      "text": "Hello from Boring API! 🚀 This is a text-only tweet. #API #Automation",
      "mediaUrls": [],
      "platform": "x"
    },
    "target": {
      "targetType": "x"
    }
  }
}

字數限制:文字超過 280 字元時會自動截斷。

2. 圖片推文(1-4 張)

{
  "post": {
    "accountId": "your-x-account-id",
    "content": {
      "text": "Check out these amazing photos! 📸\n\n#Photography #Travel",
      "mediaUrls": [
        "https://storage.example.com/photo1.jpg",
        "https://storage.example.com/photo2.jpg",
        "https://storage.example.com/photo3.jpg"
      ],
      "platform": "x"
    },
    "target": {
      "targetType": "x"
    }
  }
}

圖片規格

3. 影片推文

{
  "post": {
    "accountId": "your-x-account-id",
    "content": {
      "text": "New video tutorial! 🎥 Learn how to use our API in 5 minutes.\n\n#Tutorial #API #DevTools",
      "mediaUrls": ["https://storage.example.com/tutorial.mp4"],
      "platform": "x"
    },
    "target": {
      "targetType": "x"
    }
  }
}

影片規格

注意:同一則推文只能有 1 支影片,無法與圖片混用。

API 請求範例

Python 範例

import requests

API_URL = "https://boring.aiagent-me.com/v2/posts"
API_KEY = "boring_xxxxxxxxxxxxx"
ACCOUNT_ID = "your-x-account-id"

post_data = {
    "post": {
        "accountId": ACCOUNT_ID,
        "content": {
            "text": "Automated tweet via Boring API! 🤖 #API #Automation",
            "mediaUrls": [],
            "platform": "x"
        },
        "target": {
            "targetType": "x"
        }
    }
}

headers = {
    "boring-api-key": API_KEY,
    "Content-Type": "application/json"
}

response = requests.post(API_URL, headers=headers, json=post_data)
result = response.json()

if result.get("success"):
    print("Tweet posted successfully!")
    print(f"Tweet ID: {result['tweet_id']}")
    print(f"Tweet URL: {result['tweet_url']}")
else:
    print(f"Tweet failed: {result.get('error')}")

成功回應

{
  "success": true,
  "message": "Post published successfully",
  "postSubmissionId": "uuid-here",
  "platform": "x",
  "post_type": "photo",
  "tweet_id": "1234567890123456789",
  "tweet_url": "https://x.com/i/status/1234567890123456789",
  "media_count": 1
}

媒體上傳流程

媒體與推文都使用各連結帳號自己的 OAuth 2.0 token:

  1. 下載媒體:從提供的 URL 下載檔案
  2. OAuth 2.0 上傳:以連結帳號的 OAuth 2.0 token 透過 v2 /2/media/upload 上傳(需 media.write scope),媒體擁有者即為發文帳號
  3. 媒體處理:X 處理媒體(影片需較長時間)
  4. OAuth 2.0 發文:透過 v2 /2/tweets 發佈推文並附上媒體

影片處理

影片需要額外的處理時間:

[X] Uploading video in chunks...
[X] Upload progress: 33%
[X] Upload progress: 67%
[X] Upload progress: 100%
[X] Video processing status: pending
[X] Video processing status: processing
[X] Video processing status: succeeded
[X] Tweet posted successfully!

常見處理時間

文字長度與計數

280 字元限制

X 嚴格限制 280 字元,Boring 會自動協助:

# 超過 280 字元的文字
text = "This is a very long tweet..." * 50  # 超過 1000 字

# Boring 會自動截斷至 280 字元
post_data = {
    "post": {
        "accountId": ACCOUNT_ID,
        "content": {
            "text": text,
            "platform": "x"
        },
        "target": {"targetType": "x"}
    }
}

結果:文字將被截斷並保留前 280 字。

Unicode 與 Emoji

Emoji 與特殊字元計數方式不同:

範例:

"Hello 👋 World 🌍" = 14 字元(每個 emoji 2 字元)
"Check out https://example.com/very/long/url" ≈ 30 字元(URL 23 字元)

其他 API 範例

cURL

curl -X POST https://boring.aiagent-me.com/v2/posts \
  -H "boring-api-key: boring_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "post": {
      "accountId": "your-x-account-id",
      "content": {
        "text": "Testing the Boring API with X! 🚀 #API #Testing",
        "mediaUrls": [],
        "platform": "x"
      },
      "target": {
        "targetType": "x"
      }
    }
  }'

JavaScript / Node.js

const axios = require('axios');

const API_URL = 'https://boring.aiagent-me.com/v2/posts';
const API_KEY = 'boring_xxxxxxxxxxxxx';
const ACCOUNT_ID = 'your-x-account-id';

async function postTweet(text, mediaUrls = []) {
    const postData = {
        post: {
            accountId: ACCOUNT_ID,
            content: {
                text: text,
                mediaUrls: mediaUrls,
                platform: 'x'
            },
            target: {
                targetType: 'x'
            }
        }
    };

    try {
        const response = await axios.post(API_URL, postData, {
            headers: {
                'boring-api-key': API_KEY,
                'Content-Type': 'application/json'
            }
        });

        console.log('Tweet posted:', response.data);
        return response.data;
    } catch (error) {
        console.error('Error posting tweet:', error.response?.data || error.message);
        throw error;
    }
}

// 純文字推文
postTweet('Hello from Node.js! 👋 #NodeJS #API');

// 圖片推文
postTweet(
    'Check out this beautiful sunset! 🌅 #Photography',
    ['https://storage.example.com/sunset.jpg']
);

疑難排解

常見錯誤

錯誤:「Account is not an X (Twitter) account」

錯誤:「Too many media files」

錯誤:「Cannot mix images and videos」

錯誤:「Failed to upload media」

錯誤:「Video processing failed」

錯誤:「Token refresh failed」

最佳實務

  1. 保持簡潔:280 字內傳達重點
  2. 善用 Hashtag:建議 2-3 個相關標籤
  3. 優化圖片:使用高品質 JPG/PNG
  4. 壓縮影片:盡量小於 50MB,加快上傳
  5. 先測試 URL:確認媒體可正常存取
  6. 注意速率限制:適度錯開發文時間
  7. 預覽推文:於控制台預覽後再發佈

速率限制

X API 速率限制(以每位使用者計):

Boring 會偵測速率限制並回傳對應錯誤。

Boring Ultra 方案上限: X 發佈每月每位使用者上限 60 則(每月初重置,跨你所有連結的 X 帳號合計)。超過會回傳 X_MONTHLY_LIMIT_EXCEEDED(HTTP 429)。

發佈歷史

在控制台查看所有推文:

  1. 登入 Boring 控制台
  2. 捲動至 「Publish History」 區塊
  3. 篩選平台為 X

每筆紀錄會顯示:

進階功能

多個 X 帳號

在同一個 Boring 帳戶連結多組 X 帳號:

# 帳號 1:個人 (@john_personal)
personal_account_id = "account-id-1"

# 帳號 2:商務 (@john_business)
business_account_id = "account-id-2"

# 發佈到個人帳號
post_to_account(personal_account_id, "Personal tweet! 👋")

# 發佈到商務帳號
post_to_account(business_account_id, "Business announcement! 📢")

批次發佈

程式化發佈多則推文:

tweets = [
    {"text": "Tweet 1: Introduction 👋", "media": []},
    {"text": "Tweet 2: Key features 🚀", "media": ["feature.jpg"]},
    {"text": "Tweet 3: Final thoughts 💭", "media": []}
]

for tweet in tweets:
    post_data = {
        "post": {
            "accountId": ACCOUNT_ID,
            "content": {
                "text": tweet["text"],
                "mediaUrls": tweet["media"],
                "platform": "x"
            },
            "target": {"targetType": "x"}
        }
    }

    response = requests.post(API_URL, headers=headers, json=post_data)
    print(f"Posted: {tweet['text']} - {response.json()}")

    # 間隔發文避免速率限制
    time.sleep(60)

安全性提醒

速查表

純文字推文

{
  "post": {
    "accountId": "your-account-id",
    "content": {
      "text": "Hello World! 🌍",
      "platform": "x"
    },
    "target": {"targetType": "x"}
  }
}

圖片推文

{
  "post": {
    "accountId": "your-account-id",
    "content": {
      "text": "Check this out! 📸",
      "mediaUrls": ["https://example.com/image.jpg"],
      "platform": "x"
    },
    "target": {"targetType": "x"}
  }
}

影片推文

{
  "post": {
    "accountId": "your-account-id",
    "content": {
      "text": "Watch this! 🎥",
      "mediaUrls": ["https://example.com/video.mp4"],
      "platform": "x"
    },
    "target": {"targetType": "x"}
  }
}

下一步