API, совместимый с Cryptomus

blockwallets принимает USDT и USDC, а также BTC, LTC, DOGE, BCH и нативные монеты (зачисляются в долларах США по зафиксированному курсу): клиент платит, мы подтверждаем платёж в блокчейне и уведомляем вас. API, подписи и вебхуки такие же, как у Cryptomus — если вы уже интегрировали Cryptomus, смените домен, и всё. Сначала о том, как это работает, затем об API.

Два способа приёма

Оба принимают любую сумму: заказы с фиксированной ценой и пополнения, где клиент вводит сумму сам. После оплаты вы отгружаете заказ или зачисляете сумму на баланс клиента. Разница только в том, получает ли каждый платёж новый адрес.

Рекомендуется · большинство интеграцийСчета

Клиент выбирает товар или вводит сумму на вашей странице, вы создаёте счёт, и он отправляет сумму, указанную на странице оплаты. У каждого счёта новый адрес и обратный отсчёт; когда платёж приходит, мы уведомляем вас с фактически полученной суммой.

POST /v1/payment → вебхук type: payment

По желаниюСтатические кошельки

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

POST /v1/wallet → вебхук type: wallet

Если сомневаетесь, используйте счета. Без кода подойдут платёжные ссылки в кабинете — это счета, которые создаются за вас. Ещё не продавец? Запросите доступ на главной странице; после одобрения войдите в кабинет продавца и начните с пункта «Пробный платёж» на главной странице кабинета, заплатив небольшую сумму (деньги поступят на ваш собственный баланс).

Как проходит счёт

В платеже участвуют четыре стороны: клиент, ваш сайт, blockwallets и блокчейн. Схема идёт сверху вниз по времени; правый столбец — статус счёта на каждом шаге.

① Создание② Оплата③ Подтверждение④ Уведомление⑤ Завершение Клиентбраузер + кошелёкВаш сайтстраницы + серверblockwalletsоплата + сканерБлокчейнTRON + ещё 14 Статус счётаstatus 1Нажимает «Пополнить»2POST /v1/payment3uuid + urlcheck4Перенаправление на url5Выбирает монету + сеть6Свой адрес + сумма7Отправляет на этот адрес8Сканирование раз в минуту9Виден, ждём подтвержденийconfirm_check10Сверка со вторым узломpaid11POST url_callback12Отвечает 2xx13Проверка, отгрузка / зачисление14Возврат на url_success15Зачисление на баланс

Схема широкая — прокрутите вбок.

15 шагов сверху вниз в порядке времени. Нажмите «Воспроизвести», чтобы посмотреть, или выберите любой шаг, чтобы увидеть подробности.

Коротко, пять шагов:

  1. Вы создаёте счёт (платёжная ссылка делает это за вас, либо ваш сервер вызывает /v1/payment), получаете url страницы оплаты и перенаправляете туда клиента.
  2. На странице оплаты клиент выбирает монету и сеть, получает отдельный адрес и сумму и платит из кошелька или с биржи.
  3. Мы видим перевод в блокчейне, ждём достаточного числа подтверждений, затем сверяем его со вторым поставщиком узлов (чтобы один узел не мог подделать платёж).
  4. Счёт получает статус paid, и мы сразу отправляем POST с подписанным вебхуком на ваш url_callback; через несколько секунд страница оплаты возвращает клиента на ваш url_success.
  5. Деньги зачисляются на ваш баланс; выводите их на свой кошелёк из кабинета продавца.

Статус счёта

statusЗначениеЧто делаете вы
checkОжидает оплаты—
confirm_checkПеревод виден, ждём подтверждений—
wrong_amount_waitingПолучено меньше нужного; клиент может доплатить на тот же адрес (если is_payment_multiple равен true; уведомление приходит один раз)— (после доплаты придёт paid)
paidОплаченОтгрузите или зачислите по payment_amount_usd
paid_overОплачен с переплатойТо же (payment_amount_usd — полученная сумма)
wrong_amountИстёк, полная сумма не получена (при is_payment_multiple false — первый же недоплаченный перевод)Сервисы с пополнением могут зачислить полученную сумму payment_amount_usd; магазины просят клиента доплатить остаток
cancelИстёк, ничего не получено— (деньги, пришедшие позже, всё равно зачисляются и приходят в уведомлении)

