إنتقل إلى المحتوى الرئيسي

أكّد الوجهة قبل الإرسال

تتيح Delivery Intelligence للتاجر اقتراح وجهة وطلب تأكيدها أو تصحيحها من المستلم والحصول على نتيجة موثوقة قبل تنفيذ الطلب.

المسار من البداية إلى النهاية​

  1. ينشئ خادمك الخلفي طلب تأكيد.
  2. في Production، ترسل Alkax للمستلم رابطًا آمنًا محدود الصلاحية. تسجل Sandbox إشعارًا محجوبًا في مخزن الاختبار؛ افتح الرابط المعاد يدويًا.
  3. يراجع المستلم الوجهة المقترحة دون الحاجة إلى حساب Alkax.
  4. يحتفظ بها أو يختار مكان Alkax نشطًا آخر أو ينشئ مكانًا مفقودًا.
  5. يمكنه إضافة صورة خاصة للمدخل، تبقى غير متاحة حتى اعتمادها في المراجعة.
  6. تسجّل Alkax اللقطة المؤكّدة أو المصحّحة.
  7. يجلب خادمك النتيجة أو يستقبل خطاف ويب موقّعًا.

قبل البدء​

أنشئ مشروعًا في لوحة المطورين وأصدر بيانات اعتماد خاصة بالبيئة بالنطاقات المطلوبة:

  • delivery:write للإنشاء والإلغاء وإعادة الإرسال وإعادة التشغيل؛
  • delivery:read لجلب النتائج.

تكون بيانات اعتماد Sandbox بالشكل ak_test_<key-id>.<secret> وProduction بالشكل ak_live_<key-id>.<secret>. احفظ القيمة الكاملة في مدير أسرار. تُعرض مرة واحدة ويجب ألا توضع في كود المتصفح أو الهاتف.

export ALKAX_BASE_URL="https://api.alkax.io"
export ALKAX_API_KEY="ak_test_<key-id>.<secret>"

1. جهّز خطاف الويب​

استخدم نقطة نهاية HTTPS عامة تعيد 2xx فقط بعد قبول الحدث وتخزينه بصورة مستديمة:

POST https://merchant.example/webhooks/alkax

ترفض Alkax الوجهات غير المشفّرة بـ HTTPS ووجهات الحلقة المحلية والشبكات الخاصة ولا تتبع إعادة التوجيه.

2. أنشئ تأكيدًا​

استبدل expiresAt بطابع زمني مستقبلي بتوقيت UTC وrecipientContact بصندوق اختبار تتحكّم فيه قبل تشغيل الطلب. قالب الحمولة أدناه غير قابل للتنفيذ حتى توفير هاتين القيمتين.

ولّد مفتاح عدم تكرار أثر لكل محاولة منطقية لعنوان طلب. أعد استخدامه فقط عند إعادة الطلب المطابق تمامًا.

لا يرسل مثال Sandbox بريدًا. قد ترسل Production بريدًا، لذا احصل على موافقة المستلم أولًا.

curl --request POST "$ALKAX_BASE_URL/api/v1/address-confirmations" \
--header "X-Alkax-Key: $ALKAX_API_KEY" \
--header "Idempotency-Key: order-1042-address-v1" \
--header "Content-Type: application/json" \
--header "Accept-Language: fr" \
--data '{
"merchantReference": "ORDER-1042",
"recipientContact": "[email protected]",
"locale": "fr",
"expiresAt": "<UTC timestamp in the future>",
"proposedAddress": {
"placeId": null,
"title": "Bonaberi depot",
"plusCode": "6GCR+8J",
"settlement": "Douala",
"locality": "Bonaberi",
"country": "CM",
"buildingName": null,
"floor": null,
"unit": null,
"latitude": 4.08,
"longitude": 9.66
},
"callbackUrl": "https://merchant.example/webhooks/alkax"
}'

