← المدونة أدلة 9 دقائق قراءة · 25 سبتمبر 2026

واجهة API للفوترة الإلكترونية في السعودية: اربط نظامك مع زاتكا وأصدر الفاتورة بطلب واحد

نظام برمجي يرسل طلب JSON واحدًا إلى واجهة API للفوترة الإلكترونية فيعود إليه ردّ يحمل حكم هيئة الزكاة والضريبة والجمارك وروابط ملف XML الموقّع وPDF ورمز QR
نظامك يبقى مصدر الحقيقة، والامتثال استدعاء واحد: الإجازة أو التبليغ داخل الطلب نفسه.

وصلتك المهمة في سطر واحد: «اجعل نظامنا متوافقًا مع المرحلة الثانية من الفوترة الإلكترونية». والنظام نظامك — ERP بنيتموه، أو نقطة بيع، أو منصة حجوزات، أو فوترة اشتراكات، أو نظام عيادة أو مدرسة — وعليه من الآن أن يُصدر فواتير تُجيزها هيئة الزكاة والضريبة والجمارك أو تُبلَّغ إليها. أمامك طريقان: أن تتحدث مع واجهات منصة فاتورة مباشرة، أو أن ترسل بيانات الفاتورة بصيغة JSON إلى واجهة API تتولّى الباقي. هذا المقال عن الطريق الثاني: ماذا يعطيك بالضبط، وكيف تبدو الاستدعاءات، ومتى لا يناسبك.

هل لهيئة الزكاة API؟ نعم، لكنها لا تستقبل «بيانات فاتورة»

منصة فاتورة تتيح واجهات برمجية للربط والامتثال والإجازة والتبليغ. لكن ما تستقبله ملف XML مبني وموقّع، لا أسطر وأسعار. وقبل أن ترسل أول فاتورة حقيقية عليك أن تبني هذا كله:

  • زوج مفاتيح وطلب شهادة (CSR) يحمل الرقم الضريبي وبيانات المنشأة بالحقول التي تشترطها الهيئة.
  • شهادة امتثال (Compliance CSID) تبادلها برمز OTP تولّده المنشأة من بوابة فاتورة، ثم فحوص الامتثال: مستندات اختبارية يُنتجها كودك نفسه ويجب أن تجتاز قواعد التحقق.
  • شهادة إنتاج (Production CSID) توقّع بها الفواتير الحقيقية، ولها تاريخ انتهاء وتجديد لا يحدث وحده.
  • ملف XML بصيغة UBL 2.1 بترتيب عناصر إلزامي وقوائم رموز مغلقة، ثم التوقيع والبصمة ورمز QR.
  • عدّاد الفواتير (ICV) وبصمة الفاتورة السابقة (PIH) لكل جهاز: حالة دائمة تتأثر بالتزامن، وكسرها لا يُصلَح.
  • مساران للإرسال: الفاتورة الضريبية (B2B) تُجاز قبل أن تصل إلى المشتري، والمبسّطة (B2C) تُبلَّغ خلال 24 ساعة — نقطتا نهاية مختلفتان، وردّان مختلفان، وطابور إعادة محاولة لا يضيع مع إعادة التشغيل.

هذا طريق ممكن ومفهوم، وقد كتبناه خطوة خطوة في دليل الربط مع واجهة ZATCA من CSR إلى أول فاتورة موقّعة، مع ما يفشل عادة في كل خطوة، وللتجديد مقاله: شهادتك لها تاريخ انتهاء. فإن كان الامتثال هو منتجك نفسه فابدأ من هناك. وإن كان ميزة في منتجك لا المنتج كله، فتابع.

البديل: طلب واحد إلى POST /v1/invoices

في واجهة ZATCA Tools يبقى نظامك مصدر الحقيقة، ويصير الامتثال استدعاءً واحدًا. ترسل الأسطر، والمشتري إن كانت الفاتورة ضريبية، فتبني الواجهة ملف XML بصيغة UBL 2.1، وتوقّعه بشهادة منشأتك نفسها، وترسله إلى الهيئة وتحفظ النتيجة. الفاتورة الضريبية (standard) تُرسَل للإجازة، والمبسّطة (simplified) تُوقَّع وتُبلَّغ — وكلاهما داخل الطلب نفسه، فيصلك الرد وفيه حكم الهيئة. هذا طلب فاتورة ضريبية لشركة:

POST https://zatcatools.com/api/v1/invoices
Authorization: Bearer ztk_live_…
Content-Type: application/json

{
  "type": "standard",
  "external_id": "SO-2026-1188",
  "customer": {
    "name": "شركة المثال للتجارة",
    "vat_number": "311111111101113",
    "short_address": "RRRD2929"
  },
  "lines": [
    { "name": "اشتراك سنوي", "quantity": 1, "unit_price": 1000 }
  ]
}

والرد مختصرًا:

201 Created

{
  "uuid": "8d9f6e0a-4b7c-4f2e-9a1d-3c5b7e9f1a2b",
  "number": "INV-2026-00042",
  "type": "standard",
  "status": "accepted",
  "totals": { "taxable": "1000.00", "vat": "150.00", "grand": "1150.00", "currency": "SAR" },
  "zatca": { "channel": "clearance", "icv": 42, "warnings": [] },
  "links": {
    "view": "https://zatcatools.com/invoice/…",
    "xml":  "https://zatcatools.com/api/v1/invoices/8d9f6e0a-…/xml",
    "pdf":  "https://zatcatools.com/api/v1/invoices/8d9f6e0a-…/pdf",
    "qr":   "https://zatcatools.com/api/v1/invoices/8d9f6e0a-…/qr.svg"
  }
}

أربعة حقول تكفي لقراءة الرد:

  • status: القيمة accepted أو warnings تعني أن الفاتورة صدرت — الثانية مع ملاحظات من الهيئة في zatca.warnings — وrejected تعني أن الهيئة ردّتها، ولها قسم خاص أدناه.
  • totals: نصوص بمنزلتين عشريتين، وtaxable وvat وgrand هي الأرقام الموقّعة نفسها، فخزّنها كما هي ولا تُعِد حسابها في نظامك.
  • zatca.channel: clearance للإجازة أو reporting للتبليغ، ومعه رقم العدّاد icv.
  • links: الرابط view هو ما تضعه أمام العميل، يُفتح في أي متصفح بلا مفتاح؛ أما xml وpdf وqr فتحتاج المفتاح. وملف XML هو نفسه، بايتًا ببايت، ما استلمته الهيئة.

التوقيع والإجازة يستغرقان من ثانية إلى ثلاث ثوانٍ، فاجعل مهلة الطلب عندك 30 ثانية. وإن كانت أسعارك في النظام شاملة الضريبة كأسعار الرف، فأرسلها كما هي مع "prices_include_vat": true ولا تقسمها على 1.15 بنفسك؛ الصافي يُستخرج لكل سطر بنسبته. ولكل سطر أن يحمل معاملته الضريبية (S أو Z أو E أو O) مع رمز السبب حين يلزم، والمشتري الذي لا رقم ضريبيًا له — جهة حكومية أو منشأة تحت حد التسجيل — يُعرَّف برقم آخر مع نوعه. وتفصيل ذلك كله في التوثيق.

أعد المحاولة بلا خوف من فاتورة مكررة

أخطر لحظة في أي تكامل مع الفوترة ليست الرفض بل الصمت: انقطع الاتصال بعد أن أرسلت الطلب، ولا تعرف هل صدرت الفاتورة أم لا. لو أعدت الإرسال بلا حماية فقد تصدر فاتورتان لطلب واحد، والثانية مستند حقيقي في سلسلتك لا يُحذف، بل يُعالَج بإشعار دائن.

لذلك أرسل رقم الطلب عندك في external_id، أو في ترويسة Idempotency-Key. أي طلب يتكرر بالقيمة نفسها يعيد الفاتورة التي صدرت أول مرة — برمز 200 بدل 201 وبالمحتوى نفسه — ولا يُصدر فاتورة ثانية أبدًا، حتى لو وصل الطلبان في اللحظة نفسها. فإعادة المحاولة بعد انتهاء المهلة آمنة دائمًا، وهذا ما يجعل ربط الواجهة بطابور مهام أو بحدث «تم الدفع» في نظامك أمرًا بسيطًا.

الأخطاء: ما ترفضه الواجهة، وما ترفضه الهيئة