Если is_final равен true, статус больше не изменится (кроме поздних платежей).

Кабинет продавца → «Платежи › Платёжные ссылки» → введите описание и сумму (зафиксируйте сеть или дайте клиенту выбрать) → создайте. У каждой ссылки есть URL и QR-код.

Интеграция по API

1. Учётные данные и подпись

Кабинет продавца → «Разработчикам › Интеграция и ключи» → создайте merchant (UUID) и API key. Есть один набор для Live и один для Test: Live принимает настоящие деньги, Test работает в тестовых сетях. Добавьте также домены сайта: url_callback, url_return и url_success должны находиться на них. API key показывается только один раз — храните его надёжно и только на сервере.

Базовый URL: https://blockwallets.io. Каждый эндпоинт — POST + JSON со следующими заголовками:

Успешный ответ: {"state": 0, "result": {…}}; ошибка: {"state": 1, "message": "…"} (см. Ошибки).

У основных эндпоинтов ниже есть панель «Попробовать»: введите Test merchant и API key, и страница подпишет запрос в вашем браузере, вызовет эндпоинт и покажет полный запрос и ответ (учётные данные остаются в памяти страницы). Если подпись не совпадает, сравните её по шагам в проверке подписи.

Node.js
import crypto from "node:crypto";

async function call(path, data) {
  const body = JSON.stringify(data);
  const sign = crypto.createHash("md5").update(Buffer.from(body).toString("base64") + process.env.BW_API_KEY).digest("hex");
  const res = await fetch("https://blockwallets.io" + path, {
    method: "POST",
    headers: { merchant: process.env.BW_MERCHANT, sign, "Content-Type": "application/json" },
    body,
  });
  return res.json();
}
PHP
function bw_call(string $path, array $data): array {
    $body = json_encode($data, JSON_UNESCAPED_UNICODE);
    $sign = md5(base64_encode($body) . getenv('BW_API_KEY'));
    $ch = curl_init('https://blockwallets.io' . $path);
    curl_setopt_array($ch, [
        CURLOPT_POST => true, CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['merchant: ' . getenv('BW_MERCHANT'), 'sign: ' . $sign, 'Content-Type: application/json'],
    ]);
    return json_decode(curl_exec($ch), true);
}
Python
import base64, hashlib, json, os, requests

def bw_call(path: str, data: dict) -> dict:
    body = json.dumps(data, separators=(",", ":"), ensure_ascii=False)
    sign = hashlib.md5((base64.b64encode(body.encode()).decode() + os.environ["BW_API_KEY"]).encode()).hexdigest()
    headers = {"merchant": os.environ["BW_MERCHANT"], "sign": sign, "Content-Type": "application/json"}
    return requests.post("https://blockwallets.io" + path, data=body.encode(), headers=headers).json()

2. Создание счёта POST /v1/payment

Когда клиент оформляет заказ или вводит сумму на странице пополнения, вызовите https://blockwallets.io/v1/payment и перенаправьте его на возвращённый result.url.

