تكامل دفع يمكنك اختباره ومطابقته وأتمتته دون الخلط بين مدفوعات العملاء ومستحقات البائعين.
1. حدد مسؤولية كل طرف
يتولى متجرك الكتالوج وحسابات البائعين والسلة والشحن وتنفيذ الطلبات. يتولى Wholly Crypto صفحة الدفع والتحقق من المدفوعات وتوزيعات البائعين وصرف المستحقات المعتمد. سجل البائع ليس حساب دخول؛ ولا تقسّم إضافات المتاجر الحالية السلال متعددة البائعين تلقائيًا.
- سلة مشتركة واحدة
- فاتورة عميل واحدة
- حصص بائعين متحقق منها
- صرف مستحقات معتمد
يدفع العملاء إلى محافظ المشروع أولًا. تتحكم أنت بالمفاتيح وتحتفظ بأموال مستحقة للبائعين. ليس هذا تقسيمًا مباشرًا من العميل إلى البائع أو خدمة غير احتجازية للبائعين لديك.
يدعم السوق شبكة Bitcoin الرئيسية وعملات EVM المدعومة ورموز ERC-20 القياسية. يستلم البائعون الأصل وعلى الشبكة اللذين استخدمهما العميل، لا تحويلًا تلقائيًا إلى عملة تقليدية. لا تدعم مدفوعات السوق الصادرة جميع شبكات الاستقبال الثلاثين.
2. احسب المبالغ
يبيع كل واحد من ثلاثة بائعين سلعًا بقيمة 100 دولار. حدد عمولة المشروع على 4%، دون تجاوزات للمتجر أو البائع في هذا المثال.
| الحصة | الإجمالي | عمولتك | ما يستلمه البائع |
|---|---|---|---|
| كل بائع | $100 | $4 | $96 |
| البائعون الثلاثة | $300 | $12 | $288 |
هذه قيم مكافئة بسعر الفاتورة المثبت وتُدفع بالعملات المشفرة، وليست قيمًا مستقبلية مضمونة بالدولار. تستخدم رسوم المعالجة المعتادة 1% ثلاثة دولارات من الرصيد المسبق لهذه الفاتورة البالغة 300 دولار، مرة واحدة لا مرة لكل بائع. تترك عمولتك الإجمالية 12 دولارًا تسعة دولارات قبل تكاليف الشبكة عندما تنطبق تلك الرسوم.
احتفظ بعملات أصلية حرة منفصلة لرسوم Bitcoin أو غاز EVM. يجب ألا تستهلك الرسوم أصل أموال البائعين المحمي. لا يستطيع التجميع العادي إنفاق عناوين استقبال السوق.
3. جهّز المحافظ والبائعين
- في المشروع ← السوق ← الإعدادات، فعّل السوق واختر المتاجر وحدد العمولة. أبقِ صرف المستحقات موقوفًا والسياسات التلقائية معطلة أثناء الإعداد.
- انسخ محافظ المشروع وقاعدة البيانات احتياطيًا. فعّل وسائل BTC/EVM المطلوبة في المتجر وتحقق من جاهزية الماسحات وموّل رصيد المعالجة والرسوم الأصلية المنفصلة.
- أضف كل بائع. احفظ UUID الخاص به بجانب معرّف البائع في متجرك؛ يمكن أن يحمل external_id هذا المرجع. تحقق بشكل مستقل من كل عنوان صرف واعتمده على الشبكة ونوع الشبكة المحددين.
تحتاج وسيلة الدفع إلى وجهة مطابقة معتمدة لكل بائع مشارك. تغيير عنوان بائع لاحقًا لا يعيد توجيه الالتزامات القائمة بصمت.
يحتاج التحقق من صرف المستحقات إلى عدد تأكيدات موجب ومزوّدين مستقلين متوافقين، حتى إذا سمحت صفحة الدفع بصفر تأكيدات أو ماسح واحد.
4. اربط السلة المشتركة
أنشئ بيانات اعتماد للسوق محصورة بالمشروع في الإعدادات ← الوصول إلى API. امنح خادم الدفع الخلفي marketplace.read وinvoices.write، مع حصرها بالمتجر المناسب عند الحاجة. لا تمنح هذا المفتاح صلاحيات اعتماد العناوين أو صرف المستحقات.
احسب الأسعار والخصومات والضرائب والشحن على خادمك، ثم وزّعها على حصص البائعين. أرسل من 1 إلى 100 بائع مختلف بمبالغ موجبة كسلاسل عشرية؛ يجب أن يساوي مجموع حصصهم الإجمالية الفاتورة تمامًا. لا تثق بتقسيم يرسله المتصفح ولا تستخدم حساب الفاصلة العائمة للأموال.
استبدل اسم مضيف API والقيم النائبة لـUUID أدناه. حمّل WHOLLY_TOKEN من بيئة الخادم. يرث الطلب عمولة 4% المضبوطة ولا يحتاج صلاحية تجاوز العمولة.
افتح الطلب بصيغة cURL أوJavaScript أوPHP أوPython
cURL
: "${WHOLLY_TOKEN:?Set WHOLLY_TOKEN to your server-side API token}"
# Keep this key and the exact body for retries; use a new key for each new operation.
curl --fail-with-body --max-time 30 \
--request POST \
--url "https://api.example.com/v1/marketplace/invoices" \
--header "Authorization: Bearer $WHOLLY_TOKEN" \
--header 'Idempotency-Key: cart-1042-marketplace-v1' \
--header 'Content-Type: application/json' \
--data-raw '{
"project_id": "YOUR_PROJECT_ID",
"store_id": "YOUR_STORE_ID",
"amount": "300.00",
"currency": "USD",
"order_id": "cart-1042",
"description": "One order from three vendors",
"ipn_url": "https://shop.example.com/payments/wholly-ipn",
"metadata": {
"cart_id": "cart-1042"
},
"allocations": [
{
"vendor_id": "VENDOR_A_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_B_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_C_UUID",
"gross_amount": "100.00"
}
]
}'JavaScript
// Node.js 18+ · run on your server, never in browser code.
const token = process.env.WHOLLY_TOKEN;
if (!token) throw new Error("Set WHOLLY_TOKEN");
// Keep this key and the exact body for retries; use a new key for each new operation.
const body = `{
"project_id": "YOUR_PROJECT_ID",
"store_id": "YOUR_STORE_ID",
"amount": "300.00",
"currency": "USD",
"order_id": "cart-1042",
"description": "One order from three vendors",
"ipn_url": "https://shop.example.com/payments/wholly-ipn",
"metadata": {
"cart_id": "cart-1042"
},
"allocations": [
{
"vendor_id": "VENDOR_A_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_B_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_C_UUID",
"gross_amount": "100.00"
}
]
}`;
const response = await fetch("https://api.example.com/v1/marketplace/invoices", {
method: "POST",
headers: {
"Authorization": `Bearer ${token}`,
"Idempotency-Key": "cart-1042-marketplace-v1",
"Content-Type": "application/json"
},
body,
redirect: "error",
signal: AbortSignal.timeout(30000)
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
console.log(await response.json());PHP
<?php
// PHP 8+ with the cURL extension; run on your server.
$token = getenv('WHOLLY_TOKEN');
if (!$token) { throw new RuntimeException('Set WHOLLY_TOKEN'); }
// Keep this key and the exact body for retries; use a new key for each new operation.
$body = <<<'JSON'
{
"project_id": "YOUR_PROJECT_ID",
"store_id": "YOUR_STORE_ID",
"amount": "300.00",
"currency": "USD",
"order_id": "cart-1042",
"description": "One order from three vendors",
"ipn_url": "https://shop.example.com/payments/wholly-ipn",
"metadata": {
"cart_id": "cart-1042"
},
"allocations": [
{
"vendor_id": "VENDOR_A_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_B_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_C_UUID",
"gross_amount": "100.00"
}
]
}
JSON;
$ch = curl_init("https://api.example.com/v1/marketplace/invoices");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $token, "Idempotency-Key: cart-1042-marketplace-v1", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => $body,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($response === false) { throw new RuntimeException(curl_error($ch)); }
curl_close($ch);
if ($status < 200 || $status >= 300) { throw new RuntimeException("HTTP $status: $response"); }
print_r(json_decode($response, true, 512, JSON_THROW_ON_ERROR));Python
# Python 3 · standard library; run on your server.
import json
import os
from urllib.request import Request, build_opener, HTTPRedirectHandler
class NoRedirect(HTTPRedirectHandler):
def redirect_request(self, req, fp, code, msg, headers, newurl):
return None
# Keep this key and the exact body for retries; use a new key for each new operation.
headers = {
"Idempotency-Key": "cart-1042-marketplace-v1",
"Content-Type": "application/json"
}
headers["Authorization"] = "Bearer " + os.environ["WHOLLY_TOKEN"]
body = """{
"project_id": "YOUR_PROJECT_ID",
"store_id": "YOUR_STORE_ID",
"amount": "300.00",
"currency": "USD",
"order_id": "cart-1042",
"description": "One order from three vendors",
"ipn_url": "https://shop.example.com/payments/wholly-ipn",
"metadata": {
"cart_id": "cart-1042"
},
"allocations": [
{
"vendor_id": "VENDOR_A_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_B_UUID",
"gross_amount": "100.00"
},
{
"vendor_id": "VENDOR_C_UUID",
"gross_amount": "100.00"
}
]
}""".encode("utf-8")
request = Request("https://api.example.com/v1/marketplace/invoices",
method="POST", headers=headers, data=body)
# Non-2xx responses raise HTTPError. Do not retry writes with a new key.
with build_opener(NoRedirect()).open(request, timeout=30) as response:
print(json.load(response))احفظ محتوى الطلب وIdempotency-Key قبل الإرسال. بعد انتهاء المهلة، أعد المحتوى نفسه بالمفتاح نفسه. احفظ data.invoice_id بجانب طلبك ووجّه العميل إلى links.checkout في المستوى الأعلى. لا تضع مفاتيح API في متصفح العميل أبدًا.
أين تجد UUID للمشروع والمتجر ←
تفضل SDK؟ ابدأ بأمثلة السوق:
5. تتبع دفع العميل وصرف المستحقات بشكل منفصل
رابط العودة من صفحة الدفع ليس إثبات دفع. تحقق من توقيعات الإشعارات على المحتوى الخام والطابع الزمني والمشروع المتوقع، واحفظ event_id بقيد فريد قبل إقرار الاستلام. استخدم حماية مستقلة على مستوى الطلب كي لا تنفذه إعادة المحاولة مرتين.
| الحدث | ماذا يخبرك |
|---|---|
invoice.settled | تمت تسوية فاتورة العميل. تحقق من علامات المراجعة وحجوزات السوق قبل تنفيذ الطلب. |
marketplace.allocations.available | الحصص المتحقق منها متاحة للصرف. هذا لا يعني بالضرورة أن أي بائع قد استلم بعد. |
marketplace.payout.confirmed | أكملت عملية صرف المستحقات فحوص التأكيد. |
يستخدم IPN الفاتورة سر IPN الخاص بالمتجر. تستخدم webhooks دورة حياة السوق سر توقيع خاصًا بكل نقطة نهاية. أبقِ المستقبلين منفصلين. اقرأ الفاتورة أو عملية الصرف الحالية عبر API عند مطابقة الأحداث المفقودة أو غير المرتبة.
6. راجع أولًا وأتمت لاحقًا
عندما تصبح الحصص الموثّقة متاحة، ألغِ إيقاف الصرف مع إبقاء السياسات التلقائية معطلة. في السوق ← صرف المستحقات، جهّز التوزيعات وراجع المستلمين وحدود الرسوم الأصلية والغاز ثم وافق على الخطة المحددة مرة واحدة. تابع حتى «مدفوع»، لا «مبثوث» فقط.
يجمع Bitcoin كل الحصص غير المدفوعة لفاتورة مختارة في دفعة واحدة. قد يحتاج صرف رموز EVM إلى تمويل غاز قبل تحويل الرموز. هذه عدة معاملات وليست تقسيمًا ذريًا ينجح كله أو يفشل كله.
بعد اختبار صغير ناجح، حدد سياسة تلقائية لكل أصل: الحد الأدنى للصرف وحدود المبلغ لكل عملية ويوميًا وميزانيات الرسوم الأصلية والغاز والفاصل والتأكيدات. تفعيلها يسمح بالإرسال دون نقرات إضافية. قد يوقف انخفاض الرصيد أو تعطيل حاجز التحويل في الخادم الإنفاق مؤقتًا.
7. عالج الحالات الصعبة
دفعات ناقصة أو متأخرة أو مختلطة أو متأثرة بإعادة تنظيم السلسلة
تسوية صفحة الدفع لا تضمن تقسيمًا ممولًا بالكامل للبائعين. لا يخلق التسامح أموالًا ناقصة. افحص التوزيعات المحتجزة وانتظر الدفع أو أعد المبلغ أو وافق صراحة على تقسيم أصغر مغطى بالكامل. الدفعات الزائدة ليست تلقائيًا إيرادًا إضافيًا للسوق.
لا تمنع المدفوعات الزائدة صرف حصص البائعين المسعّرة على Bitcoin أوعملات EVM أو رموز ERC-20 المدعومة. لا تتغير حصص البائعين وتبقى الزيادة منفصلة للمطابقة.
تعطّل صرف المستحقات أو انتهت مهلة الطلب
تحقق من بصمات المعاملات المحفوظة وأرصدة المصدر والغاز وسبب المراجعة. استأنف العملية الموجودة أو طابقها؛ لا تنشئ تحويلًا ثانيًا لأن الاستجابة ضاعت. بعد استعادة نسخة احتياطية، أبقِ الصرف موقوفًا حتى تتطابق نتائج السلسلة مع دفتر القيود.
يمكن للاستئناف استبدال تحويل EVM فاشل فقط بعد أن يثبت مزوّدان مستقلان تراجعًا مؤكدًا على السلسلة. تبقى النتائج المجهولة محجوزة، وتظل رسوم المحاولة الفاشلة محسوبة ضمن الميزانية الأصلية.
العميل يحتاج استردادًا
تحقق من عنوان استرداد يتحكم به العميل. الاستردادات المدعومة كاملة وبالأصل نفسه. بعد الدفع لجميع البائعين، موّل المحفظة الأساسية منفصلًا؛ لا يستطيع Wholly Crypto استرجاع المبلغ منهم. تحتاج دفعة بائعين مدفوعة جزئيًا إلى مطابقة يدوية، لا افتراض وجود زر استرداد جزئي.
8. تحقق قبل الإطلاق
- اختبر دفعة BTC و/أوEVM صغيرة حتى تأكيد صرف مستحقات البائعين. تأكد من الشبكة وعقد الرمز والوجهات والعمولة والرسوم المنفصلة.
- اختبر إشعارًا مكررًا واستجابة API انتهت مهلتها ودفعة ناقصة وصرفًا محتجزًا. تحقق من أن أيًا منها لا يؤدي إلى تنفيذ طلب أو إرسال مرتين.
- احتفظ بنسخ خاصة خارج الخادم وراقب فشل صرف المستحقات وطابق التزامات البائعين مع الأموال على السلسلة بانتظام.
ابدأ بصرف تمت مراجعته وعدد صغير من البائعين. أتمت فقط الأصول والميزانيات والوجهات التي اختبرتها.