تتضمن استجابة 201 الأولية:

  • id، معرّف الطلب في Alkax؛
  • recipientUrl، يُعاد عند الإنشاء الأولي فقط؛
  • webhookSigningSecret، يُعاد عند الإنشاء الأولي فقط عندما تنشئ Alkax سر الاستدعاء.

احفظ سر التوقيع فورًا. لا تستطيع Alkax إعادته مرة أخرى.

3. اقرأ دورة الحياة​

curl "$ALKAX_BASE_URL/api/v1/address-confirmations/<request-id>" \
--header "X-Alkax-Key: $ALKAX_API_KEY" \
--header "Accept-Language: en"
الحالةالمعنى
Pendingأُنشئ الطلب؛ ولم يفتح المستلم الرابط النشط
Openedفتح المستلم تجربة التأكيد
Confirmedقبل المستلم الوجهة
Correctedاختار المستلم وجهة مختلفة أو أنشأها
Expiredانتهت مدة الطلب دون إكماله
Cancelledأنهى التاجر الطلب

استخدم اللقطة المؤكّدة غير القابلة للتعديل لتنفيذ الطلب. لا تُعِد بناءها من نص العرض أو الاقتراح الأصلي. عند التقييم، قد تتضمن الاستجابة أيضًا confidenceScore وconfidenceBand وconfidencePolicyVersion.

4. تحقّق من توقيعات خطاف الويب​

يتضمن كل خطاف ويب:

X-Alkax-Event-Id: <UUID>
X-Alkax-Timestamp: <Unix seconds>
X-Alkax-Signature: v1=<hex HMAC-SHA256>

البايتات الموقّعة هي:

<timestamp>.<raw HTTP request body>

مثال Node.js:

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyAlkaxWebhook({ rawBody, timestamp, signature, secret }, nowSeconds = Math.floor(Date.now() / 1000)) {
if (!Buffer.isBuffer(rawBody) || typeof timestamp !== "string" || !/^\d{1,12}$/.test(timestamp) ||
Math.abs(nowSeconds - Number(timestamp)) > 300 || typeof signature !== "string" ||
!/^v1=[a-f0-9]{64}$/.test(signature) || typeof secret !== "string" || !secret) return false;
const expected = createHmac("sha256", secret)
.update(`${timestamp}.`, "utf8")
.update(rawBody)
.digest();
const supplied = Buffer.from(signature.slice(3), "hex");
return supplied.length === expected.length && timingSafeEqual(supplied, expected);
}

عالج الحدث بهذا الترتيب:

  1. ارفض الطوابع الزمنية خارج نافذة حداثة مدتها خمس دقائق.
  2. تحقّق من التوقيع على الجسم الخام دون تعديل، ثم طابق eventId المحلل مع الترويسة.
  3. احفظ هوية البيئة والحدث وبصمة الجسم الخام بقيد فريد.
  4. إذا كانت الهوية موجودة بالبصمة نفسها، فأعد 2xx دون تكرار الآثار. البصمة المختلفة خطأ في السلامة؛ لا تطبق تغييرات على الحالة.
  5. ثبّت الحدث وتغيير الأعمال قبل إعادة 2xx.

تعيد Alkax المحاولة عند انتهاء المهلة و408 و425 و429 و5xx. يبقى معرّف الحدث والحمولة ثابتين عبر إعادة المحاولات وإعادة التشغيل اليدوي.

الإجراءات التشغيلية​

الإجراءنقطة النهايةالنطاق المطلوب
الإلغاءPOST /api/v1/address-confirmations/{id}/cancelكتابة
إعادة إرسال رابط المستلمPOST /api/v1/address-confirmations/{id}/resendكتابة
إعادة تشغيل خطاف ويب متعذّرPOST /api/v1/address-confirmations/webhooks/{eventId}/replayكتابة

تدوّر إعادة الإرسال رمز المستلم وتخضع لحد المعدّل. لا يستطيع طلب ملغى أو مكتمل أو منتهي الصلاحية إرسال إشعار قابل للتنفيذ.