json
{
  "amount": "42.00",
  "currency": "USD",
  "order_id": "order_1042",
  "url_callback": "https://shop.example/webhooks/crypto",
  "url_return": "https://shop.example/cart",
  "url_success": "https://shop.example/thanks?order=1042"
}
ПараметрОбязательныйОписание
amountДаСумма строкой, не более двух знаков после запятой: "42.00". Ваша цена или число, введённое клиентом; не меньше минимума выбранной сети (см. сети)
currencyДаUSD, USDT или USDC, все 1:1
order_idДаНомер вашего заказа: буквы, цифры, -, _, до 100 символов. Повторный вызов с тем же order_id возвращает существующий счёт (дубликатов заказов не будет)
url_callbackНетURL вебхука. Если не указать, вебхук не отправляется
url_returnНетКуда ведёт «Назад» до оплаты
url_successНетКуда попадает клиент после оплаты
networkНетЗаранее выбрать сеть: tron / bsc / eth / base / polygon / arbitrum / optimism / avalanche / xlayer / btc / ltc / doge / bch / sol / ton; если не указать, клиент выберет на странице оплаты
to_currencyНетМонета в этой сети: USDT / USDC; для btc / ltc / doge / bch это BTC / LTC / DOGE / BCH (необязательно)
lifetimeНетСрок жизни счёта в секундах, 300 – 43200, по умолчанию 3600; всё, что меньше 600, считается как 600
accuracy_payment_percentНетКакая недоплата ещё считается оплатой, 0 – 5, по умолчанию 0. 100 = принять любую пришедшую сумму: paid сразу после подтверждения (paid_over, если больше), зачисляйте по payment_amount_usd из вебхука — удобно для пополнений. Если не указать, действует «Правило суммы» в разделе «Настройки › Правила приёма платежей и ставки» кабинета: «зачислять, сколько пришло» означает 100
subtractНетДоля комиссии платформы, которую платит клиент, 0 – 100, добавляется к payer_amount (комиссия платформы 1%, при больших оборотах ниже; при 1% и значении 100 счёт на $100 обойдётся клиенту в $101.00; см. цены). Если не указать, действует настройка «Комиссия и недоплата» в разделе «Настройки › Правила приёма платежей и ставки» кабинета (по умолчанию 0)
is_payment_multipleНетМожно ли доплатить недостающую сумму, по умолчанию true: статус wrong_amount_waiting, доплата на тот же адрес переводит счёт в paid (если при первой недоплате до конца оставалось менее 30 минут, срок переносится на 30 минут вперёд). false: первый же недоплаченный перевод переводит счёт в wrong_amount. Если не указать, действует настройка в кабинете
additional_dataНетЛюбая строка (до 255), возвращается как есть в запросах и вебхуках
json
{
  "state": 0,
  "result": {
    "uuid": "6f1c2a7e-…",
    "order_id": "order_1042",
    "amount": "42.00",
    "currency": "USD",
    "network": null,
    "address": null,
    "payer_amount": null,
    "payment_amount": null,
    "url": "https://blockwallets.io/pay/inv_01J8…",
    "expired_at": 1760965200,
    "status": "check",
    "is_final": false
  }
}

network, address и payer_amount заполняются, когда клиент выбирает сеть.

3. Запрос счетов

Основной канал — вебхуки, запросы служат запасным вариантом (например, если ваш сервер не работал и пропустил вебхук).

4. Статические кошельки POST /v1/wallet

Открывает постоянный адрес для одного клиента в одной сети. Один и тот же order_id (обычно id вашего пользователя) + сеть всегда дают один и тот же адрес; все сети EVM (BNB Chain, Ethereum, Base, Polygon, Arbitrum, Optimism, Avalanche, X Layer) используют один адрес, а TRON, BTC, LTC, DOGE, BCH, Solana и TON — каждая свой. Всё, что отправит клиент, зачисляется, на каждый перевод приходит вебхук; переводы BTC / LTC / DOGE / BCH / TRX / BNB / ETH / POL / AVAX / OKB / SOL / TON пересчитываются в доллары США по курсу на момент, когда каждый перевод был замечен (payment_amount_usd).

json
{
  "order_id": "user_42",
  "currency": "USDT",
  "network": "tron",
  "url_callback": "https://shop.example/webhooks/crypto"
}
json
{
  "state": 0,
  "result": {
    "wallet_uuid": "0b9d…",
    "uuid": "5e2f…",
    "order_id": "user_42",
    "currency": "USDT",
    "network": "tron",
    "address": "TXy4…8kQ2",
    "url": "https://blockwallets.io/deposit/dac_01J8…"
  }
}

result.url — размещённая у нас страница пополнения (адрес + QR-код + последние поступления), которую можно дать клиенту. Переводы ниже минимума сети (обычно $1, BTC $5) автоматически не зачисляются; чтобы их зачислили, свяжитесь с нами. Блокировка адресов (/v1/wallet/block-address) пока не поддерживается.

Вебхуки

