Документация API
Обзор
API BotBell позволяет вашим программам и скриптам отправлять push-уведомления на устройства Apple и получать ответы. SDK не требуется — только простые HTTP-запросы.
Base URL: https://api.botbell.appКак это работает
- Создайте бота в приложении BotBell и скопируйте его URL для push-сообщений
- Отправьте JSON-сообщение POST-запросом на URL для push-сообщений из любого языка или инструмента
- Получите мгновенное push-уведомление на всех ваших устройствах
- При необходимости получайте ваши ответы через URL обратного вызова или API опроса
Формат ответа
Все ответы API используют единую JSON-обёртку. Код 0 означает успех; любой другой код указывает на ошибку.
// Success
{
"code": 0,
"message": "success",
"data": { ... }
}
// Error
{
"code": 40001,
"message": "Invalid bot token"
}Отправить сообщение
Отправьте уведомление от вашего бота в приложение BotBell. URL для push-сообщений вашего бота уже содержит токен аутентификации — просто отправьте 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 | Уникальный идентификатор этого сообщения |
delivered | true, если push-уведомление было успешно отправлено в APNs; false, если нет зарегистрированного устройства |
timestamp | Unix-метка времени (секунды) создания сообщения |
Попробовать сейчас
Вставьте токен вашего бота и отправьте реальное push-уведомление на ваше устройство.
Получение ответов
Когда вы отвечаете боту в приложении, BotBell может автоматически переслать ваш ответ на ваш сервер. Это опционально — вам это нужно только если ваш бот поддерживает двустороннюю переписку.
Настройка URL обратного вызова
В приложении BotBell перейдите в настройки бота и введите URL обратного вызова (например, https://your-server.com/botbell/reply). BotBell будет отправлять POST-запросы с вашими ответами на этот URL по мере их поступления.
Полезная нагрузка обратного вызова
Когда вы отвечаете, BotBell отправляет POST-запрос на ваш URL обратного вызова в следующем формате:
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. Ключом подписи является секрет Webhook, указанный в настройках вашего бота.
signature = HMAC-SHA256(
key: <your_webhook_secret>,
message: "<timestamp>.<raw_request_body>"
)Для проверки подписи:
- Извлеките заголовки X-Webhook-Timestamp и X-Webhook-Signature
- Убедитесь, что временная метка не старше 5 минут (для защиты от атак повторного воспроизведения)
- Вычислите HMAC-SHA256 от строки "<timestamp>.<raw_body>", используя секрет Webhook в качестве ключа
- Сравните вычисленное значение с подписью после префикса "sha256="
Ответ вашего сервера
Верните любой HTTP-код 2xx для подтверждения получения. Ответы с кодом, отличным от 2xx, или тайм-ауты (5 секунд) считаются ошибками — ответ будет сохранён в очереди опроса на 24 часа, чтобы вы могли получить его позже.
Опрос ответов
Если у вас нет публичного сервера для приёма обратных вызовов, вы можете получать ответы через опрос. Это также полезно в качестве запасного варианта, когда ваш 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 | Неверный или отсутствующий токен бота |
| 40010 | 400 | Ошибка валидации запроса (например, отсутствует поле message, тело слишком большое) |
| 40029 | 429 | Превышен лимит запросов — слишком много запросов в минуту |
| 40030 | 429 | Исчерпана месячная квота сообщений |
| 40031 | 403 | Достигнут лимит ботов для вашего тарифа |
| 50000 | 500 | Внутренняя ошибка сервера |
Ограничения и квоты
| Ограничение | Значение |
|---|---|
| Частота push (на бота) | 60 |
| Тело сообщения (символы) | 4,096 |
| Заголовок (символы) | 256 |
| Бесплатная месячная квота | 300 сообщений / бот |
| Хранение сообщений опроса | 24h |
| Тайм-аут URL обратного вызова | 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),
);
}