الأخطاء وإعادة المحاولة​

  • 400: صحّح الطلب؛ لا تُعده دون تعديل.
  • 401: بيانات الاعتماد مفقودة أو غير سليمة التنسيق أو غير صالحة أو منتهية أو ملغاة.
  • 403: تفتقر بيانات الاعتماد إلى النطاق المطلوب أو الوصول للإنتاج.
  • 404: الطلب غير موجود لدى مستأجر هذا التاجر.
  • 409: افحص دورة الحياة أو تعارض عدم تكرار الأثر.
  • 429: التزم بـ Retry-After وأضف تراجعًا بتفاوت عشوائي.
  • 5xx: أعد المحاولة بتراجع أُسّي ومفتاح عدم تكرار الأثر نفسه.

تدعم الأخطاء المقروءة بشريًا الإنجليزية والفرنسية والعربية والبرتغالية والسواحيلية. احفظ الرموز المقروءة آليًا بدلًا من مطابقة النص المترجم.

قائمة تحقّق الإطلاق​

  • احفظ بيانات اعتماد المشروع وأسرار التوقيع في مدير أسرار.
  • احجب بيانات اتصال المستلمين وروابطهم والتعليمات الخاصة ووسائط المدخل من السجلات.
  • احتفظ بجسم خطاف الويب الخام.
  • أزل التكرار حسب معرّف الحدث.
  • نبّه عند استمرار استجابات 429/5xx وتراكم خطافات الويب.
  • اختبر التأكيد والتصحيح وانتهاء الصلاحية والإلغاء وإعادة الإرسال وتسليم خطاف ويب مكرر.

عقد الاستدعاء القابل للاسترداد​

لإتاحة استرداد الإنشاء، أنشئ سرًا لكل محاولة وشفّره في تخزين دائم قبل استدعاء Alkax. عيّن الحقل الاختياري callbackSigningSecret إلى 64 محرفًا سداسيًا عشريًا صغيرًا ناتجًا عن 32 بايت عشوائيًا؛ ويتطلب callbackUrl. يُستخدم السر كنص UTF-8 لتوقيع HMAC ولا يُعاد مطلقًا. عند حذفه، تنشئ Alkax سرًا وتعيده مرة واحدة في webhookSigningSecret.

عيّن callbackSchemaVersion إلى v2 لتلقي الاستدعاء المختصر الصريح أدناه. احذفه أو اختر v1 للاحتفاظ بالاستدعاء السابق ذي الخصائص الداخلية PascalCase والحالة الرقمية. تستخدم استجابات HTTP للتأكيد خصائص camelCase وحالات نصية؛ وهذه ثلاثة تنسيقات مختلفة. تُحفظ النسخة الفعلية، وتحافظ إعادة التشغيل على معرّف الحدث وبايتات الحمولة الموجودة في قائمة الانتظار كما هي.

تحتفظ محاولات الإنشاء المتطابقة بالطلب نفسه وتعيد حقول الاستخدام الواحد فارغة، حتى بعد انتهاء صلاحية الرابط الأصلي. ما زالت العملية الجديدة تتطلب وقت انتهاء مستقبليًا. احتفظ بالحمولة الأصلية الدقيقة ومفتاح منع التكرار؛ تؤدي الخيارات المعدّلة إلى تعارض. تحتاج كل محاولة جديدة إلى مرجع مبهم خاص بها داخل المشروع والبيئة. تتضمن الاستجابة الخاصة الأساسية deliveryInstructions وcreatedAt وcancelledAt؛ وليست عرضًا عامًا للمهمة.