Когда меняется статус счёта (paid, paid_over, wrong_amount_waiting, wrong_amount, cancel) и при каждом переводе на статический кошелёк, мы отправляем POST с JSON на url_callback. Ответ 2xx считается доставкой; иначе повторяем через 1 минуту, 5 минут, 30 минут, 2 часа, 12 часов, 24 часа и ещё 24 часа. Можно также отправить повторно из кабинета или через /v1/payment/resend.

json
{
  "type": "payment",
  "uuid": "6f1c2a7e-…",
  "order_id": "order_1042",
  "amount": "42.00",
  "payment_amount": "42",
  "payment_amount_usd": "42.00",
  "merchant_amount": "41.58",
  "commission": "0.42",
  "is_final": true,
  "status": "paid",
  "from": "TQ8m…",
  "wallet_address_uuid": null,
  "network": "tron",
  "currency": "USD",
  "payer_currency": "USDT",
  "payer_amount": "42",
  "payer_amount_exchange_rate": "1",
  "additional_data": null,
  "txid": "9c1e…",
  "sign": "5f0c9b…"
}
typeКогдаЗачисление
paymentИзменился статус счёта — см. statusЗачисляйте payment_amount_usd при paid / paid_over; убирайте дубликаты по uuid
walletНа статический кошелёк пришёл перевод (status всегда paid; order_id — тот, с которым вы открыли кошелёк)Зачисляйте payment_amount_usd; у каждого перевода свой uuid — убирайте дубликаты по нему

Проверка подписи (обязательна)

Подпись — это поле sign тела вебхука: удалите sign, закодируйте остальное так же, как PHP json_encode (компактно, / экранируется как \/, не-ASCII символы не экранируются), и md5(base64(закодированное) + API key) должно совпасть с sign. Используйте API key того же режима. Один и тот же вебхук может прийти более одного раза — убирайте дубликаты по uuid + status.

Если проверка не проходит, вставьте исходное тело вебхука в проверку подписи: она показывает результат каждого шага и отмечает, где ваш результат отличается (всё выполняется в вашем браузере; API key никуда не отправляется). Любой вебхук из раздела «Разработчикам › Журнал вебхуков» в кабинете открывается в проверке одним щелчком.

Node.js
import crypto from "node:crypto";

function verify(rawBody, apiKey) {
  const { sign, ...data } = JSON.parse(rawBody);
  const json = JSON.stringify(data).replaceAll("/", "\\/");
  const expected = crypto.createHash("md5").update(Buffer.from(json).toString("base64") + apiKey).digest("hex");
  return typeof sign === "string" && sign.length === expected.length && crypto.timingSafeEqual(Buffer.from(sign), Buffer.from(expected));
}
PHP
$data = json_decode(file_get_contents('php://input'), true);
$sign = $data['sign'] ?? '';
unset($data['sign']);
$expected = md5(base64_encode(json_encode($data, JSON_UNESCAPED_UNICODE)) . $apiKey);
if (!hash_equals($expected, $sign)) {
    http_response_code(401); exit;
}
Python
import base64, hashlib, hmac, json

def verify(raw_body: bytes, api_key: str) -> bool:
    data = json.loads(raw_body)
    sign = data.pop("sign", "")
    encoded = json.dumps(data, separators=(",", ":"), ensure_ascii=False).replace("/", "\\/")
    expected = hashlib.md5((base64.b64encode(encoded.encode()).decode() + api_key).encode()).hexdigest()
    return hmac.compare_digest(expected, sign)

Тестовый режим

Счета, созданные с Test merchant и API key, работают в тестовых сетях без настоящих денег. На странице оплаты есть кнопка «Симулировать оплату» (полная / половина / переплата), так что вы увидите смену статусов и вебхуки, не добывая тестовые монеты.

Переход с Cryptomus

  1. Кабинет «Разработчикам › Интеграция и ключи» → создайте merchant и API key.
  2. Замените в коде https://api.cryptomus.com на https://blockwallets.io и используйте новые merchant и API key.
  3. Добавьте свои домены в разделе «Домены сайта» (url_callback / url_return / url_success принимают только их).

