لشركات البرمجيات ونقاط البيع

واجهة الشركاء

نظامك يخدم تجارًا كثرًا — تكاملٌ واحد معنا يعطي كل واحد منهم منشأة فوترة كاملة لدى الهيئة: شهادته الخاصة، سلسلته الخاصة، وفواتير بلا حدّ. أنت تنشئ الحسابات برمجيًا، ونحن نتولى تعقيدات ZATCA.

BASE URL https://zatcatools.com/api/partner
Building the integration? The full English API Reference — every endpoint, parameter and error code — lives at /docs/partner-api. API Reference →

كيف تعمل

الهيئة تُصدر الشهاداتلكل مكلَّف على حدة— لا وجود لشهادة مشتركة يُوقَّع بها عن الجميع. لذلك كل تاجر تنشئه عبر هذه الواجهة هو منشأة مستقلة كاملة: رقمه الضريبي، شهادته، سلسلة فواتيره (ICV/PIH)، وأرشيفه. ما توفره الواجهة هو أنك تنشئ هذه المنشآت وتديرها من نظامك بدل أن يسجّل كل تاجر بنفسه.

الخطوة من يقوم بها كيف
1 · إنشاء منشأة التاجرنظامكPOST /merchants
2 · الربط مع بوابة فاتورةنظامك — والتاجر يجلب الرمزPOST /merchants/{id}/connect
3 · إصدار الفواتيرنظامكPOST /api/v1/invoices + X-Merchant-Id

الاشتراكات:اتفاقك معنا يحدد عدد اشتراكات التجار المدفوعة. كل تاجر نشط يستهلك اشتراكًا، وإيقاف اشتراك تاجرٍ غادَرَ يُعيده لرصيدك. حين يُستهلك الرصيد ترجع الواجهة402 seat_limit_reached— تواصل معنا لزيادتها.

حقيقة رمز فاتورة — اقرأها قبل أن تكتب سطرًا

خطوة واحدة في الرحلة كلها لا يمكن لأي واجهة برمجية أن تتولاها عن التاجر:رمز التحقق (OTP) من بوابة فاتورة. الهيئة تُصدره للمكلَّف نفسه داخل بوابتهاfatoora.zatca.gov.sa، ولا يصل إلينا ولا إليك. هذا قيد من الهيئة على السوق كله، لا قيد عندنا.

القيد علىمصدر الرمزفقط — أما إدخاله فيحدثداخل شاشتك أنت: اعرض لتاجرك «أدخل رمز التحقق من بوابة فاتورة»، ومرّر ما يكتبه إلىPOST /merchants/{id}/connectوتابع التقدم منGET /merchants/{id}/status— الشهادة وفحوص التوافق الستة خلال دقيقتين تقريبًا، وتاجرك لم يغادر نظامك. والقاعدة نفسها تنطبق على كل جهاز فرع لاحقًا:رمز جديد لكل جهاز(إلحاق حل فوترة جديد ← عدد الأجهزة) — تفاصيلها فيفروع التاجر وأجهزته.

لا تريد بناء الشاشة؟onboarding_urlيبقى بديلًا جاهزًا: رابط موقَّع يفتح صفحتنا على الخطوة نفسها.

الاستيثاق

مفتاح الشريك يبدأ بـztkp_live_وتستلمه منا عند توقيع الاتفاق — يظهر مرة واحدة، فخزّنه في متغير بيئة. وهو للأنظمة فقط:بوابة الشركاء تفتح ببريدك المسجّل ورمز تحقق، فلا يحتاج مفتاحك أن يمر بحافظة أحد. وهو مفتاحكالوحيد: يدير حساباتك هنا،ويُصدر فواتير كل تجّاركعلى واجهة الفواتير — التاجر المقصود تسمّيه في كل نداء بترويسةX-Merchant-Id. سرّ واحد في خزنتك، وتدوير واحد تديره.

curl https://zatcatools.com/api/partner/account \
  -H "Authorization: Bearer ztkp_live_..."

الأخطاء

