Skip to content

API 文件

概述

BotBell API 讓你的程式和腳本能夠向你的 Apple 裝置傳送推送通知並接收回覆。無需 SDK——只需簡單的 HTTP 請求即可。

Base URL: https://api.botbell.app

工作流程

  1. 在 BotBell 應用程式中建立一個 Bot,複製其推送 URL
  2. 用任何語言或工具向推送 URL 傳送 JSON 訊息
  3. 在你的所有裝置上即時收到推送通知
  4. 可選:透過回覆回呼或輪詢 API 接收你的回覆

回應格式

所有 API 回應使用統一的 JSON 信封格式。code 為 0 表示成功,其他值表示錯誤。

// Success
{
  "code": 0,
  "message": "success",
  "data": { ... }
}

// Error
{
  "code": 40001,
  "message": "Invalid bot token"
}

推送訊息

從你的 Bot 向 BotBell 應用程式傳送通知。Bot 的推送 URL 已包含認證權杖——直接 POST 即可。

介面位址

POST https://api.botbell.app/v1/push/<your_bot_token>

無需 Authorization 請求標頭。URL 中的權杖就是你的認證憑證。

你也可以使用 POST /v1/messages/push 並攜帶 X-Bot-Token: <token> 請求標頭。

請求主體(JSON)

欄位類型必填說明
messagestring訊息正文(最多 4,096 個字元)
titlestring顯示在訊息上方的標題(最多 256 個字元)
urlstring附加在通知上的可點擊連結
imageUrlstring通知中展示的圖片 URL

請求範例

curl
curl -X POST https://api.botbell.app/v1/push/bt_your_token \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Server CPU is at 95%!",
    "title": "Alert",
    "url": "https://grafana.example.com/dashboard"
  }'

回應

{
  "code": 0,
  "message": "success",
  "data": {
    "message_id": "msg_abc123",
    "delivered": true,
    "timestamp": 1709827200
  }
}
欄位說明
message_id此訊息的唯一 ID
delivered如果推送通知已成功傳送到 APNs 則為 true;如果沒有已註冊的裝置則為 false
timestamp訊息建立時的 Unix 時間戳(秒)

線上試用

貼上你的 Bot Token,直接向你的裝置傳送一則真實推播通知。


接收回覆

當你在應用程式中回覆 Bot 時,BotBell 可以自動將回覆轉發到你的伺服器。這是可選功能——只有在你的 Bot 需要處理雙向對話時才需要設定。

設定回覆回呼地址

在 BotBell 應用程式中,進入 Bot 設定頁,輸入一個回覆 URL(例如 https://your-server.com/botbell/reply)。你回覆時 BotBell 會即時 POST 到此地址。

回呼酬載

當你回覆時,BotBell 會向你的回覆 URL 傳送以下格式的 POST 請求:

POST https://your-server.com/botbell/reply
Headers:
  Content-Type: application/json
  X-Webhook-Signature: sha256=abc123...
  X-Webhook-Timestamp: 1709827300

Body:
{
  "event": "user_reply",
  "bot_id": "bot_abc123",
  "message_id": "msg_xyz789",
  "content": "Got it, thanks!",
  "timestamp": 1709827300
}

簽章驗證

每次回呼都包含 HMAC-SHA256 簽章,用於驗證請求確實來自 BotBell。簽章金鑰是 Bot 設定中展示的 Webhook Secret。

signature = HMAC-SHA256(
  key:     <your_webhook_secret>,
  message: "<timestamp>.<raw_request_body>"
)

驗證簽章的步驟:

  1. 從請求標頭中擷取 X-Webhook-Timestamp 和 X-Webhook-Signature
  2. 檢查時間戳與目前時間差不超過 5 分鐘(防止重放攻擊)
  3. 使用 Webhook Secret 作為金鑰,對字串 "<timestamp>.<raw_body>" 計算 HMAC-SHA256
  4. 將計算結果與簽章中 "sha256=" 後面的值進行比較

你的伺服器回應

回傳任意 HTTP 2xx 狀態碼表示接收成功。非 2xx 回應或逾時(5 秒)將被視為投遞失敗——回覆會存入輪詢佇列保留 24 小時,你可以稍後透過輪詢 API 取得。


輪詢取得回覆

如果你沒有可接收回呼的公網伺服器,可以改用輪詢方式取得回覆。當你的回覆 URL 暫時無法使用時,輪詢也可以作為備用方案。

介面位址

GET https://api.botbell.app/v1/messages/poll
Headers:
  X-Bot-Token: <your_bot_token>

查詢參數

欄位類型預設值說明
sinceinteger-僅回傳此 Unix 時間戳之後的訊息
limitinteger20回傳的訊息筆數(最大 100)

回應

{
  "code": 0,
  "message": "success",
  "data": {
    "messages": [
      {
        "message_id": "msg_xyz789",
        "content": "Got it, thanks!",
        "timestamp": 1709827300
      }
    ],
    "has_more": false
  }
}

注意: 已輪詢的訊息會被標記為已讀,不會重複回傳。未輪詢的訊息在 24 小時後自動過期。


錯誤代碼

代碼HTTP 狀態碼說明
40001401無效或缺少 Bot 權杖
40010400請求驗證失敗(如缺少 message 欄位、請求主體過大等)
40029429超出速率限制——每分鐘請求數過多
40030429每月訊息額度已用盡
40031403目前方案的 Bot 數量已達上限
50000500伺服器內部錯誤

速率限制與配額

限制項
推送速率(每個 Bot)60
訊息正文(字元數)4,096
標題(字元數)256
每月免費額度每個 Bot 300 則訊息
輪詢訊息保留時長24h
回覆回呼逾時時間5s

速率限制狀態會在回應標頭中回傳:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1709827260

程式碼範例

傳送訊息

curl
curl -X POST https://api.botbell.app/v1/push/bt_your_token \
  -H "Content-Type: application/json" \
  -d '{"message":"Server CPU at 95%","title":"Alert"}'
Python
import requests

resp = requests.post(
    "https://api.botbell.app/v1/push/bt_your_token",
    json={
        "message": "Build #42 succeeded",
        "title": "CI/CD",
        "url": "https://ci.example.com/builds/42",
    },
)
print(resp.json())  # {"code": 0, "data": {"message_id": "...", ...}}
JavaScript / Node.js
const resp = await fetch("https://api.botbell.app/v1/push/bt_your_token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    message: "New order received!",
    title: "E-Commerce",
  }),
});
const data = await resp.json();
console.log(data);
Go
package main

import (
    "bytes"
    "encoding/json"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]string{
        "message": "Disk usage above 90%",
        "title":   "Alert",
    })
    http.Post(
        "https://api.botbell.app/v1/push/bt_your_token",
        "application/json",
        bytes.NewReader(body),
    )
}
PHP
<?php
$ch = curl_init('https://api.botbell.app/v1/push/bt_your_token');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'message' => 'Payment received: $49.99',
        'title' => 'Stripe',
    ]),
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);

驗證回覆簽章

Python
import hmac, hashlib

def verify_signature(payload: bytes, timestamp: str, signature: str, secret: str) -> bool:
    message = f"{timestamp}.{payload.decode()}"
    expected = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
Node.js
const crypto = require("crypto");

function verifySignature(payload, timestamp, signature, secret) {
  const message = `${timestamp}.${payload}`;
  const expected = crypto.createHmac("sha256", secret).update(message).digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(`sha256=${expected}`),
    Buffer.from(signature),
  );
}