خطاها و کدهای وضعیت
ساختار پاسخ، فهرست کامل کدهای وضعیت و الگوی درست مدیریت خطا در کلاینت.
همهٔ پاسخهای این API — موفق یا ناموفق — ساختار یکسانی دارند، بنابراین میتوانید یک لایهٔ مدیریت خطای واحد بنویسید و همهجا از آن استفاده کنید.
ساختار پاسخ
{ "return": { "status": 200, "message": "درخواست تایید شد." }, "entries": []}return.status— کد وضعیتreturn.message— پیام فارسی قابل نمایشentries— دادههای پاسخ. در پاسخ موفق یک شیء یا آرایه است و در همهٔ پاسخهای خطا آرایهٔ خالی[]برمیگردد.
برخلاف بسیاری از APIها، این سرویس کد وضعیت داخل بدنه را در خودِ کد وضعیت HTTP هم برمیگرداند. مثلاً
وقتی اعتبار حساب کافی نیست، پاسخ HTTP دقیقاً 418 است و return.status هم 418.
نتیجهٔ عملی: بعضی کتابخانههای HTTP برای کدهای غیر ۲xx استثنا پرتاب میکنند. کلاینت خود را طوری بنویسید که بدنهٔ پاسخ را حتی در حالت خطا هم بخواند — پیام دقیق آنجاست.
چهار استثنا که قالب بالا را ندارند
بیشتر سرویسها دقیقاً همین قالب را برمیگردانند، ولی چهار مورد استثنا هستند و کلاینت شما باید آنها را تحمل کند:
| مورد | چه برمیگرداند |
|---|---|
| خطای غیرمنتظرهٔ سرور | HTTP 500 با بدنهٔ {"message": "..."} — بدون return و entries |
GET /health | {"message": "~it works~"} |
POST /v2/sms/outbox | HTTP 501 با بدنهٔ {"error": "not implemented yet"} |
| سرویس WebEngage | قالب اختصاصی {"status", "statuscode", "message"} |
اگر خطای پیشبینینشدهای در سرویس رخ دهد، پاسخ قالب استاندارد را ندارد. پس پیش از خواندن
return، وجودش را بررسی کنید:
body = response.json()result = body.get("return")if result is None: # خطای غیرمنتظرهٔ سرور — پیام در کلید "message" است raise ServerError(body.get("message", "خطای ناشناخته"))کدی که مستقیم body["return"]["status"] را میخواند، دقیقاً در بدترین لحظه (خطای سرور) با
KeyError میشکند و پیام واقعی خطا را از دست میدهد.
فهرست کدهای وضعیت
این جدول فقط کدهایی را دارد که سرویس واقعاً تولید میکند. کدام کد از کدام سرویس برمیگردد، در صفحهٔ همان سرویس در بخش «پاسخها» آمده است.
موفق
| کد | معنی |
|---|---|
200 | درخواست تایید شد. |
201 | ساخته شد — فقط در ساخت کمپین، بارگذاری مخاطبان و بارگذاری فایل. توجه: در این سه مورد کد HTTP برابر 201 است ولی return.status داخل بدنه 200 میماند. |
خطای درخواست
| کد | معنی |
|---|---|
400 | پارامترها ناقص هستند |
411 | دریافت کننده نامعتبر است |
412 | ارسال کننده نامعتبر است |
414 | حجم درخواست بیشتر از حد مجاز است |
417 | تاریخ ارسال اشتباه است و فرمت آن صحیح نمیباشد |
422 | دادههای ارسالی قابل پردازش نیستند (طول توکن یا قالب پارامتر در ارسال با الگو) |
424 | تمپلیت ارسالی تایید نشده است |
خطای احراز هویت و دسترسی
| کد | معنی |
|---|---|
401 | حساب کاربری فعال نشده است |
403 | کد شناسائی API-Key معتبر نمیباشد |
416 | IP سرویس مبدا با تنظیمات مطابقت ندارد — فقط سرویسهای نسخهٔ ۱ |
خطای اعتبار و سرور
| کد | معنی |
|---|---|
418 | اعتبار شما کافی نمیباشد |
500 | خطای داخلی رخ داده است. با پشتیبانی تماس بگیرید. |
501 | پیادهسازی نشده — فقط POST /v2/sms/outbox |
سرویس چند کد دیگر را هم در فهرست ثابتهایش دارد که هیچ مسیری آنها را برنمیگرداند:
402، 404، 405، 406، 407، 409، 413، 415، 419، 420.
اگر مستندات قدیمیتری دیدهاید که این کدها را وعده میداد، به آنها تکیه نکنید. بهطور مشخص:
409(محدودیت نرخ) — این سرویس هیچ محدودیت نرخی روی درخواستها اعمال نمیکند.413(طول پیام) — هیچ بررسی طول متنی روی مسیرهای ارسال انجام نمیشود؛ سقف «۹۰۰ کاراکتر» که در متن این کد آمده، در کد سرویس اعمال نشده است.404و405— سرویس هیچ هندلر اختصاصی برای مسیر یا متد ناموجود ندارد؛ در آن حالت پاسخ متنی پیشفرض چارچوب برمیگردد، نه قالب استاندارد.
وضعیت پیامک (متفاوت با کد خطا)
مقدار status که در پاسخ سرویسهای استعلام برای هر پیامک برمیگردد، ربطی به کد وضعیت درخواست
ندارد. این مقدار چرخهٔ عمر یک پیامک را نشان میدهد:
| مقدار | statustext |
|---|---|
0 | دریافت کننده نامعتبر |
1 | در صف ارسال |
2 | زمانبندی شده |
4 | ارسال شده به مخابرات |
6 | خطا در ارسال پیام به سرشماره مشخص شده |
10 | رسیده به گیرنده |
11 | مشکل در رسیدن پیام |
13 | ارسال پیام از سمت کاربر لغو شده یا در ارسال آن مشکلی پیش آمده که هزینه آن به حساب برگشت داده میشود |
14 | بلاک شده است |
15 | شماره تکراری |
100 | شناسه پیامک نامعتبر است |
10، 11، 13، 14 وضعیتهای پایانیاند و دیگر تغییر نمیکنند. 1، 2 و 4 وضعیتهای میانی
هستند؛ برای آنها استعلام را با فاصلهٔ زمانی تکرار کنید، نه در حلقهٔ تنگ.
الگوی مدیریت خطا
import requestsresponse = requests.post(url, json=payload, headers=headers)body = response.json() # بدنه را در هر حالتی بخوانیدresult = body.get("return")if result is None: # خطای غیرمنتظرهٔ سرور (به هشدار بالا نگاه کنید) raise ServerError(body.get("message", "خطای ناشناخته"))if result["status"] == 200: entries = body["entries"]elif result["status"] == 418: raise OutOfCredit(result["message"]) # اعتبار کافی نیستelif result["status"] in (401, 403, 416): raise AuthError(result["message"]) # کلید، حساب یا آیپیelif result["status"] == 500: retry_later() # قابل تلاش مجددelse: raise RequestError(result["status"], result["message"])مقدار return.message متن فارسیِ آمادهٔ نمایش است. بهجای نگاشت دوبارهٔ کدها به متن دلخواه خودتان،
همین پیام را به کاربر نهایی نشان دهید تا با چیزی که پشتیبانی نجوا میبیند یکی باشد.