HTTP code المعنى
401 unauthenticated مفتاح الشريك مفقود أو غير صحيح — أو أرسلت مفتاح تاجر بالخطأ
402 seat_limit_reached كل اشتراكاتك المدفوعة مشغولة — حرّر اشتراكًا أو تواصل لزيادتها
403 partner_suspended حساب الشراكة موقوف — تواصل معنا
404 not_found لا تاجر بهذا المعرّف ضمن شراكتك
409 email_taken / vat_taken البريد له حساب قائم، أو الرقم الضريبي مسجّل لمنشأة أخرى
422 validation_failed بيانات ناقصة أو غير صالحة — الرسالة توضح السبب
429 too_many_requests تجاوزت حد الطلبات (120/دقيقة)

حسابك واشتراكاتك

GET /api/partner/account

{
  "partner": {
    "name": "Smart POS Co.",
    "status": "active",
    "seats": { "limit": 50, "used": 34, "remaining": 16 }
  }
}

إنشاء تاجر

POST /api/partner/merchants

يستهلك اشتراكًا وينشئ منشأة كاملة بفوترةبلا حدّ. nameوemailإلزاميان؛vat_numberإلزامي أيضًا — هو هوية المنشأة لدى الهيئة، ونظامك يعرفه عن عميله دائمًا. السجل التجاري اختياري. وللعنوان أرسلshort_address— العنوان الوطني المختصر (4 أحرف و4 أرقام، مثلRRRD2929): نحلّ منه العنوان التفصيلي كاملًا تلقائيًا كما في التسجيل العادي، وإن تعذّر الحلّ يكمل التاجر بياناته في خطوة الـOnboarding — لا شيء يتعطل. البريد يجب أن يكونجديدًا عندنا: بريد له حساب قائم يُرفض بـ409 ولا يُتبنّى — معرفتك ببريد تاجر ليست بابًا إلى حساب يملكه.

ومع رقم التسجيل أرسلcr_scheme— أي وثيقة هو. الافتراضيCRNأي سجل تجاري من عشرة أرقام؛ ومن يعمل بترخيص أو برقم موحّد يرسلMOMلترخيص وزارة الشؤون البلدية، أوMLSلترخيص وزارة الموارد البشرية، أوSAGلترخيص وزارة الاستثمار، أو700للرقم الموحد، أوOTH. رمز خارج هذه القائمة يُرفض ولا يُقرأ سجلًا تجاريًا: كل مستند نوقّعه بعدها سيسمّي الوثيقة الخطأ. وهذا هو الحقل نفسه الذي يختاره التاجر منالإعدادات ← ملف المنشأة.

curl -X POST https://zatcatools.com/api/partner/merchants \
  -H "Authorization: Bearer ztkp_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "مطعم الذواقة — فرع المروج",
    "email": "[email protected]",
    "vat_number": "310000000000003",
    "cr_number": "1010203040",
    "cr_scheme": "CRN",
    "short_address": "RRRD2929"
  }'
HTTP/1.1 201 Created
{
  "merchant": { "id": 34, "name": "…", "status": "awaiting_onboarding", "seat": "active" },
  "onboarding_url": "https://…",     // موقَّع، صالح 72 ساعة
  "seats": { "limit": 50, "used": 35, "remaining": 15 }
}

لا مفتاح لكل تاجر — خزّنmerchant.idمقابل عميلك في نظامك: هو ما يذهب في ترويسةX-Merchant-Idمع مفتاح شراكتك في كل نداء فوترة.

ربط التاجر — من داخل شاشتك

POST /api/partner/merchants/{id}/connect · GET /api/partner/merchants/{id}/status

قبل النداء تأكد أن بيانات المنشأة مكتملة —nameوvat_numberوcr_numberوshort_address— أكملها بـPATCH /merchants/{id}إن نقصت. النقص يُرفضقبلصرف الرمز: رمز فاتورة يُستخدم مرة واحدة، وحرقه على نقص حقل هو أسوأ نسخ هذا الخطأ.

ويُقرأcr_numberبحسبcr_schemeالخاص بالتاجر نفسه — فالترخيص لا يُطالب بأن يبدو سجلًا تجاريًا من عشرة أرقام.

