المطورون

الأخطاء وحل المشكلات

كل رمز خطأ تعيده الواجهة البرمجية لوندرفاتورة اليوم، وسببه وطريقة معالجته، مع إجابات أكثر مشكلات الربط شيوعًا.

صيغة الخطأ

للأخطاء غلاف واحد أيًّا كانت الطبقة التي رفضت الطلب. ابنِ منطقك على error.code لا على الرسالة؛ فالرسائل مكتوبة للبشر وقد تتغير.

{
  "ok": false,
  "error": {
    "code": "insufficient_scope",
    "message": "This API key has not been granted the permission this request needs.",
    "details": { "required_ability": "invoices:issue" }
  }
}

لغة الرسائل

الرسائل بالعربية ما لم تفضّل ترويسة Accept-Language في الطلب الإنجليزية (Accept-Language: en أو en-US ونحوها)، وتُستخدم العربية لأي قيمة أخرى أو عند غياب الترويسة. وتذكر كل إجابة لغتها في ترويسة Content-Language. ولا تتغير الرموز ولا أسماء الحقول ولا البيانات بتغير اللغة. أما خادم MCP فافتراضه معاكس لوكلاء الذكاء الاصطناعي: الإنجليزية ما لم يطلب العميل العربية.

رموز الأخطاء

HTTP الرمز السبب والحل
400 bad_request تعذّرت قراءة الطلب، كمحتوى JSON لا يمكن تحليله. ويبيّن details موضع الخطأ.
400 unsupported_api_version يذكر المسار إصدارًا للواجهة البرمجية غير v1 (أو إصدارًا بصيغة غير صحيحة). استخدم /api/v1/….
401 unauthorized المفتاح مفقود أو غير معروف أو ملغى، أو أن منشئه لم يعد ضمن المنشأة. راجع الترويسة والمفتاح في الإعدادات ← مفاتيح API.
401 invalid_token رمز وصول OAuth غير صالح أو منتهٍ أو ملغى، أو أن المنشأة فصلت التطبيق. جدّده، أو أعد الشخص إلى شاشة الموافقة.
401 token_expired انتهت صلاحية المفتاح في التاريخ المذكور في الرسالة. details.renew_url هي الصفحة التي ينشئ منها المسؤول مفتاحًا جديدًا أو يجدّد هذا المفتاح (بالصلاحيات نفسها)، وdetails.expired_at الوقت الدقيق.
403 insufficient_scope تنقص بيانات الاعتماد صلاحية يسمّيها details.required_scope (ويحمل details.required_ability اسمها الأصلي للعملاء الأقدم). استخدم بيانات اعتماد تملكها.
403 forbidden الشخص الذي تمثّله بيانات الاعتماد غير مخوّل بهذا الإجراء، كإصدار الفواتير. عدّل دور المستخدم، أو استخدم بيانات اعتماد شخص مخوّل.
403 plan_upgrade_required باقة المنشأة لا تشمل الوصول إلى الواجهة البرمجية (باقة الأعمال أو المؤسسات).
403 mode_mismatch بيانات اعتماد تجريبية مع منشأة فعلية، أو العكس. تُنشأ بيانات الاعتماد دائمًا لنوع منشأتها، فلا يحدث هذا في الاستخدام المعتاد، وتُرفض مثل هذه البيانات بالرمز 401 unauthorized.
404 not_found لا توجد نقطة نهاية بهذا المسار، أو لا يوجد سجل بهذا المعرّف (نقطة استقبال Webhook أو عملية تسليم) في منشأة بيانات الاعتماد. راجع المسار والمعرّف.
404 invoice_not_found لا توجد فاتورة بهذا المعرّف في منشأة بيانات الاعتماد.
404 customer_not_found لا يوجد عميل بهذا المعرّف في منشأة بيانات الاعتماد. وفي POST /invoices يعيده customer.id الذي ليس لك بالرمز 422.
404 note_not_found لا يوجد إشعار دائن أو مدين بهذا المعرّف في منشأة بيانات الاعتماد.
404 xml_not_applicable المنشأة غير مرتبطة بهيئة الزكاة والضريبة والجمارك، فلا يوجد ملف XML نظامي لمستنداتها. نزّل ملف PDF بدلًا منه.
405 method_not_allowed نقطة النهاية موجودة لكن ليس بهذه الطريقة، وتسرد ترويسة Allow الطرق التي تقبلها.
409 invoice_not_draft يتطلب الإجراء مسودة (للتحقق منها أو إصدارها)، وهذا المستند ليس مسودة، كمسودة أُلغيت. اطلع على حالته أولًا.
409 invoice_immutable لا يمكن تعديل مستند صادر. صحّحه بإشعار دائن أو مدين.
409 document_not_available ملف PDF أو XML غير جاهز بعد، غالبًا لأن الهيئة لم تعالج المستند. أعد المحاولة بعد قليل.
409 idempotency_in_progress طلب بمفتاح Idempotency-Key نفسه ما زال قيد التنفيذ. انتظر ثواني Retry-After ثم أرسله مجددًا دون تغيير.
413 payload_too_large حجم محتوى الطلب كبير جدًا.
415 unsupported_media_type المحتوى ليس application/json. أرسل Content-Type: application/json.
422 validation_failed المحتوى غير صحيح، ويربط details كل حقل برسائله.
422 invalid_reference tax_rate_id أو product_id في أحد البنود ليس لك، ويسمّيه details.field.
422 invoice_requirements_missing تنقص إعدادات منشأتك أمرًا تحتاجه كل فاتورة، ويسرده details.missing. أكمله من لوحة التحكم.
422 invoice_not_issuable لا يمكن إصدار الفاتورة على حالها، والرسالة تبين السبب. لم يُنشأ شيء.
422 customer_vat_invalid الرقم الضريبي السعودي للمشتري غير صحيح.
422 credit_exceeds_invoice مبلغ الإشعار الدائن أكبر من المتبقي على الفاتورة بعد الإشعارات الدائنة السابقة.
422 note_reason_required يحتاج الإشعار الدائن أو المدين إلى reason.
409 invoice_not_payable تُسجَّل الدفعة على فاتورة صادرة فقط، لا على مسودة أو فاتورة ملغاة أو مستردة؛ وdetails.status يذكر حالتها.
422 payment_exceeds_balance الدفعة أكبر من المتبقي على الفاتورة؛ وdetails.balance وdetails.currency يذكران المتبقي. الدفع الزائد يسجله شخص من داخل وندرفاتورة فقط. وفي POST /invoices لا يُنشأ شيء.
422 plan_limit_reached استنفدت المنشأة أحد حدود باقتها، ويسمّيه details.resource وdetails.limit. رقِّ الباقة أو انتظر الفترة التالية.
422 idempotency_key_reused سبق استخدام مفتاح Idempotency-Key هذا مع طلب مختلف. استخدم مفتاحًا جديدًا لكل طلب جديد.
429 rate_limited طلبات كثيرة. انتظر ثواني Retry-After. راجع حدود الطلبات.
500 server_error تعطّل شيء من جهتنا وأُبلغنا به تلقائيًا، ويعرّف details.request_id الطلب. أعد المحاولة بنفس external_reference أو Idempotency-Key.
503 service_unavailable نقطة النهاية هذه متوقفة حاليًا. أعد المحاولة لاحقًا.