حالتان مختلفتان تمامًا، ويجب أن يفرّق بينهما كودك.

رفض الواجهة (4xx). كل خطأ يعود في غلاف واحد: كائن error فيه code ثابت يقرؤه برنامجك، وmessage يقرؤه الإنسان ويسمّي الحقل الذي يجب إصلاحه، مثل lines[1].quantity. ولا يُوقَّع شيء ولا يُرقَّم قبل أن يجتاز الطلب كل الفحوص، فالخطأ من هذه الفئة لا يترك أثرًا على المنشأة: تصلحه وتعيد الإرسال. والسطر الذي لا يُقرأ يُرفض معه الطلب كله؛ لا يسقط سطر من فاتورة موقّعة بصمت. وبعض قواعد الهيئة تُفحص هنا قبل التوقيع، مثل تاريخ الإصدار المستقبلي (BR-KSA-04) وسطر معفى بوصفه تعليمًا أو صحة لمشترٍ بلا هوية وطنية (BR-KSA-49)، فيصلك خطأ 422 بدل مستند مرفوض يأخذ رقمًا.

رفض الهيئة (201 مع rejected). هذا ليس خطأ من الواجهة: المستند وصل إلى الهيئة فردّته. الأسباب في zatca.rejection بأكواد الهيئة كما قالتها، والمستند المرفوض يحتفظ برقمه وموضعه في السلسلة كما يشترط النظام، فتُصدر فاتورة مصحّحة جديدة ولا تعدّل المرفوضة. والمستند الذي ترفضه الهيئة يعيد وحدته إلى رصيد باقتك. ولكل كود تحقق صفحة بالعربية في مرجع أكواد أخطاء الفاتورة الإلكترونية تشرح معناه وطريقة إصلاحه، ولقراءة الرفض من أوله: فاتورتك مرفوضة؟ اقرأ السبب وأصلحه.

الإشعارات الدائنة والمدينة: POST /v1/notes

الفاتورة الصادرة لا تُحذف ولا تُعدَّل؛ تُصحَّح بإشعار. ترسل إلى /v1/notes نوع الإشعار (credit أو debit) ومعرّف الفاتورة الأصلية invoice_uuid والسبب — وهو إلزامي، فالإشعار بلا سبب ترفضه الهيئة (BR-KSA-17). والأسطر تُسعَّر بالصافي الذي دفعه المشتري فعلًا، والكمية المرتجعة لا تتجاوز كمية الفاتورة، والإشعار الدائن لا يتجاوز الرصيد المفتوح للفاتورة بعد الإشعارات السابقة (المادة 40) — وإلا عاد الخطأ exceeds_open_balance قبل أن يُوقَّع شيء.

ولإلغاء فاتورة كاملة أرسل إشعارًا دائنًا مع "full": true بلا أسطر، فيُحسب الرصيد المفتوح عنك ولا يتجاوز السقف النظامي. وللتراجع عن الإلغاء الطلب نفسه بنوع debit. والإشعار يصدر من فرع فاتورته نفسه، والفرق بين النوعين مشروح في الإشعار الدائن والمدين.

الفروع والأجهزة: رقم ضريبي واحد ومنافذ كثيرة

إن كان نظامك يخدم منشأة لها فروع أو صناديق متعددة، فالقاعدة عند الهيئة أن الشهادة تخص الجهاز لا الشركة. في الواجهة يُصدر كل فرع من جهازه الخاص (وحدة EGS بلغة الهيئة): يُفعَّل برمز OTP مستقل من بوابة فاتورة — لمرة واحدة وصالح لساعة — ويحمل شهادته وسلسلة فواتيره، فتُصدر الفروع بالتوازي دون أن تتنازع موضعًا في سلسلة واحدة.

تنشئ الفرع بـPOST /v1/branches، ثم تضيف جهازه بـPOST /v1/branches/{id}/devices مع الرمز، فيعود الرد 202 فورًا، ويكتمل طلب الشهادة وفحوص الامتثال الستة في الخلفية، عادة في أقل من دقيقة. وفاتورة الفرع تسمّي branch_id وdevice_id معًا، ويبقى الاسم القانوني والرقم الضريبي للمنشأة. ويعرض GET /v1/account الفروع وأجهزتها وتاريخ انتهاء الشهادة، فيستطيع نظامك أن ينبّه قبل الانتهاء لا بعده.

