API 文件
概述
BotBell API 讓你的程式和腳本能夠向你的 Apple 裝置傳送推送通知並接收回覆。無需 SDK——只需簡單的 HTTP 請求即可。
Base URL: https://api.botbell.app工作流程
- 在 BotBell 應用程式中建立一個 Bot,複製其推送 URL
- 用任何語言或工具向推送 URL 傳送 JSON 訊息
- 在你的所有裝置上即時收到推送通知
- 可選:透過回覆回呼或輪詢 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)
| 欄位 | 類型 | 必填 | 說明 |
|---|---|---|---|
message | string | 是 | 訊息正文(最多 4,096 個字元) |
title | string | 否 | 顯示在訊息上方的標題(最多 256 個字元) |
url | string | 否 | 附加在通知上的可點擊連結 |
imageUrl | string | 否 | 通知中展示的圖片 URL |
請求範例
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>"
)驗證簽章的步驟:
- 從請求標頭中擷取 X-Webhook-Timestamp 和 X-Webhook-Signature
- 檢查時間戳與目前時間差不超過 5 分鐘(防止重放攻擊)
- 使用 Webhook Secret 作為金鑰,對字串 "<timestamp>.<raw_body>" 計算 HMAC-SHA256
- 將計算結果與簽章中 "sha256=" 後面的值進行比較
你的伺服器回應
回傳任意 HTTP 2xx 狀態碼表示接收成功。非 2xx 回應或逾時(5 秒)將被視為投遞失敗——回覆會存入輪詢佇列保留 24 小時,你可以稍後透過輪詢 API 取得。
輪詢取得回覆
如果你沒有可接收回呼的公網伺服器,可以改用輪詢方式取得回覆。當你的回覆 URL 暫時無法使用時,輪詢也可以作為備用方案。
介面位址
GET https://api.botbell.app/v1/messages/poll
Headers:
X-Bot-Token: <your_bot_token>查詢參數
| 欄位 | 類型 | 預設值 | 說明 |
|---|---|---|---|
since | integer | - | 僅回傳此 Unix 時間戳之後的訊息 |
limit | integer | 20 | 回傳的訊息筆數(最大 100) |
回應
{
"code": 0,
"message": "success",
"data": {
"messages": [
{
"message_id": "msg_xyz789",
"content": "Got it, thanks!",
"timestamp": 1709827300
}
],
"has_more": false
}
}注意: 已輪詢的訊息會被標記為已讀,不會重複回傳。未輪詢的訊息在 24 小時後自動過期。
錯誤代碼
| 代碼 | HTTP 狀態碼 | 說明 |
|---|---|---|
| 40001 | 401 | 無效或缺少 Bot 權杖 |
| 40010 | 400 | 請求驗證失敗(如缺少 message 欄位、請求主體過大等) |
| 40029 | 429 | 超出速率限制——每分鐘請求數過多 |
| 40030 | 429 | 每月訊息額度已用盡 |
| 40031 | 403 | 目前方案的 Bot 數量已達上限 |
| 50000 | 500 | 伺服器內部錯誤 |
速率限制與配額
| 限制項 | 值 |
|---|---|
| 推送速率(每個 Bot) | 60 |
| 訊息正文(字元數) | 4,096 |
| 標題(字元數) | 256 |
| 每月免費額度 | 每個 Bot 300 則訊息 |
| 輪詢訊息保留時長 | 24h |
| 回覆回呼逾時時間 | 5s |
速率限制狀態會在回應標頭中回傳:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1709827260程式碼範例
傳送訊息
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"}'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": "...", ...}}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);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
$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);驗證回覆簽章
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)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),
);
}