صيغة الخطأ
للأخطاء غلاف واحد أيًّا كانت الطبقة التي رفضت الطلب. ابنِ منطقك على 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 وأرسل أول طلب خلال دقائق.