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

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

نظامك يخدم تجارًا كثرًا — تكاملٌ واحد معنا يعطي كل واحد منهم منشأة فوترة كاملة لدى الهيئة: شهادته الخاصة، سلسلته الخاصة، وفواتير بلا حدّ. أنت تنشئ الحسابات برمجيًا، ونحن نتولى تعقيدات 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 ولا يُتبنّى — معرفتك ببريد تاجر ليست بابًا إلى حساب يملكه.

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",
    "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}إن نقصت. النقص يُرفضقبلصرف الرمز: رمز فاتورة يُستخدم مرة واحدة، وحرقه على نقص حقل هو أسوأ نسخ هذا الخطأ.

# 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 حرّرتَ اشتراكه — بياناته محفوظة ولا فوترة جديدة

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

من هنا وصاعدًا تستخدمواجهة الفواتير 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]— نتفق على الاشتراكات، وتستلم مفتاحك، وأول تاجر لك يُصدر خلال يوم.