الأخطاء والحدود
غلاف واحد لكل إخفاق، ورمز ثابت لكل سبب، ومعرّف طلب على كل استجابة. وهذه الصفحة سطح الإخفاق كاملا: الرموز والحالات وتقسيم الصفحات وتحديد المعدل.
غلاف الخطأ
كل خطأ، من كل نقطة، له الشكل نفسه. لا توجد صيغة ثانية ولا استجابة نصية مجردة.
HTTP/1.1 422 Unprocessable Entity
content-type: application/json; charset=utf-8
x-request-id: req_...
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request payload failed validation.",
"request_id": "req_...",
"details": {
"issues": [
{ "path": "to", "message": "must be an E.164 number, e.g. +9665XXXXXXXX" }
]
}
}
}| الحقل | الوصف |
|---|---|
| error.code | معرّف ثابت مقروء آليا. وهذا ما يتفرّع عليه كودك. |
| error.message | نص إنجليزي للإنسان. مفيد في السجل؛ ولا تطابق عليه أبدا. |
| error.request_id | وهو أيضا الـ header المسمى X-Request-Id. يحدد هذا الطلب بعينه في سجلات المنصة. |
| error.details | موجود لبعض الرموز فقط. وشكله يتبع الرمز — خطأ التحقق يحمل issues، وخطأ الاستحقاق يحمل الحد والعدد الحالي. |
تفرّع على code لا على message
الـ code جزء من عقد الـ API ولن يتغيّر معناه دون رفع الإصدار. أما الـ message فنص بشري يمكن إعادة صياغته في أي وقت. والمطابقة عليه أسرع طريق لبناء تكامل ينكسر عند تحرير لغوي.
أخطاء التحقق
الطلب غير السليم يعطي 422 مع قائمة مقروءة آليا بما كان خطأ.
- إخفاقات التحقق هي
422لا 400. والـ 400 الوحيد في الـ API كلها هو غياب سياق مساحة العمل. - docs.pages.errors.validation.rules.issues
- القيمة التي أرسلتها لا تُعاد إليك أبدا، فتسجيل الخطأ آمن حتى لو حمل الطلب شيئا حساسا.
- معظم أجسام الكتابة صارمة: الحقل المجهول خطأ لا مفتاح يُتجاهل. والاسم المكتوب خطأ يخفق بصوت عال.
رموز الأخطاء
الدليل العام كاملا: 72 رمزا، مجموعة كما تجمعها المنصة. وعمود الرسالة هو نص الـ API الإنجليزي نفسه منقولا حرفيا — فهو بيانات استجابة لا نثر توثيق، ولهذا لم يُترجم.
قد تُضاف رموز إلى هذه القائمة. أما الرمز الموجود فلا يغيّر معناه ولا يختفي دون رفع إصدار الـ API.
النقل والمصادقة
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| UNAUTHORIZED | 401 | Authentication is required or the provided credentials are invalid. |
| FORBIDDEN | 403 | You do not have permission to perform this action. |
| NOT_FOUND | 404 | The requested resource was not found. |
| METHOD_NOT_ALLOWED | 405 | That HTTP method is not allowed on this resource. |
| VALIDATION_ERROR | 422 | The request payload failed validation. |
| CONFLICT | 409 | The request conflicts with the current state of the resource. |
| PAYLOAD_TOO_LARGE | 413 | The request payload is too large. |
| UNSUPPORTED_MEDIA_TYPE | 415 | The request content type is not supported. |
| RATE_LIMITED | 429 | Too many requests. Please retry later. |
| IDEMPOTENCY_CONFLICT | 409 | This idempotency key was already used with a different request payload. |
| INTERNAL_ERROR | 500 | An unexpected error occurred while processing the request. |
| SERVICE_UNAVAILABLE | 503 | The service is temporarily unavailable. Please retry later. |
الحسابات وتسجيل الدخول
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| INVALID_CREDENTIALS | 401 | The email address or password is incorrect. |
| EMAIL_ALREADY_IN_USE | 409 | An account already exists for that email address. |
| EMAIL_NOT_VERIFIED | 403 | Verify your email address before continuing. |
| ACCOUNT_SUSPENDED | 403 | This account is suspended. |
| TOKEN_INVALID | 401 | That link or token is invalid or has already been used. |
| TOKEN_EXPIRED | 401 | That link or token has expired. Request a new one. |
مساحات العمل والأعضاء والفرق
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| WORKSPACE_NOT_FOUND | 404 | The requested workspace was not found. |
| WORKSPACE_SUSPENDED | 403 | This workspace is suspended. |
| WORKSPACE_CONTEXT_REQUIRED | 400 | A workspace must be specified for this request. |
| MEMBER_NOT_FOUND | 404 | The requested workspace member was not found. |
| MEMBER_ALREADY_EXISTS | 409 | That person is already a member of this workspace. |
| OWNER_REQUIRED | 403 | Only the workspace owner can perform this action. |
| INVITATION_NOT_FOUND | 404 | The requested invitation was not found. |
| TEAM_NOT_FOUND | 404 | The requested team was not found. |
مفاتيح API والخطط
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| API_KEY_NOT_FOUND | 404 | The requested API key was not found. |
| API_KEY_REVOKED | 401 | This API key has been revoked. |
| PLAN_NOT_FOUND | 404 | The requested plan was not found. |
| ENTITLEMENT_LIMIT_REACHED | 409 | The current plan limit for this resource has been reached. |
القنوات والمزوّدون
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| CHANNEL_NOT_FOUND | 404 | The requested channel was not found. |
| CHANNEL_NOT_CONNECTED | 409 | The selected channel is not connected. |
| CHANNEL_CAPABILITY_UNAVAILABLE | 409 | The selected channel does not support this capability. |
| PROVIDER_RATE_LIMITED | 429 | The upstream messaging provider is rate limiting this channel. |
| PROVIDER_REJECTED | 502 | The upstream messaging provider rejected this request. |
الـ Sandbox
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| SANDBOX_RECIPIENT_NOT_VERIFIED | 403 | The recipient is not verified for this sandbox allocation. |
| SANDBOX_TEST_KEY_REQUIRED | 403 | A test-mode API key is required for sandbox operations. |
| SANDBOX_SESSION_NOT_FOUND | 404 | The requested sandbox session was not found. |
| SANDBOX_SESSION_EXPIRED | 409 | This sandbox session has expired. Request a new one. |
| SANDBOX_NO_NUMBER_AVAILABLE | 503 | No shared test number is available right now. Please retry shortly. |
| SANDBOX_VERIFICATION_PENDING | 409 | Send the verification code from the recipient number to the assigned test number to complete verification. |
| SANDBOX_VERIFICATION_INVALID | 422 | That verification code is incorrect. |
| SANDBOX_VERIFICATION_EXPIRED | 409 | That verification code has expired. Request a new one. |
جهات الاتصال والمجموعات والاستيراد
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| CONTACT_NOT_FOUND | 404 | The requested contact was not found. |
| CONTACT_ALREADY_EXISTS | 409 | A contact with that phone number already exists in this workspace. |
| CONTACT_GROUP_NOT_FOUND | 404 | The requested contact group was not found. |
| TAG_NOT_FOUND | 404 | The requested tag was not found. |
| IMPORT_NOT_FOUND | 404 | The requested import was not found. |
| IMPORT_FILE_TOO_LARGE | 413 | The uploaded file is larger than the import limit. |
| IMPORT_FORMAT_UNSUPPORTED | 415 | That file format is not supported for contact import. |
المحادثات والإسناد
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| CONVERSATION_NOT_FOUND | 404 | The requested conversation was not found. |
| CONVERSATION_ACCESS_DENIED | 403 | You do not have access to this conversation. |
| ASSIGNEE_NOT_FOUND | 404 | The requested assignee was not found in this workspace. |
| CONVERSATION_CONFLICT | 409 | This conversation was changed by someone else. Reload and try again. |
| NOTE_NOT_FOUND | 404 | The requested note was not found. |
القوالب
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| TEMPLATE_NOT_FOUND | 404 | The requested template was not found. |
| TEMPLATE_NOT_APPROVED | 409 | The requested template is not approved for sending. |
| TEMPLATE_ALREADY_EXISTS | 409 | A template with that name and language already exists. |
| TEMPLATE_VARIABLE_MISSING | 422 | One or more template variables were not supplied. |
| TEMPLATE_NOT_SENDABLE | 409 | This template is not available for sending. |
| META_SERVICE_WINDOW_REQUIRED_TEMPLATE | 409 | The customer service window is closed. Send an approved template instead. |
QR
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| QR_SAFETY_LIMIT_REACHED | 429 | The channel safety limit for this period has been reached. |
الـ Webhooks
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| WEBHOOK_ENDPOINT_NOT_FOUND | 404 | The requested webhook endpoint was not found. |
| WEBHOOK_DELIVERY_NOT_FOUND | 404 | The requested webhook delivery was not found. |
| WEBHOOK_ENDPOINT_DISABLED | 409 | This webhook endpoint was disabled after repeated delivery failures. Update it and set it back to active. |
| WEBHOOK_URL_NOT_ALLOWED | 422 | That webhook URL is not accepted by this environment. |
الحملات والأتمتة
رموز محجوزة
هذه الرموز معرّفة وثابتة، لكن لا نقطة تصدرها: فالحملات والأتمتة غير مبنية. وقد سُردت حتى لا يُفاجأ عميل يعالجها أصلا لاحقا، لا لأنك ستراها اليوم.
| الرمز | HTTP | الرسالة الافتراضية التي تعيدها الـ API |
|---|---|---|
| CAMPAIGN_NOT_FOUND | 404 | The requested campaign was not found. |
| CAMPAIGN_PAUSED | 409 | The campaign is paused. |
| CAMPAIGN_INVALID_STATE | 409 | That action is not available while the campaign is in its current state. |
| CAMPAIGN_AUDIENCE_EMPTY | 422 | The selected audience contains no contacts that may receive a marketing message. |
| CAMPAIGN_CHANNEL_NOT_ELIGIBLE | 409 | The selected channel cannot be used to run a campaign. |
| AUTOMATION_LIMIT_REACHED | 409 | The automation execution limit has been reached. |
حالات HTTP
الحالة تخبرك بصنف المشكلة؛ والرمز يخبرك أيّها.
| HTTP | الوصف |
|---|---|
| 400 | لم تُحدَّد مساحة عمل. وهذا هو الـ 400 الوحيد في الـ API. |
| 401 | لا بيانات اعتماد، أو بيانات غير صالحة. |
| 403 | بيانات اعتماد صحيحة لكنها غير مسموحة هنا، أو حساب أو مساحة عمل موقوفة. |
| 404 | المورد غير موجود، أو يخص مساحة عمل أخرى — والاثنان لا يمكن التمييز بينهما عمدا. |
| 409 | الطلب يتعارض مع الحالة الراهنة: قناة غير متصلة، أو حد خطة، أو تعارض حماية من التكرار. |
| 413 | الحمولة أكبر من الحد. |
| 415 | نوع المحتوى أو صيغة الملف غير مدعومة. |
| 422 | أخفقت الحمولة في التحقق. راجع details.issues. |
| 429 | تجاوز حد المعدل. اقرأ Retry-After. |
| 500 | إخفاق غير متوقع في المنصة. إعادة المحاولة آمنة. |
| 502 | رفض مزوّد الرسائل الأعلى الطلب. |
| 503 | تبعية غير متاحة مؤقتا. إعادة المحاولة آمنة. |
التحقق 422 لا 400
إن كان عميلك يعامل 400 حالةَ التحقق فسيفوته كل خطأ تحقق تنتجه هذه الـ API. والـ 400 الوحيد هو WORKSPACE_CONTEXT_REQUIRED.
تقسيم الصفحات
قوائم النتائج مقسّمة بالـ cursor. اقرأ page.next_cursor وأعده في after؛ وتوقّف حين تصير has_more بقيمة false.
curl "https://whats.azzamkh.sa/api/v1/messages?limit=50" \
-H "Authorization: Bearer $WA_API_KEY"
# 200 OK
# {
# "data": [ { "id": "msg_...", ... } ],
# "page": { "next_cursor": "bXNnXzAxSj...", "has_more": true }
# }
# Follow the cursor. Send it back verbatim; it is opaque.
curl "https://whats.azzamkh.sa/api/v1/messages?limit=50&after=bXNnXzAxSj..." \
-H "Authorization: Bearer $WA_API_KEY"| المعامل | الافتراضي | الوصف |
|---|---|---|
| limit | 50 | يُحصر بين 1 و100. |
| after | — | قيمة next_cursor من الصفحة السابقة. |
- قيمة
limitالخارجة عن المدى أو غير القابلة للقراءة تُحصر ولا تُرفض. فطلب 5000 صف يعيد 100. - الـ cursor مبهم. أعده كما هو ولا تفكّه — والمشوّه منه يُتجاهل فتحصل على الصفحة الأولى ثانية بصمت.
- معظم القوائم الأحدث أولا، لكن القوالب الأقدم أولا. لا تفترض اتجاها؛ اتبع الـ cursor.
- قيمة
next_cursorتكون null في الصفحة الأخيرة. كرّر علىhas_moreلا على مصفوفة data فارغة.
تحديد المعدل
المسارات المحدودة تجيب بـ 429 مع الـ headers القياسية وتلميح إعادة المحاولة في الجسم.
HTTP/1.1 429 Too Many Requests
ratelimit-limit: 600
ratelimit-remaining: 0
ratelimit-reset: 37
retry-after: 37
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please retry later.",
"request_id": "req_...",
"details": { "bucket": "messages.send", "retry_after_s": 37 }
}
}| Header | الوصف |
|---|---|
| RateLimit-Limit | السقف لهذا الدلو وهذه النافذة. |
| RateLimit-Remaining | كم طلبا بقي في النافذة الحالية. وصفر عند الرفض. |
| RateLimit-Reset | ثوان حتى تُصفَّر النافذة. |
| Retry-After | ثوان الانتظار. موجود عند الرفض فقط. التزم به. |
- كل القيم بالـ
ثوانيلا طوابع زمنية. - تغيب هذه الـ headers حين يكون تحديد المعدل مطفأ في البيئة. عامل غيابها انعدامَ معلومة لا حصةً بلا حد.
- المحدِّد يخفق مفتوحا: إن تعذّر مخزنه سُمح بالطلبات. فلا تعتمد عليه آلية صحّة أبدا.
- الرمز
PROVIDER_RATE_LIMITEDشيء آخر: مزوّد واتساب الأعلى يخنق القناة، ولا header يخبرك متى يتوقف.
ماذا تعيد
أعد المحاولة بتباعد أسّي وعشوائية، وأرسل دائما Idempotency-Key مع أي كتابة حتى لا تكرر إعادة المحاولة شيئا.
| الرمز | ما ينبغي فعله |
|---|---|
| RATE_LIMITED | انتظر مدة Retry-After ثم أعد. ولا تعد قبلها. |
| PROVIDER_RATE_LIMITED | تباعد أكثر — المزوّد الأعلى يخنق، ولا header يخبرك متى يتوقف. |
| SERVICE_UNAVAILABLE | أعد بتباعد. تبعية متوقفة مؤقتا. |
| INTERNAL_ERROR | أعد بتباعد. وإن استمر فاذكر قيمة request_id. |
| PROVIDER_REJECTED | لا تعد بغير تفكير. المزوّد رفض الرسالة؛ افحصها أولا. |
| VALIDATION_ERROR | لا تعد أبدا. أصلح الطلب. |
| IDEMPOTENCY_CONFLICT | لا تعد كما هو أبدا. إما الجسم خطأ وإما المفتاح. |