المطورون
المحافظ الثابتة
امنح كل عميل من عملائك عناوين إيداع خاصة به لا تتغير أبدًا، عنوان لكل شبكة. يُضاف كل إيداع إلى رصيدك في Crypto Merchant، ويُبلَّغ خادمك بالعميل الذي أرسله، حتى تشحن رصيد الحساب الصحيح.
كيف تحصل على المحافظ الثابتة
403 sticky_wallets_unavailable. وهي تستخدم عنوان URL الأساسي نفسه والمفاتيح السرية نفسها وتنسيق الأخطاء نفسه المستخدم في بقية API.قبل أن تبدأ
- 1
أكمل الإعداد واختر عملاتك. يحصل كل عميل على عنوان على شبكات العملات التي تقبلها (البوابة، الإعدادات).
- 2
أنشئ مفتاحًا سريًا. في البوابة، افتح المطورون وأنشئ مفتاح API. يُعرض المفتاح مرة واحدة فقط: احتفظ به على خادمك، مثلًا باسم
CM_SECRET_KEY، ولا تضعه أبدًا في صفحة ويب أو تطبيق. - 3
أضف نقطة نهاية Webhook. ضمن المطورون أيضًا، أضف عنوان URL الخاص بك مع الأحداث
deposit.pendingوdeposit.confirmedوdeposit.dropped(أو كل الأحداث). احتفظ بسر التوقيع الخاص بها،whsec_…، للتحقق من كل طلب.
كيف يعمل
- 1
يفتح العميل صفحة الإيداع على موقعك.
- 2
يستدعي خادمك
POST /sticky-walletsبالمعرّف الخاص بك لذلك العميل. ينشئ الاستدعاء الأول العناوين، وكل استدعاء لاحق يُعيد العناوين نفسها. - 3
تعرض العنوان، مع رمز QR، للعملة التي يختارها العميل.
- 4
عند وصول العملات تتلقى
deposit.pending، ثمdeposit.confirmedبعد أن تؤكدها الشبكة. - 5
عند
deposit.confirmedتضيف المبلغ إلى رصيد العميل المذكور فيsticky_wallet.reference.
الحصول على محفظة عميل
POST/sticky-wallets
تنشئ محفظة العميل في الاستدعاء الأول وتُعيد المحفظة نفسها في كل استدعاء لاحق: 201 عند إنشائها للتو، و200 بعد ذلك. يمكنك استدعاؤها بأمان في كل مرة تُفتح فيها صفحة الإيداع.
معاملات النص (Body)
referenceمطلوبstring- معرّفك لهذا العميل: من 1 إلى 120 حرفًا أو رقمًا أو
. _ : @ + -، ويبدأ بحرف أو رقم. محفظة واحدة لكل مرجع، بشكل دائم. labelاختياريstring- اسم ستراه في البوابة. إرساله مرة أخرى يستبدله.
metadataاختياريobject- كائن خاص بك، حتى 4 KB. إرساله مرة أخرى يستبدله.
curl https://cryptomerchant.online/api/v1/sticky-wallets \
-H "Authorization: Bearer $CM_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"reference": "user-1042",
"label": "Jane Doe",
"metadata": { "plan": "pro" }
}'// On your server, when a customer opens their deposit page
export async function depositAddresses(userId) {
const res = await fetch("https://cryptomerchant.online/api/v1/sticky-wallets", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CM_SECRET_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ reference: String(userId) }),
});
if (!res.ok) {
const { error } = await res.json();
throw new Error(`${error.code}: ${error.message}`);
}
const wallet = await res.json();
return wallet.addresses; // [{ network, address, coins: [...] }, …]
}كائن المحفظة الثابتة
idstring- معرّف المحفظة، يبدأ بـ
sw_. referencestring- معرّفك للعميل.
addressesarray- إدخال واحد لكل شبكة:
network(tronأوevmأوsolأوbtcأوltc)، وaddress، وcoinsالتي يقبلها. عنوانevmهو نفسه على Ethereum وBNB Smart Chain وPolygon وBase وArbitrum. pending_networksarray- الشبكات التي لا يزال عنوانها قيد التجهيز، وهذا نادر. استدعِ مرة أخرى بعد بضع دقائق وستظهر في
addresses. created_atstring- وقت إنشاء المحفظة.
{
"id": "sw_8Kd2pQx7Vb1mNc3T",
"object": "sticky_wallet",
"reference": "user-1042",
"label": "Jane Doe",
"metadata": { "plan": "pro" },
"addresses": [
{
"network": "tron",
"address": "TXbajeGHq4Vb…",
"coins": [
{ "id": "TRX.TRON", "symbol": "TRX", "network": "Tron" },
{ "id": "USDT.TRON", "symbol": "USDT", "network": "Tron" }
]
},
{
"network": "evm",
"address": "0xE550EC6d…",
"coins": [
{ "id": "ETH.ETH", "symbol": "ETH", "network": "Ethereum" },
{ "id": "BNB.BSC", "symbol": "BNB", "network": "BNB Smart Chain" },
{ "id": "USDT.BSC", "symbol": "USDT", "network": "BNB Smart Chain" }
]
}
],
"pending_networks": [],
"created_at": "2026-10-29T18:20:41.000Z"
}أخبر العملاء بما يجب إرساله
البحث عن المحافظ
GET/sticky-wallets
GET/sticky-wallets/{id}
ابحث عن محفظة بمرجعك، أو اجلب محفظة بمعرّفها، أو تصفح كل المحافظ صفحة تلو الأخرى، الأحدث أولًا: limit من 1 إلى 100، وstarting_after بمعرّف آخر محفظة لديك، ويوضح has_more ما إذا كانت هناك المزيد.
# By your reference
curl "https://cryptomerchant.online/api/v1/sticky-wallets?reference=user-1042" \
-H "Authorization: Bearer $CM_SECRET_KEY"
# By id
curl https://cryptomerchant.online/api/v1/sticky-wallets/sw_8Kd2pQx7Vb1mNc3T \
-H "Authorization: Bearer $CM_SECRET_KEY"
# All of them, 50 at a time
curl "https://cryptomerchant.online/api/v1/sticky-wallets?limit=50&starting_after=sw_8Kd2pQx7Vb1mNc3T" \
-H "Authorization: Bearer $CM_SECRET_KEY"{
"object": "list",
"data": [ { "id": "sw_8Kd2pQx7Vb1mNc3T", "object": "sticky_wallet", … } ],
"has_more": false
}عرض الإيداعات
GET/deposits
كل الإيداعات في محافظ عملائك، الأحدث أولًا. صفِّ حسب sticky_wallet (معرّف محفظة) وstatus (pending أو confirmed أو dropped)، وتنقّل بين الصفحات باستخدام limit وstarting_after (معرّف إيداع). استخدمها لتعويض ما فاتك عندما لا يستلم خادمك بعض Webhooks.
curl "https://cryptomerchant.online/api/v1/deposits?sticky_wallet=sw_8Kd2pQx7Vb1mNc3T&status=confirmed&limit=20" \
-H "Authorization: Bearer $CM_SECRET_KEY"كائن الإيداع
idstring- معرّف الإيداع. استخدمه لإضافة كل إيداع مرة واحدة فقط.
statusstringpending: رُصد على الشبكة وبانتظار التأكيدات.confirmed: نهائي وأُضيف إلى رصيدك.dropped: لم يُؤكَّد أبدًا.sticky_walletobject- المحفظة التي أُرسل إليها:
idوreferenceالخاص بك. coinobject- العملة وشبكتها.
amountstring- ما أرسله العميل، بالعملة نفسها.
feestring- الرسوم، بالعملة نفسها.
net_amountstring- ما أُضيف إلى رصيدك (المبلغ ناقص الرسوم)، بعد التأكيد.
amount_usdstring- قيمته بالدولار الأمريكي عند وصوله.
tx_hashstring- تجزئة المعاملة؛ يفتحها
explorer_urlفي مستكشف الكتل.
{
"id": "cmvu1x9a0000l10u8k2f3h7q",
"object": "deposit",
"status": "confirmed",
"sticky_wallet": { "id": "sw_8Kd2pQx7Vb1mNc3T", "reference": "user-1042" },
"coin": { "id": "USDT.TRON", "symbol": "USDT", "network": "Tron" },
"address": "TXbajeGHq4Vb…",
"amount": "250",
"amount_usd": "250.00",
"fee": "2.5",
"net_amount": "247.5",
"from_address": "TQn9Y2khEsLJ…",
"tx_hash": "36423ec5…f00d4a",
"explorer_url": "https://tronscan.org/#/transaction/36423ec5…f00d4a",
"confirmations": 19,
"detected_at": "2026-10-29T18:31:02.000Z",
"confirmed_at": "2026-10-29T18:32:01.000Z"
}Webhooks
تحمل أحداث الإيداع كائن الإيداع في data. تحقق من التوقيع، كما هو موضح في Webhooks، قبل أن تثق بأي حدث.
deposit.pending- تم رصد إيداع على السلسلة في المحفظة الثابتة لأحد عملائك، وهو بانتظار التأكيدات.
deposit.confirmed- تم تأكيد إيداع في محفظة ثابتة وأُضيف إلى رصيدك بعد خصم الرسوم: أضف المبلغ إلى رصيد ذلك العميل الآن.
deposit.dropped- إيداع في محفظة ثابتة تم رصده لكنه لم يُؤكَّد أبدًا (فشل أو أُزيل من السلسلة).
import express from "express";
import { verifyWebhook } from "./verify-webhook.js"; // from the Webhooks page
import { db } from "./db.js"; // your database; table webhook_events as on the Webhooks page
const app = express();
app.post(
"/webhooks/crypto-merchant",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = verifyWebhook(req.body, req.get("CM-Signature"), process.env.CM_WEBHOOK_SECRET);
} catch {
return res.sendStatus(400);
}
try {
// Save first: a repeat delivery has the same event.id and is ignored
await db.query(
"INSERT INTO webhook_events (id, type, payload) VALUES ($1, $2, $3) ON CONFLICT (id) DO NOTHING",
[event.id, event.type, event],
);
} catch {
return res.sendStatus(500); // not saved: we send it again later
}
res.sendStatus(200); // stored, so confirm it
processEvents().catch(console.error); // or run it from a background job
},
);
async function processEvents() {
const { rows } = await db.query(
"SELECT payload FROM webhook_events WHERE processed_at IS NULL ORDER BY received_at",
);
for (const { payload: event } of rows) {
const deposit = event.data;
if (event.type === "deposit.pending") {
// Optional: show "deposit on its way" to deposit.sticky_wallet.reference
}
if (event.type === "deposit.confirmed") {
// Credit once: creditCustomer must skip a deposit.id it has already credited
await creditCustomer({
customerId: deposit.sticky_wallet.reference,
depositId: deposit.id,
coin: deposit.coin.id, // e.g. "USDT.TRON"
amount: deposit.net_amount, // or deposit.amount to cover the fee yourself
txHash: deposit.tx_hash,
});
}
await db.query("UPDATE webhook_events SET processed_at = now() WHERE id = $1", [event.id]);
}
}الأخطاء
400invalid_request: حقل مفقود أو خاطئ؛ تذكر الرسالة أي حقل.401unauthorized: المفتاح السري مفقود أو غير صالح.403sticky_wallets_unavailable: المحافظ الثابتة غير مفعّلة لهذا النشاط التجاري، أو لم يكتمل إعداده بعد.404not_found: لا توجد محفظة ثابتة بهذا المعرّف.
ممارسات جيدة
- أضف المبلغ إلى رصيد العميل عند
deposit.confirmedفقط، ومرة واحدة فقط لكلidإيداع: قد يصل Webhook أكثر من مرة. - حدّد من يدفع الرسوم: أضف
net_amountلتحميلها على العميل، أوamountلتتحملها بنفسك. - مرجعك هو المفتاح: استدعاء
POST /sticky-walletsمرة أخرى آمن دائمًا، لذا لا تحتاج إلى تخزين العناوين. - احتفظ بالمفتاح السري على خادمك. إذا تسرّب، فألغِه ضمن المطورون وأنشئ مفتاحًا جديدًا.
- إذا كانت نقطة النهاية لديك متوقفة، فاعرض الإيداعات بحالة
confirmedوأضف إلى الأرصدة ما لم تعالجه بعد. - هل تنشئ رصيدًا لعملائك؟ اقرأ كيف تضيف الشحن بالعملات الرقمية إلى حسابات العملاء.