Перейти к содержимому
Crypto Merchant

Разработчикам

Постоянные кошельки

Дайте каждому клиенту собственные адреса для пополнения, которые никогда не меняются, по одному на сеть. Каждое пополнение зачисляется на ваш баланс в Crypto Merchant, а ваш сервер узнаёт, какой клиент его отправил, чтобы вы зачислили средства на нужный аккаунт.

Как подключить постоянные кошельки

При регистрации выберите кошельки клиентов или попросите поддержку включить постоянные кошельки для уже существующего аккаунта. Пока они не включены, эти эндпоинты отвечают 403 sticky_wallets_unavailable. Они используют тот же базовый URL, те же секретные ключи и тот же формат ошибок, что и остальной API.

Перед началом

  1. 1

    Завершите настройку и выберите монеты. Каждый клиент получает адрес в сетях тех монет, которые вы принимаете (личный кабинет, Настройки).

  2. 2

    Создайте секретный ключ. В личном кабинете откройте раздел Разработчикам и создайте API-ключ. Он показывается один раз: храните его на своём сервере, например в CM_SECRET_KEY, и никогда не размещайте на веб-странице или в приложении.

  3. 3

    Добавьте эндпоинт вебхука. Там же, в разделе Разработчикам, добавьте свой URL с событиями deposit.pending, deposit.confirmed и deposit.dropped (или со всеми событиями). Сохраните его секрет подписи whsec_…, чтобы проверять каждый запрос.

Как это работает

  1. 1

    Клиент открывает страницу пополнения на вашем сайте.

  2. 2

    Ваш сервер вызывает POST /sticky-wallets с вашим собственным ID этого клиента. Первый вызов создаёт адреса, каждый следующий возвращает те же самые.

  3. 3

    Вы показываете адрес с QR-кодом для монеты, которую выбрал клиент.

  4. 4

    Когда монеты поступают, вы получаете deposit.pending, а после подтверждения сетью — deposit.confirmed.

  5. 5

    По событию deposit.confirmed вы зачисляете средства клиенту, указанному в sticky_wallet.reference.

Получение кошелька клиента

POST/sticky-wallets

При первом вызове создаёт кошелёк клиента, а при каждом следующем возвращает тот же: 201, если он только что создан, и 200 после этого. Его можно смело вызывать каждый раз, когда открывается страница пополнения.

Параметры тела

referenceОбязательныйstring
Ваш ID этого клиента: от 1 до 120 букв, цифр или . _ : @ + -, начинается с буквы или цифры. Один кошелёк на идентификатор, навсегда.
labelНеобязательныйstring
Имя, которое вы увидите в личном кабинете. При повторной отправке заменяется.
metadataНеобязательныйobject
Ваш собственный объект размером до 4 КБ. При повторной отправке заменяется.
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
ID кошелька, начинается с sw_.
referencestring
Ваш ID клиента.
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}

Найдите кошелёк по своему идентификатору, получите его по ID или просмотрите все постранично, сначала новые: limit от 1 до 100, starting_after с ID последнего полученного кошелька, а 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 (ID кошелька) и status (pending, confirmed или dropped), листайте страницы с помощью limit и starting_after (ID пополнения). Так можно наверстать пропущенное, если ваш сервер не получил вебхуки.

curl
curl "https://cryptomerchant.online/api/v1/deposits?sticky_wallet=sw_8Kd2pQx7Vb1mNc3T&status=confirmed&limit=20" \
  -H "Authorization: Bearer $CM_SECRET_KEY"

Объект пополнения

idstring
ID пополнения. Используйте его, чтобы зачислять каждое пополнение только один раз.
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"
}

Вебхуки

События пополнений передают объект пополнения в data. Прежде чем доверять событию, проверьте подпись, как описано в разделе Вебхуки.

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: постоянного кошелька с таким ID нет.

Рекомендации

  • Зачисляйте средства клиенту только по deposit.confirmed и только один раз для каждого id пополнения: вебхук может прийти больше одного раза.
  • Решите, кто платит комиссию: зачисляйте net_amount, чтобы переложить её на клиента, или amount, чтобы взять её на себя.
  • Всё держится на вашем идентификаторе: повторный вызов POST /sticky-wallets всегда безопасен, поэтому хранить адреса не нужно.
  • Храните секретный ключ на своём сервере. Если он утёк, отзовите его в разделе Разработчикам и создайте новый.
  • Если ваш эндпоинт был недоступен, получите список пополнений со статусом confirmed и зачислите те, которые вы ещё не обработали.
  • Создаёте баланс для клиентов? Прочитайте, как добавить пополнение криптовалютой в аккаунты клиентов.