أخطاء التحقق من البيانات

HTTP/1.1 422 Unprocessable Content

{
  "ok": false,
  "error": {
    "code": "validation_failed",
    "message": "The submitted data is invalid.",
    "details": {
      "issue_date": ["The issue date field is required."],
      "items.0.unit_price": ["The items.0.unit_price field is required."]
    }
  }
}

حل المشكلات

تصلني صفحة HTML بدل JSON

أرسل Accept: application/json مع كل طلب. بدونها قد يرد رابط مكتوب خطأً بصفحة الخطأ HTML الخاصة بالموقع بدل خطأ JSON.

401 مع أن المفتاح يبدو صحيحًا

  • يجب أن تكون الترويسة Authorization: Bearer <key> (بمسافة واحدة ودون علامات اقتباس) أو X-Api-Key: <key>.
  • المفاتيح في الرابط مرفوضة.
  • ربما جُدّد المفتاح؛ فالمفتاح القديم يتوقف لحظة تجديده. أما المفتاح المنتهي فيجيب بـ token_expired.
  • ربما غادر منشئ المفتاح المنشأة. أنشئ مفتاحًا جديدًا.

403 forbidden عند الإصدار

يحتاج المفتاح invoices:issue، ويحتاج منشئه صلاحية إصدار الفواتير. المستخدم ذو دور العرض فقط أو الدور المحدود لا يستطيع الإصدار عبر مفتاح أيضًا.

يفشل الإصدار بـ invoice_not_issuable

اقرأ error.message فهي تسمّي المشكلة. أكثر الأسباب شيوعًا: رقم المنشأة الضريبي أو عنوانها غير مكتمل؛ مشترٍ من المنشآت في فاتورة ضريبية بلا عنوان وطني كامل؛ بند خاضع للنسبة الصفرية أو معفى بلا vat_exemption_code. أنشئ مسودة ("issue": false) لتحتفظ بالبيانات حتى تعالج السبب.

الفاتورة صادرة لكن deliverable يساوي false

الفاتورة الضريبية بين المنشآت تنتظر اعتماد الهيئة. اقرأها مجددًا بعد قليل. وإن أصبحت حالتها rejected فستجد أسباب الهيئة في errors.

إعادة المحاولة أنشأت فاتورة ثانية

أرسل external_reference؛ فبدونه كل طلب فاتورة جديدة.

طلب المساعدة

راسلنا بوقت الطلب ورمز HTTP وerror.code. لا ترسل مفتاح API نفسه أبدًا.

جاهز للبدء؟

الوصول إلى الواجهة البرمجية ضمن باقات: الأعمال والمؤسسات. أنشئ مفتاحًا من الإعدادات ← مفاتيح API وأرسل أول طلب خلال دقائق.