البدء السريع
هذا الدليل يأخذك عبر مسار التكامل كاملاً: الحصول على مفاتيح الربط من لوحة تحكم التاجر في قروش، التأكد أن الاتصال يعمل، مزامنة الفروع وربطها، مزامنة عميل، ثم إرسال أول حدث بيع. الجزء البرمجي يستغرق نحو ١٥ دقيقة، وهناك خطوتان قصيرتان يقوم بهما التاجر في لوحة تحكم قروش.
كيف يعمل التكامل
نظامان يتخاطبان في الاتجاهين: منصتك تستدعي Quroosh Partner API، وقروش يرسل Webhooks إلى endpoint الاستقبال في منصتك. بعض الخطوات عندك، وبعضها عند التاجر في لوحة تحكم قروش:
| # | أين | ماذا يحدث |
|---|---|---|
| ١ | لوحة تحكم قروش (التاجر) | التاجر يفعّل التكامل ويحصل على مفتاح API وسر موقِّع — يظهران مرة واحدة — ويسلّمهما لك. |
| ٢ | منصتك | تخزّن القيمتين، ثم تستدعي GET /connection للتأكد أن الاتصال يعمل. |
| ٣ | منصتك | ترسل حدث BranchSynced لكل فرع من فروعك. |
| ٤ | لوحة تحكم قروش (التاجر) | التاجر يربط كل فرع من فروعك بفرع في قروش. المبيعات تُرفض حتى يكتمل هذا الربط. |
| ٥ | منصتك | ترسل CustomerSynced لعملائك، ثم InvoiceEarned مع كل عملية بيع. النقاط تُحتسب تلقائياً. |
| ٦ | قروش ← منصتك | قروش يرسل Webhooks (تغييرات قواعد الولاء، حالة التكامل) إلى endpoint الاستقبال لديك، موقَّعة بنفس السر. الـ header X-TenantId يخبرك لأي تاجر يعود التسليم. |
١. الحصول على مفاتيح الربط (لوحة تحكم قروش)
مفاتيح الربط يصدرها التاجر، وليس دعم قروش. في لوحة تحكم التاجر، يفتح التاجر صفحة التكاملات مع الشركاء، يختار منصتك وأي بيئة من بيئاتك يستهدفها التكامل (اختبارية أو إنتاجية — رابط الاستقبال لكل بيئة يُسجَّل لدى قروش عند تأسيس الشراكة)، يُدخل معرّف حساب التاجر على منصتك، ثم يفعّل. تعرض اللوحة عندها قيمتين مرة واحدة فقط:
| القيمة | شكلها | تستخدمها في |
|---|---|---|
| مفتاح API | qpk_9f2a… | يُرسل في header X-Api-Key مع كل طلب. المفتاح يحدد التاجر — لا ترسل معرّف التاجر في جسم الطلب أبداً. |
| السر الموقِّع | نص عشوائي | حساب header X-Signature على POST /events، والتحقق من توقيع Webhooks التي يرسلها قروش إليك. |
قروش يحتفظ بالتجزئة (hash) فقط ولا يعرض القيم الخام مرة أخرى. خزّن القيمتين في مخزن أسرار على خادمك. إذا فُقدت قيمة، يجدّدها التاجر من نفس الصفحة: التجديد يصدر قيمة جديدة بينما تبقى القديمة صالحة حتى تُلغى صراحةً، فالانتقال يتم دون أي انقطاع.
بيئة الاختبار والإنتاج منفصلتان: التاجر يفعّل التكامل في لوحة كل بيئة على حدة، وكل بيئة تصدر مفاتيحها الخاصة. مفتاح بيئة الاختبار يعمل فقط مع api-staging.quroosh.io.
٢. اختبار الاتصال
GET /connection هو اختبار الاتصال. استجابة ناجحة تثبت أن المفتاح وتحديد التاجر وحالة التكامل تعمل من البداية إلى النهاية، وتعيد اسم متجر التاجر — اعرضه بصيغة «متصل بـ …» ليُكتشف فوراً أي مفتاح لُصق لحساب خاطئ. طلبات GET لا تحتاج توقيعاً — المفتاح وحده يكفي:
curl https://api-staging.quroosh.io/api/partner/v1/connection \
-H "X-Api-Key: qpk_XXXXXXXXXXXX"200 OK:
{
"connected": true,
"storeId": "0195d0a0-0000-7000-8000-0000000000aa",
"storeName": "Karam Coffee",
"platform": "Kosoor",
"environment": "Production"
}environment هي البيئة التي يسلّم قروش الـ Webhooks إليها على جانبك — إذا ظهرت Testing وأنت تتوقع الإنتاج، فقد اختار التاجر البيئة الخاطئة عند التفعيل.
إذا فشل الطلب، كل الأخطاء تستخدم نفس البنية ({ "code", "message", "correlationId" }):
| الحالة | الرمز | الحل |
|---|---|---|
| 401 | MISSING_API_KEY | header X-Api-Key غير موجود. |
| 401 | INVALID_API_KEY | المفتاح غير معروف أو ملغى — تحقق من القيمة، أو اطلب من التاجر التجديد. |
| 401 | INTEGRATION_NOT_CONNECTED | التاجر لم يفعّل التكامل بعد (الخطوة ١). |
| 503 | INTEGRATION_PAUSED | التاجر أوقف التكامل مؤقتاً. المفاتيح ما زالت صالحة — أعد المحاولة لاحقاً. |
٣. مزامنة فروعك
كل ما ترسله إلى قروش يمر عبر endpoint واحد:POST /api/partner/v1/events. كل طلب هومظروف حدث موقَّع بسرّك. اكتب دالة الإرسال مرة واحدة وأعد استخدامها لكل أنواع الأحداث في هذا الدليل:
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
async Task<EventAckResponse?> SendEventAsync(
HttpClient client, string apiKey, string signingSecret,
string eventType, string entityType, string entityId, object payload)
{
// Serialize once so the bytes you sign are the exact bytes you send.
var rawBody = JsonSerializer.SerializeToUtf8Bytes(new
{
eventId = Guid.CreateVersion7(), // dedup key — one per business event
occurredAt = DateTimeOffset.UtcNow,
entityType,
entityId,
sourceSystem = "Kosoor", // your platform identifier
schemaVersion = 1,
correlationId = Guid.CreateVersion7(),
eventType,
payload
});
// X-Signature: t=<unix_ts>,v1=<hex> — HMAC-SHA256 over "{timestamp}." + raw body.
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
using var hmac = IncrementalHash.CreateHMAC(
HashAlgorithmName.SHA256,
Encoding.UTF8.GetBytes(signingSecret));
hmac.AppendData(Encoding.UTF8.GetBytes($"{timestamp}."));
hmac.AppendData(rawBody);
var signature = $"t={timestamp},v1={Convert.ToHexStringLower(hmac.GetHashAndReset())}";
using var content = new ByteArrayContent(rawBody);
content.Headers.ContentType = new("application/json");
using var request = new HttpRequestMessage(HttpMethod.Post, "api/partner/v1/events")
{
Content = content
};
request.Headers.Add("X-Api-Key", apiKey);
request.Headers.Add("X-Signature", signature);
using var response = await client.SendAsync(request);
return await response.Content.ReadFromJsonAsync<EventAckResponse>();
}HMAC يُحسب على تسلسل البايتات الذي سيستقبله قروش تماماً. إعادة تسلسل الـ JSON بين التوقيع والإرسال (فرق مسافات أو ترتيب مفاتيح) تُفشل التحقق — احتفظ بمصفوفة byte[] الخام وأعد استخدامها للتوقيع والإرسال معاً.
الآن عرّف قروش على كل فرع من فروعك بحدث BranchSynced:
var branchId = Guid.Parse("7c9e6679-7425-40de-963d-0d5f8b1a2c11"); // your branch's ID
var ack = await SendEventAsync(client, apiKey, signingSecret,
eventType: "BranchSynced",
entityType: "Branch",
entityId: branchId.ToString(),
payload: new
{
externalBranchId = branchId,
name = "Olaya Branch",
isActive = true
});200 OK:
{
"accepted": true,
"eventId": "0195d1c7-6e40-7f8e-9a2b-000000000001",
"alreadyProcessed": false
}accepted يعني أن الحدث سُجِّل. إعادة إرسال نفسeventId تُعيد الاستجابة المخزّنة معalreadyProcessed: true — المعالجة لا تحدث مرتين أبداً، فإعادة المحاولة آمنة دائماً.
٤. التاجر يربط الفروع (لوحة تحكم قروش)
كل فرع تزامنه يصل إلى قروش بحالة غير مربوط. قروش لا يُظهر أي تنبيه تلقائي — التاجر يفتح التكاملات مع الشركاء ← ربط الفروع، يختار الفرع المطابق في قروش لكل فرع من فروعك، ثم يؤكد. الربط يُعدَّل هناك فقط، فلا يمكن أن يختلف الطرفان على أي فرع يقابل أي فرع.
وتستطيع متابعة الحالة من جهتك في أي وقت:
curl https://api-staging.quroosh.io/api/partner/v1/branch-mappings \
-H "X-Api-Key: qpk_XXXXXXXXXXXX"{
"mappings": [
{
"externalBranchId": "7c9e6679-7425-40de-963d-0d5f8b1a2c11",
"externalBranchName": "Olaya Branch",
"status": "Mapped",
"mappedStoreId": "0195d0a0-0000-7000-8000-0000000000aa",
"mappedStoreName": "Karam Coffee",
"mappedBranchId": "0195d0a0-0000-7000-8000-000000000001",
"mappedBranchName": "Olaya"
}
]
}حدث InvoiceEarned لفرع غير معروف يفشل برمزBRANCH_MAPPING_NOT_FOUND، ولفرع مُزامَن لكن غير مؤكد برمز BRANCH_MAPPING_UNCONFIRMED. الأحداث الفاشلة لا تُخزَّن أبداً — بمجرد أن يؤكد التاجر الربط، أعد إرسال نفس الحدث (بنفس eventId) وسينجح.
٥. مزامنة عميل
قروش يطابق عمليات الكسب مع أعضاء الولاء عبر معرّف العميل عندك، لذا يجب مزامنة العميل قبل أول فاتورة له. نفس دالة الإرسال، بمحتوى مختلف:
var ack = await SendEventAsync(client, apiKey, signingSecret,
eventType: "CustomerSynced",
entityType: "Customer",
entityId: "cust_012345",
payload: new
{
externalCustomerId = "cust_012345",
phone = "+966501234567",
firstName = "Sara",
lastName = "Alqahtani"
});أرسل الحدث عند إنشاء العميل وعند تعديله. رقم الجوال هو ما يربط عميلك بحسابه في برنامج الولاء.
٦. إرسال أول عملية بيع
اللحظة التي بنيت كل ما سبق لأجلها — عميل يكسب نقاطاً على فاتورة بقيمة ١٠٤٫٣٥ ريال:
var invoiceId = Guid.CreateVersion7();
var ack = await SendEventAsync(client, apiKey, signingSecret,
eventType: "InvoiceEarned",
entityType: "Invoice",
entityId: invoiceId.ToString(),
payload: new
{
externalInvoiceId = invoiceId,
externalCustomerId = "cust_012345",
externalBranchId = branchId,
subtotalAfterDiscountBeforeVat = 104.35m,
earnType = "Points",
stampCardId = (Guid?)null,
channel = "Pos"
});
Console.WriteLine($"accepted={ack!.Accepted} alreadyProcessed={ack.AlreadyProcessed}");accepted: true ورصيد العميل يتحرك. من هنا فصاعداً، أرسلInvoiceEarned مع كل عملية بيع مكتملة.
٧. ماذا تبني بعد ذلك
- الاستعلام عند الكاشير —
GET /customers/lookup?phone=…يعيد رصيد العميل ومستواه ومكافآته القابلة للاستبدال وتقدّم الأختام لحظياً عند نقطة البيع. راجع الاستعلام عن العملاء. - المنتجات والكوبونات — أرسل
ProductSyncedوCouponSyncedبنفس طريقة مزامنة الفروع، إضافة إلىCouponUsed/CouponUsageCancelledعند الاستخدام. بعدها يربط التاجر مكافآت قروش بمنتجاتك من محرر المكافآت. راجع أنواع الأحداث لكل البنى. - استقبال Webhooks — قروش يرسل
LoyaltyRuleChangedوIntegrationStatusChangedإلى endpoint الاستقبال المسجَّل لديك، موقَّعة بنفس منظومةX-Signature؛ وجّه كل تسليم حسب الـ headerX-TenantId. راجع Webhooksلكود التحقق وجدول إعادة المحاولة.
قائمة التحقق قبل الإطلاق
GET /connectionيعيد اسم متجر التاجر على بيئة الاختبار.- كل فرع يظهر بحالة
MappedفيGET /branch-mappings. - العملاء يتزامنون عند الإنشاء وعند التعديل.
- حدث
InvoiceEarnedيُقبل، وإعادة إرسال نفسeventIdتعيدalreadyProcessed: true. - رابط الاستقبال عندك يتحقق من
X-Signatureويستجيب بـ 2xx. - التاجر يفعّل التكامل على بيئة الإنتاج وتستبدل مفاتيح الإنتاج بمفاتيح الاختبار.
تابع القراءة
- المصادقة — منظومة التوقيع بالتفصيل، تجديد المفاتيح، رموز الأخطاء.
- أنواع الأحداث — الكتالوج الكامل لـ ١٦ حدثاً وبنى المحتوى.
- الأخطاء — كل رموز الأخطاء، بما فيها رموز معالجة الأحداث.
- مرجع API — بنى الطلبات والاستجابات مع ساحة تجربة مباشرة.