رفتن به محتوای اصلی
مستندات APIمرجعError handling

خطاها و پیام‌ها

همهٔ خطاها با یک ساختار JSON یکسان برمی‌گردند. کدهای خطا، وضعیت HTTP هر کدام و روش درست مدیریت ۴۲۹ و خطاهای اعتبار را اینجا ببینید.

ساختار پاسخ خطا

هر خطا با یک وضعیت HTTP غیر از 2xx و بدنه‌ای با شکل زیر برمی‌گردد. برای منطق برنامه از error.code استفاده کنید؛ error.message برای انسان نوشته شده و ممکن است تغییر کند.

JSON
1{
2  "error": {
3    "code": "insufficient_credits",
4    "message": "Insufficient credits. Required: 8, available: 2."
5  }
6}

کدهای خطا

ستون «تکرار» می‌گوید آیا فرستادن دوبارهٔ همان درخواست معنی دارد یا نه.

احراز هویت و دسترسی

HTTPcodeمعنی و راه‌حلتکرار
401missing_authorizationهدر Authorization ارسال نشده یا طرح Bearer ندارد.هدر را به شکل Authorization: Bearer ba_live_… بفرستید.خیر
401invalid_api_keyکلید نامعتبر است یا ساختار درستی ندارد.کلید را از پنل توسعه‌دهندگان کپی کنید؛ فاصله یا کاراکتر اضافه نداشته باشد.خیر
403revoked_api_keyاین کلید لغو شده است.کلید جدیدی بسازید و در برنامه جایگزین کنید.خیر
403plan_requiredحساب پلن فعال ندارد یا پلن منقضی شده. API برای پلن کاوشگر و بالاتر فعال است.پلن را از صفحهٔ پلن‌ها فعال یا تمدید کنید.خیر
403user_bannedحساب کاربری به‌طور موقت یا دائم مسدود شده است.با پشتیبانی تماس بگیرید.خیر

اعتبار و سهمیه

HTTPcodeمعنی و راه‌حلتکرار
403insufficient_creditsاعتبار حساب برای این درخواست کافی نیست. پیام، مقدار لازم و موجودی فعلی را می‌گوید.حساب را شارژ کنید یا مدل/کیفیت ارزان‌تری انتخاب کنید.خیر
429rate_limit_exceededتعداد درخواست‌ها از سقف دقیقه‌ای پلن بیشتر شده (پیش‌فرض 30).به اندازهٔ هدر Retry-After صبر کنید و با وقفهٔ افزایشی دوباره تلاش کنید.پس از Retry-After

درخواست

HTTPcodeمعنی و راه‌حلتکرار
400invalid_requestبدنه یا پارامترها نامعتبرند؛ مثلاً prompt خالی، مدت خارج از بازه یا رزولوشن غیرمجاز.پیام خطا دقیقاً می‌گوید کدام فیلد مشکل دارد؛ همان را اصلاح کنید.خیر
400unsupported_modelشناسهٔ مدل برای این مسیر پشتیبانی نمی‌شود.شناسه را با جدول مدل‌های همان صفحه مطابقت دهید.خیر
400invalid_idempotency_keyمقدار Idempotency-Key خالی، طولانی‌تر از ۲۵۶ کاراکتر یا دارای فاصله است.یک رشتهٔ ASCII بدون فاصله مثل UUID بفرستید.خیر
404task_not_foundتسکی با این شناسه برای این حساب وجود ندارد.مقدار فیلد id را از پاسخ ایجاد تسک بخوانید، نه taskId.خیر
409idempotency_key_in_progressدرخواست قبلی با همین Idempotency-Key هنوز در حال اجراست.به اندازهٔ Retry-After صبر کنید و همان درخواست را دوباره بفرستید.پس از Retry-After
422idempotency_key_reusedهمان Idempotency-Key با بدنهٔ متفاوت استفاده شده است.برای هر عملیات منطقی یک کلید یکتا بسازید.خیر

سرور

HTTPcodeمعنی و راه‌حلتکرار
500generation_failedارسال درخواست به مدل ناموفق بود. اعتباری رزرو نشده و تسکی ساخته نشده است.چند ثانیه بعد دوباره تلاش کنید.بله
500internal_errorخطای غیرمنتظرهٔ سرور.با وقفهٔ افزایشی دوباره تلاش کنید؛ اگر ادامه داشت به پشتیبانی اطلاع دهید.بله

محدودیت نرخ درخواست (429)

نرخ درخواست هر کلید در یک بازهٔ شناور ۶۰ ثانیه‌ای محدود می‌شود و همهٔ مسیرهای /api/v1، از جمله پیگیری تسک، از یک سهمیه استفاده می‌کنند. سقف فعلی: کاوشگر و خلاق 30، استودیو 60 و اولترا 120 درخواست در دقیقه. سقف کلید خودتان را از GET /api/v1/account بخوانید.

پاسخ ۴۲۹ به‌همراه هدرها
HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 30
Content-Type: application/json

{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded. Maximum 30 requests per minute."
  }
}
  • Retry-After: تعداد ثانیه تا آزاد شدن سهمیه.
  • X-RateLimit-Limit: سقف درخواست در دقیقه برای پلن شما.
  • درخواست اجرا نمی‌شود و اعتباری از حساب کم نخواهد شد.

نکته

رایج‌ترین دلیل ۴۲۹، پیگیری خیلی سریع تسک‌هاست. هر ۳ تا ۵ ثانیه یک‌بار کافی است؛ اگر چند تسک هم‌زمان دارید، پیگیری آن‌ها را پشت هم بچینید، نه هم‌زمان.

مدیریت خطا در کد

نمونهٔ زیر الگوی توصیه‌شده را نشان می‌دهد: ۴۲۹ را با انتظار تکرار کنید، خطاهای اعتبار را به کاربر نشان دهید و خطاهای ۴۰۰ را به‌عنوان اشکال برنامه گزارش کنید.

JavaScript
async function createTask(body) {
  const res = await fetch("https://bananaai.ir/api/v1/images/generations", {
    method: "POST",
    headers: {
      Authorization: "Bearer ba_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  });

  if (res.ok) return res.json();

  const { error } = await res.json();

  switch (error.code) {
    case "rate_limit_exceeded": {
      const wait = Number(res.headers.get("Retry-After") ?? 5) * 1000;
      await new Promise((r) => setTimeout(r, wait));
      return createTask(body); // تلاش دوباره
    }
    case "insufficient_credits":
      // به کاربر بگویید اعتبار کافی نیست
      throw new Error(error.message);
    case "invalid_request":
    case "unsupported_model":
      // اشکال در بدنهٔ درخواست؛ تکرار فایده ندارد
      throw new Error(`Bad request: ${error.message}`);
    default:
      throw new Error(`${res.status} ${error.code}: ${error.message}`);
  }
}