# The merchant typed the six digits into YOUR screen:
curl -X POST https://zatcatools.com/api/partner/merchants/34/connect \
  -H "Authorization: Bearer ztkp_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "otp": "123456" }'

HTTP/1.1 202 Accepted
{ "status": "connecting", "poll": "…/merchants/34/status" }
# Poll every couple of seconds while your checklist spins:
GET /api/partner/merchants/34/status
{
  "connected": false, "connecting": true, "stalled": false,
  "compliance_passed": 4,        // of the 6 checks
  "error": null
}
# …until:
{ "connected": true, "compliance_passed": 6, "certificate_expires_at": "2029-08-31" }

errorيهمك منه اثنان:otp_invalid— الرمز خاطئ أو منتهٍ، اطلب من تاجرك رمزًا جديدًا؛ وstalled: true— توقف العدّ، أعد المحاولة برمز جديد. وبعد الربط تُقفل حقول الهوية (الاسم والرقم الضريبي والسجل): الشهادة الصادرة تحملها، وتغييرها يجعل الوثائق تخالف شهادتها.

قائمة التجار وتفاصيلهم

GET /api/partner/merchants · GET /api/partner/merchants/{id}

الحقل الذي تبني عليه شاشتك هوstatus:

awaiting_onboarding أُنشئ ولم يُكمل الربط — اعرض له رابط الإكمال
connected مرتبط بالهيئة — فواتيره تصدر الآن
failed آخر محاولة ربط فشلت — اطلب رابطًا جديدًا وأعد توجيهه
trial يجرّب على بيئة الهيئة التجريبية
released حرّرتَ اشتراكه — بياناته محفوظة ولا فوترة جديدة

إصدار الفواتير

المشتري الذي لا يحمل رقمًا ضريبيًا — جهة حكومية أو منشأة صغيرة أو فرد — يُعرَّف بـcr_numberمصحوبًا بـid_schemeداخل كائنcustomer؛ فالرقم الموحد700للجهات الحكومية، وNATللهوية الوطنية، وIQAللإقامة. والسطر المعفى تعليمًا أو صحة يلزمهNATتحديدًا (BR-KSA-49). التفاصيل كاملة فيمرجع الواجهة.

من هنا وصاعدًا تستخدمواجهة الفواتير v1 بمفتاح شراكتك نفسه+ ترويسة تسمّي التاجر — إصدار، إشعارات دائن ومدين، XML وPDF وQR. مثال بيع من نقطة بيعك:

curl -X POST https://zatcatools.com/api/v1/invoices \
  -H "Authorization: Bearer ztkp_live_…" \
  -H "X-Merchant-Id: 34"                  # التاجر صاحب هذا البيع \
  -H "Content-Type: application/json" \
  -d '{
    "type": "simplified",
    "branch_id": 3,                  // البيع من فرع؟ سمِّ الفرع وجهازه معًا —
    "device_id": 7,                  // القاعدة نفسها للضريبية والمبسطة سواء
    "lines": [
      { "name": "وجبة غداء", "quantity": 2, "unit_price": 45.00 },
      { "name": "دواء", "quantity": 1, "unit_price": 120.00,
        "tax_category": "Z", "tax_reason_code": "VATEX-SA-35" }
    ]
  }'

البنود تقبلtax_category (Sافتراضيًا ·Zصفرية ·Eمعفاة ·Oخارج النطاق) — والفئات غير الخاضعة تتطلبtax_reason_codeمن قائمة الهيئة، والفاتورة الواحدة تجمع فئات مختلفة بلا مشكلة. والبيع من فرع يسمّيbranch_idوdevice_idمعًا — للضريبية والمبسطة سواء؛ التفاصيل فيفروع التاجر وأجهزتهأدناه.

فروع التاجر وأجهزته

تاجرك له أكثر من نقطة بيع؟ كل الفروع تحت رقمه الضريبي، لكن كل فرع يُصدر عبرجهازه الخاص (EGS unit) — نموذج الهيئة نفسه: التاجر يولّد من بوابة فاتورة رمز OTPلكل جهاز(إلحاق حل فوترة جديد ← عدد الأجهزة)، أنت تجمعه في شاشتك وتمرره لنا، وكل جهاز يخرج بشهادته وسلسلة فواتيره المستقلة. ربط المنشأة الأساسي (أعلاه) هو جهاز المقر الرئيسي؛ ما يلي للفروع. نفس مفتاحك + ترويسة التاجر:

# 1. الفرع
curl -X POST https://zatcatools.com/api/v1/branches \
  -H "Authorization: Bearer ztkp_live_…" -H "X-Merchant-Id: 34" \
  -d '{ "name": "فرع النخيل مول", "cr_number": "1010999888", "short_address": "RESB3139" }'
# → 201 { "branch": { "id": 3, … } }

# 2. جهاز الفرع — otp جمعته من شاشة تاجرك
curl -X POST https://zatcatools.com/api/v1/branches/3/devices \
  -H "Authorization: Bearer ztkp_live_…" -H "X-Merchant-Id: 34" \
  -d '{ "otp": "482913", "name": "كاشير 1" }'
# → 202 { "device": { "id": 7, "status": "pending", … } }

# 3. تتبّع حتى connected (عادة أقل من دقيقة)
curl https://zatcatools.com/api/v1/devices/7 \
  -H "Authorization: Bearer ztkp_live_…" -H "X-Merchant-Id: 34"
# → { "device": { "status": "connected", "usable": true, … } }

# 4. بيع من الفرع — الفاتورة تسمّي فرعها وجهازها معًا
curl -X POST https://zatcatools.com/api/v1/invoices \
  -H "Authorization: Bearer ztkp_live_…" -H "X-Merchant-Id: 34" \
  -d '{ "type": "simplified", "branch_id": 3, "device_id": 7,
        "lines": [{ "name": "وجبة", "quantity": 1, "unit_price": 45 }] }'

الفرع الواحد يتحمّل عدة أجهزة — كرر الخطوة 2 برمز OTP جديد لكل جهاز، وكلٌّ بسلسلته المستقلة فتُصدر نقاط البيع بالتوازي.فاتورة الفرع تسمّي جهازها: خزّنdevice_idعند كل نقطة بيع ومرّره معbranch_idعلى كل فاتورة — أحدهما بلا الآخر يُرفض (device_required / branch_required)، وجهاز غير متصل يُرفض بـdevice_not_usable. الإشعارات تتبع فرع فاتورتها الأصل تلقائيًا وجهازها عليها اختياري. فشل التفعيل بـotp_invalid؟ الرمز خُطئ أو انتهت ساعته أو استُهلك — اطلب من تاجرك رمزًا جديدًا وأعد التفعيل على نفس الجهاز:POST /v1/devices/{id}/connect. القائمة الكاملة للفروع وأجهزتها دائمًا علىGET /v1/account.

إيقاف اشتراك وإعادته

POST /api/partner/merchants/{id}/release · POST /api/partner/merchants/{id}/reinstate

تاجر غادر نظامك؟ أوقف اشتراكه ليخدم غيره. الإيقافلا يحذف شيئًا أبدًا— الهيئة تُلزم بأرشيف ست سنوات، وسلسلة الفواتير لا تنقطع: المنشأة ووثائقها ودخول صاحبها كلها تبقى،وقراءة أرشيفه عبر الـ API تبقى أيضًا(كل نداءاتGETتعمل للموقوف — تصدير وتدقيق بلا انقطاع)؛ الذي يتوقف هو الفوترة الجديدة وكل فعل يُنشئ شيئًا. عاد التاجر؟reinstateيعيد تفعيله على اشتراك شاغر ويستأنف سلسلته من حيث توقفت.

حدود الاستخدام

واجهة الشركاء:120 طلبًا في الدقيقة. واجهة الفواتير:60 طلبًا في الدقيقةعلى مفتاحك — يكفي مئات نقاط البيع في الاستخدام الواقعي؛ ولو بلغت حجمًا يتجاوزه فراسلنا ونرفعه لك.

جاهز تبدأ؟راسلنا على[email protected]— نتفق على الاشتراكات، وتستلم مفتاحك، وأول تاجر لك يُصدر خلال يوم.