Поддерживаются: /v1/payment, /v1/payment/info, /v1/payment/list, /v1/payment/services, /v1/payment/resend, /v1/wallet, /v1/test-webhook/payment, /v1/test-webhook/wallet. Отличия: счета выставляются только в USD / USDT / USDC (все 1:1, без курсового спреда); commission — наша комиссия платформы (полученная сумма × ставка продавца на момент создания счёта — стандартная 1%, по обороту вплоть до 0.5%; с доли, которую покрывает клиент, ничего не берётся дважды), а merchant_amount = получено − commission; когда клиент платит в BTC / LTC / DOGE / BCH / TRX / BNB / ETH / POL / AVAX / OKB / SOL / TON, мы берём медиану нескольких бирж, зафиксированную на 30 минут — payer_amount это количество монет к отправке, payer_amount_exchange_rate — стоимость одной монеты в долларах США, а платёж пересчитывается в payment_amount_usd по зафиксированному курсу (монеты остаются у нас, ничего не обменивается); сети tron / bsc / eth / base / polygon / arbitrum / optimism / avalanche / xlayer / btc / ltc / doge / bch / sol / ton; минимальный срок жизни счёта 10 минут; нет is_refresh и блокировки статических кошельков; по умолчанию вебхуки приходят с меняющихся IP; если вы используете список разрешённых IP, включите в кабинете «Вебхуки с фиксированного IP» в разделе «Разработчикам › Интеграция и ключи», и вебхуки будут приходить только с 18.163.145.41 — список разрешённых адресов лишь дополнительный слой, продолжайте проверять sign.

Переходите с NOWPayments или Coinbase Commerce? У нас есть совместимые API для обоих — смените базовый URL и ключи; см. руководство по переходу.

Сети и суммы

МонетаСетьПараметр networkМинимумПоступление
USDTTRONtron$1~1 мин
USDTBNB Chainbsc$1~1 мин
USDCBNB Chainbsc$1~1 мин
USDTEthereumeth$5~1 мин
USDCEthereumeth$5~1 мин
USDCBasebase$1~1 мин
USDTPolygonpolygon$1~1 мин
USDCPolygonpolygon$1~1 мин
USDTArbitrumarbitrum$1~1 мин
USDCArbitrumarbitrum$1~1 мин
USDTOptimismoptimism$1~1 мин
USDCOptimismoptimism$1~1 мин
USDTAvalancheavalanche$1~1 мин
USDCAvalancheavalanche$1~1 мин
USDTX Layerxlayer$1~1 мин
USDCX Layerxlayer$1~1 мин
USD1BNB Chainbsc$1~1 мин
FDUSDBNB Chainbsc$1~1 мин
DAIEthereumeth$5~1 мин
DAIArbitrumarbitrum$1~1 мин
DAIBasebase$1~1 мин
BTCBitcoinbtc$5~10 мин
LTCLitecoinltc$1~3 мин
DOGEDogecoindoge$1~1 мин
BCHBitcoin Cashbch$1~10 мин
TRXTRONtron$1~1 мин
BNBBNB Chainbsc$1~1 мин
ETHEthereumeth$5~1 мин
ETHBasebase$1~1 мин
ETHArbitrumarbitrum$1~1 мин
ETHOptimismoptimism$1~1 мин
POLPolygonpolygon$1~1 мин
AVAXAvalancheavalanche$1~1 мин
OKBX Layerxlayer$1~1 мин
USDTSolanasol$1~1 мин
USDCSolanasol$1~1 мин
SOLSolanasol$1~1 мин
USDTTONton$1~1 мин
TONTONton$1~1 мин

