Skip to content

API ドキュメント

概要

BotBell API を使えば、プログラムやスクリプトから Apple デバイスにプッシュ通知を送信し、返信を受け取ることができます。SDK は不要——シンプルな HTTP リクエストだけで利用できます。

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

仕組み

  1. BotBell アプリで Bot を作成し、プッシュ URL をコピーします
  2. 任意の言語やツールからプッシュ URL に JSON メッセージを POST します
  3. すべてのデバイスで即座にプッシュ通知を受け取ります
  4. オプションとして、返信コールバック URL またはポーリング 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/pushX-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
deliveredAPNs へのプッシュ通知送信が成功した場合は true、登録済みデバイスがない場合は false
timestampメッセージが作成された Unix タイムスタンプ(秒)

今すぐ試す

Bot Token を貼り付けて、デバイスにリアルなプッシュ通知を送信しましょう。


返信の受信

アプリで Bot に返信すると、BotBell はその返信を自動的にサーバーに転送できます。これはオプションです——Bot が双方向の会話を処理する場合にのみ必要です。

返信コールバック URL の設定

BotBell アプリで Bot の設定に移動し、返信コールバック URL(例:https://your-server.com/botbell/reply)を入力してください。BotBell はあなたの返信をリアルタイムでこの URL に 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 時間保存され、後で取得できます。


返信のポーリング

コールバックを受信するための公開サーバーがない場合、代わりに返信をポーリングで取得できます。返信コールバック 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 ステータス説明
40001401Bot トークンが無効または欠落しています
40010400リクエストの検証に失敗しました(例:message フィールドの欠落、ボディが大きすぎる)
40029429レート制限を超過しました——1 分あたりのリクエスト数が多すぎます
40030429月間メッセージクォータを使い果たしました
40031403プランの Bot 数上限に達しました
50000500内部サーバーエラー

レート制限とクォータ

制限
プッシュレート(Bot ごと)60
メッセージ本文(文字数)4,096
タイトル(文字数)256
月間無料枠Bot あたり 300 メッセージ
ポーリングメッセージの保持期間24h
返信コールバック URL のタイムアウト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),
  );
}