جرّب قبل الرقم الضريبي: وضع التجربة

لا تحتاج رقمًا ضريبيًا حقيقيًا لتكتب أول سطر. ابدأ في وضع التجربة: يُربط حسابك ببيئة الاختبار لدى الهيئة بهويتها الاختبارية، فتُصدر عبر الواجهة مستندات تُبنى وتُوقَّع وتُرسَل إلى تلك البيئة فعلًا، وتقرأ ردودها كما ستقرأ ردود الإنتاج. مستندات بيئة الاختبار ليست فواتير نظامية، وحين تنفد تجيب الواجهة 402 trial_exhausted، وعندها تربط المنشأة برقمها الضريبي ورمز OTP من بوابة فاتورة. وقبل أول فاتورة حقيقية تأكد أن الربط اكتمل: GET /v1/account يعيد "connected": true حين تكون المنشأة جاهزة للإصدار.

لا تريد كتابة كود؟ تكاملات جاهزة

الواجهة نفسها هي المحرك خلف لوحة ZATCA Tools وخلف تكاملاتها الجاهزة، فإن كان نظامك واحدًا منها فلا حاجة لأن تكتب شيئًا:

لشركات البرمجيات: مفتاح واحد لكل عملائك

إن كنت شركة برمجيات تخدم عشرات المنشآت من نظام واحد — ERP تنفّذه لعملائك، أو منصة حجوزات أو فوترة يستخدمها تجّار كثيرون — فالمفتاح العادي لا يكفيك لأنه يخص منشأة واحدة. Partner API تعطيك مفتاح شريك واحدًا يبدأ بـztkp_ يعمل باسم كل تاجر تنشئه، وكل نقطة نهاية في الواجهة تقبله مع ترويسة X-Merchant-Id. والمقارنة الكاملة بين بناء التكامل لكل عميل وتشغيل مكتبة مفتوحة واستخدام طبقة جاهزة في مقال شركات تنفيذ ERPNext. وإن كانت منصتك تُصدر طلبات لتجّار آخرين فاقرأ قبل الربط من يُصدر الفاتورة — المنصة أم التاجر؟.

متى لا تناسبك هذه الواجهة

نقولها قبل أن تجرّب، لأن اكتشافها بعد أسبوع من العمل أسوأ:

  • المبالغ بالريال السعودي فقط. كل مبلغ في الطلب والرد بالريال بمنزلتين عشريتين. إن كنت تُصدر فواتير بعملة أخرى فالواجهة لا تغطيها اليوم.
  • لا نُصدر فاتورة الدفعة المقدّمة (النوع 386). إن كان نشاط عملائك يقوم على دفعات مقدّمة تُخصم لاحقًا من الفاتورة النهائية، فاتفق مع المحاسب على معالجتها قبل أن تبني عليها.
  • لسنا نظام محاسبة. لا دفتر أستاذ ولا قيود يومية ولا مخزون ولا رواتب. نحن طبقة الامتثال: التوقيع والإجازة والتبليغ وحفظ الملف الموقّع. إن كانت المهمة «نحتاج محاسبة» فهذا ليس ذاك — راجع هل تحتاج برنامج محاسبة للفوترة الإلكترونية؟
  • إن كان مورّد نظامك يشحن وحدة مرحلة ثانية تعمل فعلًا، فقد لا تحتاج طبقة ثانية فوقها؛ جهازان وشهادتان لمهمة واحدة عمل مكرر لا فائدة منه.
  • إن كانت سياستك تمنع خروج بيانات الفواتير من خوادمك — عقد حكومي أو سياسة أمن معلومات — فالقرار محسوم: ابنِ التكامل أو شغّل مكتبة مفتوحة المصدر، والدليل يبدأ معك.

وللوضوح: ZATCA Tools منصة مستقلة لا تتبع هيئة الزكاة والضريبة والجمارك. الهيئة هي التي تُجيز كل فاتورة ضريبية وتستلم تبليغ كل مبسّطة وتتحقق منهما، وصحة ما ترسله — من الأسعار إلى بيانات المشتري — تبقى مسؤولية المنشأة التي تُصدر الفاتورة أيًّا كان الطريق الذي تختاره.

