الأخطاء
كل خطأ يرجع بنفس الشكل، وكود HTTP مناسب، و code ثابت تعتمد عليه في برنامجك:
{
"statusCode": 422,
"code": "outside_24h_window",
"message": "(#131047) Re-engagement message",
"request_id": "9fb64a88-f0f1-4a36-a1e8-0ba3eef81360"
}
- اعتمد على
code وليس على message، لأن نص الرسالة قد يتغير أو يُترجم.
request_id يرجع أيضاً في الهيدر X-Request-Id. احفظه في سجلاتك وأرسله لنا عند طلب المساعدة.
- أخطاء واتساب فيها حقل إضافي
meta_error بتفاصيل Meta الأصلية (code و subcode و message و details).
- أخطاء التحقق فيها
errors: كائن بأسماء الحقول الخاطئة وسبب كل منها.
#متى أعيد المحاولة؟
| كود HTTP |
المعنى |
أعيد المحاولة؟ |
| 400 |
البيانات المرسلة غير صحيحة |
لا. صحح البيانات |
| 401 |
المفتاح ناقص أو خاطئ |
لا. صحح المفتاح |
| 403 |
غير مسموح (صلاحية، اشتراك، حد الباقة، حساب واتساب) |
لا، حتى يتغير السبب |
| 404 |
العنصر غير موجود |
لا |
| 409 |
طلب بنفس Idempotency-Key ما زال يُنفذ |
نعم بعد ثانية |
| 422 |
واتساب رفضت الرسالة، أو بيانات غير منطقية |
لا، إلا لو تغير الوضع (مثلاً راسلك العميل فانفتحت النافذة) |
| 429 |
تجاوزت حداً |
نعم، بعد انتظار متزايد |
| 500 |
خطأ عندنا |
نعم بعد قليل، وأرسل لنا request_id لو تكرر |
| 502 |
لم نستطع الوصول لخوادم واتساب |
نعم بعد قليل |
#الأكواد العامة
| HTTP |
code |
السبب |
الحل |
| 400 |
validation_error |
حقل ناقص أو بصيغة خاطئة. التفاصيل في errors |
صحح الحقول المذكورة |
| 401 |
bearer_token_missing |
لا يوجد هيدر Authorization |
أرسل Authorization: Bearer <key> |
| 401 |
bearer_token_invalid |
المفتاح خاطئ أو مُلغى أو دُوّر |
انسخ المفتاح الصحيح |
| 403 |
api_key_scope_denied |
صلاحية المفتاح لا تسمح بهذا الطلب |
استخدم مفتاحاً بصلاحية مناسبة |
| 403 |
subscription_inactive |
اشتراك المؤسسة منتهٍ |
جدّد الاشتراك |
| 404 |
not_found |
uuid غير موجود في مؤسستك |
تأكد من المعرّف |
| 409 |
idempotency_in_progress |
طلب بنفس المفتاح لم ينتهِ |
انتظر وأعد |
| 422 |
idempotency_key_reused |
نفس Idempotency-Key مع بيانات مختلفة |
استخدم مفتاحاً جديداً لكل رسالة مختلفة |
| 429 |
rate_limited |
طلبات كثيرة في الدقيقة |
انتظر ثم أعد |
| 500 |
server_error |
خطأ غير متوقع |
أعد المحاولة، وراسلنا بـ request_id |
#حدود الباقة والحساب
| HTTP |
code |
السبب |
| 403 |
message_limit_reached |
وصلت لحد الرسائل في دورة الاشتراك الحالية |
| 403 |
contacts_limit_reached |
وصلت لحد جهات الاتصال (والرقم غير موجود مسبقاً) |
| 403 |
campaign_limit_reached |
وصلت لحد الحملات |
| 403 |
canned_replies_limit_reached |
وصلت لحد الردود التلقائية |
| 403 |
whatsapp_not_connected |
لم يُربط رقم واتساب بالمؤسسة |
#إرسال الرسائل (أسباب من واتساب)
| HTTP |
code |
كود Meta |
السبب |
الحل |
| 422 |
outside_24h_window |
131047 |
مرت 24 ساعة على آخر رسالة من العميل |
أرسل قالباً |
| 422 |
recipient_unavailable |
131026 |
الرقم ليس عليه واتساب، أو لا يستقبل |
تأكد من الرقم |
| 422 |
recipient_is_sender |
131021 |
ترسل لنفس رقمك |
استخدم رقماً آخر |
| 422 |
display_name_not_approved |
131037 |
اسم العرض لم توافق عليه Meta |
من WhatsApp Manager |
| 422 |
meta_payment_issue |
131042 |
لا توجد وسيلة دفع في حساب Meta |
أضف وسيلة دفع في Meta Business |
| 422 |
meta_ecosystem_limited |
131049 |
Meta لم ترسل الرسالة حفاظاً على تجربة العميل (رسائل تسويقية كثيرة) |
خفف الرسائل التسويقية لهذا العميل |
| 422 |
unsupported_message_type |
131051 |
نوع رسالة غير مدعوم |
|
| 422 |
media_download_failed |
131052 |
واتساب لم تستطع تحميل الملف من الرابط |
تأكد أن الرابط عام ويفتح، والحجم والصيغة مقبولة |
| 422 |
media_upload_failed |
131053 |
فشل رفع الملف |
أعد بملف آخر |
| 422 |
template_parameters_mismatch |
132000 |
عدد المتغيرات لا يطابق القالب |
طابق عدد {{n}} في القالب |
| 422 |
template_not_found |
132001 |
القالب غير موجود بهذا الاسم أو اللغة، أو غير معتمد |
راجع GET /api/templates |
| 422 |
template_text_too_long |
132005 |
النص بعد ملء المتغيرات طويل جداً |
قصّر قيم المتغيرات |
| 422 |
template_policy_violation |
132007 |
القالب يخالف سياسات Meta |
عدّل القالب |
| 422 |
template_parameters_invalid |
132012 |
صيغة متغير خاطئة (مثلاً صورة بدل نص) |
طابق نوع المتغير |
| 422 |
template_paused |
132015 |
Meta أوقفت القالب مؤقتاً لجودة منخفضة |
حسّن القالب أو استخدم آخر |
| 422 |
template_disabled |
132016 |
Meta عطّلت القالب نهائياً |
أنشئ قالباً جديداً |
| 422 |
invalid_request |
100 |
معامل غير صحيح في الطلب |
راجع meta_error.details |
| 422 |
meta_rejected |
أخرى |
رفض لسبب آخر |
التفاصيل في meta_error |
| 429 |
meta_rate_limited |
130429 |
تجاوزت سرعة الإرسال المسموحة للرقم |
انتظر وأعد |
| 429 |
meta_spam_rate_limited |
131048 |
Meta حدّت الإرسال بسبب بلاغات أو حظر |
راجع جودة رسائلك |
| 429 |
recipient_rate_limited |
131056 |
رسائل كثيرة لنفس العميل في وقت قصير |
انتظر قبل الرسالة التالية لنفس العميل |
| 403 |
whatsapp_account_locked |
131031 |
حساب واتساب للأعمال مقفل |
راجع Meta Business Support |
| 403 |
whatsapp_account_restricted |
368 |
الحساب مقيّد مؤقتاً لمخالفة |
راجع Meta Business Support |
| 401 |
whatsapp_token_expired |
190 |
انتهت صلاحية ربط واتساب |
أعد ربط الواتساب من الإعدادات |
| 502 |
meta_unreachable |
— |
لم نستطع الوصول لخوادم واتساب |
أعد المحاولة بعد قليل |
| 404 |
contact_not_found |
— |
جهة الاتصال لا تخص مؤسستك |
|
#الرسائل والحملات
| HTTP |
code |
السبب |
| 404 |
message_not_found |
message_id غير موجود في مؤسستك |
| 404 |
template_not_found |
uuid القالب في الحملة غير صحيح |
| 404 |
contact_group_not_found |
uuid المجموعة في الحملة غير صحيح |
| 422 |
campaign_audience_empty |
المجموعة لا تحتوي جهات اتصال |
#موتشي
| HTTP |
code |
السبب |
| 403 |
assistant_not_active |
المساعد الذكي مقفول في المؤسسة |
| 404 |
conversation_not_found |
المحادثة غير موجودة، أو توكن الجهاز ناقص أو خاطئ (المفتاح العام) |
| 429 |
too_many_conversations |
محادثات جديدة كثيرة من نفس الجهاز (المفتاح العام) |
| 429 |
too_many_messages |
رسائل سريعة جداً أو كثيرة في نفس المحادثة |
#مثال: معالجة الأخطاء في الكود
async function sendWhatsApp(payload, idempotencyKey, attempt = 1) {
const res = await fetch('https://botzo.net/api/send', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.BOTZO_API_KEY}`,
Accept: 'application/json',
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: JSON.stringify(payload),
});
const body = await res.json();
if (res.ok) return body.message_id;
const retryable = [409, 429, 500, 502, 503].includes(res.status);
if (retryable && attempt < 5) {
await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
return sendWhatsApp(payload, idempotencyKey, attempt + 1);
}
if (body.code === 'outside_24h_window') {
return sendTemplateInstead(payload.phone);
}
throw new Error(`Botzo ${body.code} (${body.request_id}): ${body.message}`);
}
function sendWhatsApp(array $payload, string $idempotencyKey): ?string
{
for ($attempt = 1; $attempt <= 5; $attempt++) {
$response = Http::withToken(env('BOTZO_API_KEY'))
->acceptJson()
->timeout(30)
->withHeaders(['Idempotency-Key' => $idempotencyKey])
->post('https://botzo.net/api/send', $payload);
if ($response->successful()) {
return $response->json('message_id');
}
if (! in_array($response->status(), [409, 429, 500, 502, 503], true)) {
logger()->warning('Botzo send failed', $response->json());
return null;
}
sleep(2 ** $attempt);
}
return null;
}