الانتقال إلى المحتوى
Crypto Merchant

المطورون

المحافظ الثابتة

امنح كل عميل من عملائك عناوين إيداع خاصة به لا تتغير أبدًا، عنوان لكل شبكة. يُضاف كل إيداع إلى رصيدك في Crypto Merchant، ويُبلَّغ خادمك بالعميل الذي أرسله، حتى تشحن رصيد الحساب الصحيح.

كيف تحصل على المحافظ الثابتة

اختر محافظ العملاء عند التسجيل، أو اطلب من الدعم تفعيل المحافظ الثابتة لحساب لديك بالفعل. وإلى أن يتم تفعيلها، تُرجع نقاط النهاية هذه 403 sticky_wallets_unavailable. وهي تستخدم عنوان URL الأساسي نفسه والمفاتيح السرية نفسها وتنسيق الأخطاء نفسه المستخدم في بقية API.

قبل أن تبدأ

  1. 1

    أكمل الإعداد واختر عملاتك. يحصل كل عميل على عنوان على شبكات العملات التي تقبلها (البوابة، الإعدادات).

  2. 2

    أنشئ مفتاحًا سريًا. في البوابة، افتح المطورون وأنشئ مفتاح API. يُعرض المفتاح مرة واحدة فقط: احتفظ به على خادمك، مثلًا باسم CM_SECRET_KEY، ولا تضعه أبدًا في صفحة ويب أو تطبيق.

  3. 3

    أضف نقطة نهاية Webhook. ضمن المطورون أيضًا، أضف عنوان URL الخاص بك مع الأحداث deposit.pending وdeposit.confirmed وdeposit.dropped (أو كل الأحداث). احتفظ بسر التوقيع الخاص بها، whsec_…، للتحقق من كل طلب.

كيف يعمل

  1. 1

    يفتح العميل صفحة الإيداع على موقعك.

  2. 2

    يستدعي خادمك POST /sticky-wallets بالمعرّف الخاص بك لذلك العميل. ينشئ الاستدعاء الأول العناوين، وكل استدعاء لاحق يُعيد العناوين نفسها.

  3. 3

    تعرض العنوان، مع رمز QR، للعملة التي يختارها العميل.

  4. 4

    عند وصول العملات تتلقى deposit.pending، ثم deposit.confirmed بعد أن تؤكدها الشبكة.

  5. 5

    عند deposit.confirmed تضيف المبلغ إلى رصيد العميل المذكور في sticky_wallet.reference.

الحصول على محفظة عميل

POST/sticky-wallets

تنشئ محفظة العميل في الاستدعاء الأول وتُعيد المحفظة نفسها في كل استدعاء لاحق: 201 عند إنشائها للتو، و200 بعد ذلك. يمكنك استدعاؤها بأمان في كل مرة تُفتح فيها صفحة الإيداع.

معاملات النص (Body)

referenceمطلوبstring
معرّفك لهذا العميل: من 1 إلى 120 حرفًا أو رقمًا أو . _ : @ + -، ويبدأ بحرف أو رقم. محفظة واحدة لكل مرجع، بشكل دائم.
labelاختياريstring
اسم ستراه في البوابة. إرساله مرة أخرى يستبدله.
metadataاختياريobject
كائن خاص بك، حتى 4 KB. إرساله مرة أخرى يستبدله.
curl
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" }
  }'
Node.js
// 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
وقت إنشاء المحفظة.
sticky_wallet
{
  "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 ما إذا كانت هناك المزيد.

curl
# 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
curl "https://cryptomerchant.online/api/v1/deposits?sticky_wallet=sw_8Kd2pQx7Vb1mNc3T&status=confirmed&limit=20" \
  -H "Authorization: Bearer $CM_SECRET_KEY"

كائن الإيداع

idstring
معرّف الإيداع. استخدمه لإضافة كل إيداع مرة واحدة فقط.
statusstring
pending: رُصد على الشبكة وبانتظار التأكيدات. confirmed: نهائي وأُضيف إلى رصيدك. dropped: لم يُؤكَّد أبدًا.
sticky_walletobject
المحفظة التي أُرسل إليها: id وreference الخاص بك.
coinobject
العملة وشبكتها.
amountstring
ما أرسله العميل، بالعملة نفسها.
feestring
الرسوم، بالعملة نفسها.
net_amountstring
ما أُضيف إلى رصيدك (المبلغ ناقص الرسوم)، بعد التأكيد.
amount_usdstring
قيمته بالدولار الأمريكي عند وصوله.
tx_hashstring
تجزئة المعاملة؛ يفتحها explorer_url في مستكشف الكتل.
deposit
{
  "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
إيداع في محفظة ثابتة تم رصده لكنه لم يُؤكَّد أبدًا (فشل أو أُزيل من السلسلة).
server.js · إضافة المبلغ إلى رصيد العميل
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]);
  }
}

الأخطاء

400
invalid_request: حقل مفقود أو خاطئ؛ تذكر الرسالة أي حقل.
401
unauthorized: المفتاح السري مفقود أو غير صالح.
403
sticky_wallets_unavailable: المحافظ الثابتة غير مفعّلة لهذا النشاط التجاري، أو لم يكتمل إعداده بعد.
404
not_found: لا توجد محفظة ثابتة بهذا المعرّف.

ممارسات جيدة

  • أضف المبلغ إلى رصيد العميل عند deposit.confirmed فقط، ومرة واحدة فقط لكل id إيداع: قد يصل Webhook أكثر من مرة.
  • حدّد من يدفع الرسوم: أضف net_amount لتحميلها على العميل، أو amount لتتحملها بنفسك.
  • مرجعك هو المفتاح: استدعاء POST /sticky-wallets مرة أخرى آمن دائمًا، لذا لا تحتاج إلى تخزين العناوين.
  • احتفظ بالمفتاح السري على خادمك. إذا تسرّب، فألغِه ضمن المطورون وأنشئ مفتاحًا جديدًا.
  • إذا كانت نقطة النهاية لديك متوقفة، فاعرض الإيداعات بحالة confirmed وأضف إلى الأرصدة ما لم تعالجه بعد.
  • هل تنشئ رصيدًا لعملائك؟ اقرأ كيف تضيف الشحن بالعملات الرقمية إلى حسابات العملاء.