Комиссии ERC-20 высоки, поэтому минимум $5; комиссии Bitcoin тоже немалые, минимум $5; во всех остальных сетях $1. Клиенты должны отправлять в той сети, которая указана на странице оплаты — деньги, отправленные в другой сети, автоматически не зачисляются. BTC / LTC / DOGE / BCH отображаются как «обнаружен» сразу, как попадают в мемпул, и засчитываются, когда наберут достаточно подтверждений; заменённые (RBF) или отброшенные транзакции не засчитываются. Нативные монеты (TRX, BNB, ETH, POL, AVAX, OKB, SOL, TON) котируются по зафиксированному курсу и зачисляются в долларах США, как BTC / LTC / DOGE / BCH; указывайте и сеть, и монету: для счетов network: "bsc", to_currency: "BNB", для статических кошельков network: "bsc", currency: "BNB". Одна сеть без монеты по умолчанию означает USDT в этой сети (USDC в Base). Переводы, сделанные контрактами (мультиподпись, пакетные выплаты), тоже принимаются; в некоторых сетях хеш их транзакции недоступен, и txid в вебхуке равен null.

Ошибки

json
{ "state": 1, "message": "amount must be a number like 10.28" }
HTTPЧастые причины
422Отсутствуют или некорректны параметры; сумма ниже минимума сети; URL вебхука или перенаправления не входит в зарегистрированные домены; неподдерживаемая монета или сеть в /v1/payment
401Неверный merchant, неверный sign (Invalid Sign.) или API key был заменён
404Счёта не существует или он не ваш (Payment not found); в /v1/wallet — неподдерживаемое сочетание монеты и сети (The service was not found)
503Сеть временно недоступна — выберите другую или не задавайте сеть заранее

Если подпись неверна (Invalid Sign.), в ответе есть объект debug: body_base64 — base64 тела запроса, которое мы получили (ваше собственное содержимое, но никогда не API key), а body_bytes — его длина. Сравните с base64, которое вы подписывали: если они различаются, отправленное вами тело не совпадает с подписанной строкой (ваш фреймворк сериализовал его заново, прокси изменил кодировку, добавился завершающий перевод строки); если совпадают, неверен API key. Вставьте его в проверку подписи, чтобы увидеть первое отличие.

json
{
  "state": 1,
  "message": "Invalid Sign.",
  "debug": {
    "body_base64": "eyJhbW91bnQiOiI0Mi4wMCIsImN1cnJlbmN5IjoiVVNEIiwi…",
    "body_bytes": 158,
    "sign_formula": "md5(body_base64 + API key)"
  }
}

Вопросы

Клиенты пополняют на любую сумму — какой способ выбрать?

Счета. Пусть клиент вводит сумму на вашей странице пополнения, создайте на неё счёт и зачислите payment_amount_usd, когда платёж придёт. Статические кошельки нужны, только если клиенты должны сохранить один адрес и многократно отправлять на него.

Что, если клиент заплатил меньше?

До истечения срока клиент может отправить разницу на странице оплаты (она показывает, сколько ещё нужно; статус wrong_amount_waiting, а если при первой недоплате до конца оставалось менее 30 минут, срок переносится на 30 минут вперёд). Если к истечению всё ещё не хватает, счёт получает статус wrong_amount, а payment_amount_usd в вебхуке — полученная сумма; сервисы с пополнением могут просто зачислить её.

Что, если клиент заплатил поздно или дважды?

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

Что, если клиент отправил в неверной сети?

Например, счёт в TRON, а он отправил из BNB Chain: платёж автоматически не зачисляется — напишите нам, и мы разберём его вручную.

Сколько это стоит?

1% с каждого полученного платежа, ставка автоматически снижается по обороту прошлого месяца (0.9% от $50,000, 0.8% от $100,000, 0.7% от $250,000, 0.6% от $500,000 и 0.5% от $1,000,000), без абонентской платы и платы за подключение. Комиссию сети клиент платит при отправке; чтобы переложить её на клиента, задайте subtract при создании счёта или значение по умолчанию в кабинете. За вывод дополнительная комиссия не взимается. См. цены.

Когда деньги попадут ко мне?

Они зачисляются на ваш баланс сразу после подтверждения платежа. Запросите вывод на свой кошелёк в разделе «Средства › Баланс и вывод»; после нашего одобрения мы выплачиваем, и транзакция в блокчейне появляется в истории выводов.

Можно также включить автовывод: когда доступный баланс достигает заданной вами суммы или раз в сутки в 00:00 UTC выводится весь доступный баланс. Автоматические выводы проверяются так же, и каждое изменение настроек отправляет уведомление на вашу почту.