في الاستدعاء أدناه، طابق eventId مع الترويسة، وتحقق من التوقيع الخام وحداثته، وأزل التكرار بصورة دائمة، ثم اجلب النتيجة الأساسية عبر طلب موثّق. لا يحتوي الاستدعاء المختصر على إحداثيات أو تعليمات أو روابط وصول. تبقى أحداث اشتراكات المشروع قناة منفصلة. تكون هويات الإنشاء والإلغاء فيها ثابتة لكل تأكيد وانتقال؛ ولا يزيل ذلك التكرار الدلالي في قناة الاستدعاء السابقة لكل تأكيد.

{
"schemaVersion": "v2",
"eventId": "11111111-1111-4111-8111-111111111111",
"type": "address_confirmation.confirmed",
"occurredAt": "2026-10-25T12:00:00+00:00",
"request": {
"id": "22222222-2222-4222-8222-222222222222",
"merchantReference": "opaque-attempt-reference",
"status": "Confirmed",
"expiresAt": "2026-10-26T12:00:00+00:00"
}
}

تسجل Sandbox إشعارات المستلمين في مخزن اختبار ولا ترسل بريدًا للمستلم. اختبر الرابط المعاد يدويًا؛ ويتطلب تفعيل Production اختبار قبول مستضافًا.

انشر نسخة المزوّد المتوافقة قبل استخدام الخيارات الإضافية. قد تظل الحالة الأساسية المسجلة Pending أو Opened بعد الموعد حتى اكتشاف انتهاء الصلاحية؛ وتبقى تسوية الانتهاء الخلفية شرطًا للإصدار. لا يبطل موعد الرابط لقطة اكتمل تأكيدها. قد تحتفظ تغييرات النقطة الخاصة بالحالة Confirmed عند ثبات معرّفات المكان: قارن اللقطة الأساسية الدقيقة وأدر نسخة للوجهة بدل الاعتماد على التصنيف وحده. لا ينفذ عقد الاسترداد وحده موافقة VolXpr أو الإفصاح. يُفعّل العرض الخاص المستضاف بشكل منفصل عبر خيار السياق أدناه.

الزيارات المجتمعية الخاصة​

لزيارة منزلية خاصة، أضف الحقول التالية إلى طلب الإنشاء المعتاد:

{ "presentationContext": "private_visit", "locale": "fr" }

الحقل presentationContext اختياري؛ وغيابه يحافظ على تجربة التسليم المعتادة. القيمة الوحيدة المقبولة هي private_visit. تُحفظ مع التأكيد وتدخل في المطابقة التكرارية؛ تغييرها يتطلب محاولة ومرجعًا جديدين. تعيد استجابات الإنشاء وGET المصادق عليها هذه القيمة المرتبطة بالخادم لكشف مزود قديم يتجاهل الخيار.

توضح صفحة الزيارة أن المنزل يبقى خاصًا، وتخفي إنشاء الأماكن العامة وجمع الصور، وتسمح بدبوس خاص دقيق أو نقطة لقاء عامة موجودة اختياريًا. لا ينشئ الإكمال مكانًا عامًا ولا يعدّله. يرفض الخادم entranceImageReference للزيارات الخاصة، حتى للطلبات خارج الواجهة.

تتضمن الاستجابة العامة effectiveLocale بعد تطبيعه إلى en أو fr أو ar أو pt أو sw، مع الإنجليزية كخيار احتياطي. تستخدم رسالة الزيارة وصفحتها الأولية اللغة المطلوبة نفسها. يمكن تغيير اللغة دون فقدان المدخلات وتُدعم العربية من اليمين لليسار. تعرض الأعطال المؤقتة إعادة المحاولة بدلاً من اعتبار الرابط غير صالح.

حتى انتهاء صلاحية الرابط الأصلي، تعيد محاولة الإكمال برمز مستهلك إيصالًا فقط: تكون proposedAddress وconfirmedAddress والوسائط فارغة. يظل GET غير متاح بعد الإكمال؛ ولا يفتح الإيصال الموقع مجددًا ولا يغير النتيجة. تبقى قيود دورة الحياة والانتقالات النهائية المتزامنة الأخرى كما هي موضحة أعلاه.