ابدأ من التوثيق

التوثيق الكامل في صفحة الواجهة، بالإنجليزية كما يُكتب توثيق الواجهات عادة: المصادقة، وجدول الأخطاء، وإعادة المحاولة، والأسطر والخصومات، وتعريف المشتري، والمعاملات الضريبية، والفروع والأجهزة، وكل نقطة نهاية بطلبها وردّها، مع أمثلة جاهزة بـcURL وNode.js وPHP وPython. وأسماء الأسطر في الأمثلة عربية كما سترسلها أنت.

المفتاح تولّده من إعدادات حسابك بعد ربط المنشأة، يبدأ بـztk_live_ ويُعرض مرة واحدة، فاحفظه في متغير بيئة لا في الكود. والواجهة متاحة من اليوم الأول، ضمن البداية المجانية نفسها لا في باقة أعلى. أنشئ حسابك من هنا — أسبوع مجانًا بدون دفع من يوم ربط منشأتك، ثم من 49 ريالًا شهريًا.

أسئلة شائعة

هل لهيئة الزكاة والضريبة والجمارك API خاصة بها؟ +
نعم. منصة فاتورة تتيح واجهات للربط والامتثال والإجازة والتبليغ، لكنها تستقبل ملف XML بصيغة UBL 2.1 موقّعًا بشهادة الجهاز، لا بيانات فاتورة خامًا. فمن يربط معها مباشرة يبني بنفسه طلب الشهادة وفحوص الامتثال والتوقيع وعدّاد الفواتير وسلسلة البصمات وتجديد الشهادة قبل انتهائها. أما واجهة ZATCA Tools فتستقبل الأسطر والمشتري بصيغة JSON وتتولى ذلك كله، ثم ترسل الفاتورة إلى الهيئة نفسها لتجيزها أو تستلم تبليغها، وتعيد إليك حكمها في الرد.
هل أحتاج رقمًا ضريبيًا لأجرّب الواجهة؟ +
لا. وضع التجربة يربط حسابك ببيئة الاختبار لدى الهيئة بهويتها الاختبارية، فتُصدر مستندات عبر الواجهة وتختبر الردود قبل أن تربط رقمًا ضريبيًا حقيقيًا. مستندات بيئة الاختبار ليست فواتير نظامية. وحين تنفد مستندات التجربة تجيب الواجهة بالرمز trial_exhausted، فتربط المنشأة برقمها الضريبي ورمز OTP من بوابة فاتورة لتبدأ الفواتير الفعلية.
بأي لغة برمجة أستدعي الواجهة؟ +
بأي لغة تستطيع إرسال طلب HTTPS بصيغة JSON مع ترويسة Authorization تحمل المفتاح. التوثيق يعرض أمثلة كل نقطة نهاية بأربع صيغ: cURL وNode.js وPHP وPython، والمبدأ نفسه في Java أو .NET أو Go أو غيرها. لا مكتبة خاصة تثبّتها، ولا توقيع ولا تشفير في جهتك.
ماذا يحدث إن رفضت الهيئة الفاتورة؟ +
يعود الرد برمز 201 وفيه status بقيمة rejected، وأسباب الهيئة في zatca.rejection كما قالتها. المستند المرفوض يحتفظ برقمه وموضعه في السلسلة كما يشترط النظام، فلا تعدّله ولا تحذفه: أصلح البيانات وأصدر فاتورة جديدة. والمستند المرفوض يعيد وحدته إلى رصيد باقتك، ولكل كود تحقق صفحة في مرجع أكواد الأخطاء بالعربية تشرح سببه وطريقة إصلاحه.
هل تدعم الواجهة عملات غير الريال السعودي؟ +
لا. كل المبالغ في الطلب والرد بالريال السعودي بمنزلتين عشريتين. إن كانت فواتيرك تصدر بعملة أجنبية فهذه الواجهة لا تغطيها اليوم، والأفضل أن تعرف ذلك قبل أن تبني عليها لا بعده.
جاهز تربط منشأتك؟

الربط مجاني ويستغرق أقل من خمس دقائق.

ابدأ مجانًا