وثائق API
نظرة عامة
تتيح واجهة BotBell API لبرامجك ونصوصك البرمجية إرسال إشعارات فورية إلى أجهزة Apple الخاصة بك واستقبال الردود. لا حاجة لـ SDK — فقط طلبات HTTP بسيطة.
Base URL: https://api.botbell.appكيف يعمل
- أنشئ بوتاً في تطبيق BotBell وانسخ رابط الإرسال الخاص به
- أرسل رسالة JSON عبر POST إلى رابط الإرسال من أي لغة أو أداة
- استلم إشعاراً فورياً على جميع أجهزتك
- اختيارياً، استقبل ردودك عبر رد اتصال عنوان URL للرد أو API الاستطلاع
صيغة الاستجابة
جميع استجابات API تستخدم نفس غلاف JSON. الرمز 0 يعني النجاح؛ أي رمز آخر يشير إلى خطأ.
// Success
{
"code": 0,
"message": "success",
"data": { ... }
}
// Error
{
"code": 40001,
"message": "Invalid bot token"
}إرسال رسالة
أرسل إشعاراً من بوتك إلى تطبيق BotBell. رابط الإرسال الخاص ببوتك يحتوي بالفعل على توكن المصادقة — فقط أرسل POST إليه.
نقطة النهاية
POST https://api.botbell.app/v1/push/<your_bot_token>لا حاجة لترويسة Authorization. التوكن في الرابط هو مصادقتك.
يمكنك أيضاً استخدام 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 إذا تم إرسال الإشعار إلى APNs بنجاح؛ false إذا لم يكن هناك جهاز مسجّل |
timestamp | طابع زمني Unix (بالثواني) عند إنشاء الرسالة |
جرّب الآن
الصق رمز البوت الخاص بك وأرسل إشعارًا فوريًا حقيقيًا إلى جهازك.
استقبال الردود
عندما ترد على بوت في التطبيق، يمكن لـ BotBell توجيه ردك إلى خادمك تلقائياً. هذا اختياري — تحتاجه فقط إذا كان بوتك يتعامل مع محادثات ثنائية الاتجاه.
إعداد عنوان URL للرد
في تطبيق BotBell، انتقل إلى إعدادات بوتك وأدخل عنوان URL للرد (مثلاً https://your-server.com/botbell/reply). سيرسل BotBell ردودك إلى هذا العنوان عبر POST فور حدوثها.
حمولة رد الاتصال
عندما ترد، يرسل 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 | فشل التحقق من الطلب (مثلاً حقل الرسالة مفقود أو الجسم كبير جداً) |
| 40029 | 429 | تم تجاوز حد المعدل — طلبات كثيرة جداً في الدقيقة |
| 40030 | 429 | تم استنفاد حصة الرسائل الشهرية |
| 40031 | 403 | تم الوصول إلى حد البوتات لخطتك |
| 50000 | 500 | خطأ داخلي في الخادم |
حدود المعدل والحصص
| الحد | القيمة |
|---|---|
| معدل الإرسال (لكل بوت) | 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),
);
}