Собственный REST API

Открыть в ChatGPTОткрыть в Claude

Собственный API — это REST-интерфейс blockwallets: счета в центах США, идемпотентный ref для каждого заказа, статические депозитные аккаунты на всех сетях и вебхуки с подписью HMAC-SHA256. Он создаёт такие же счета на той же странице оплаты, что и API, совместимый с Cryptomus, с теми же комиссиями и балансом.

Ключи вы создаёте сами в кабинете, в разделе «Разработчикам › Интеграция и ключи»: ключ Live и ключ Test и секреты подписи их вебхуков. Каждый показывается один раз, в списке виден только префикс. Если в аккаунте включена двухфакторная аутентификация, для создания или обновления ключа Live нужно ввести код. Ещё нет аккаунта продавца? Запросите доступ. Уже работаете с Cryptomus? Посмотрите API, совместимый с Cryptomus (как выбрать).

Ключи и запросы

Базовый URL: https://blockwallets.io. Запросы и ответы — JSON. Каждый запрос содержит:

Ошибки возвращаются с HTTP-статусом и телом {"error": {"code": "…", "message": "…"}}: 400 invalid_request (отсутствует поле или оно неверного формата), 401 unauthorized (ключ отсутствует, неизвестен или отключён), 404 not_found, 409 conflict (запрос противоречит текущему состоянию счёта), 422 currency_unsupported.

Эндпоинты

ЭндпоинтЧто делает
GET /v1/networksСети, которые можно принимать прямо сейчас в режиме этого ключа: минимум, подтверждения, обычное время поступления и оценка комиссии; для монет с курсом указан текущий курс
POST /v1/invoicesСоздаёт счёт (201) или возвращает существующий для того же ref (200)
GET /v1/invoices?ref=…Находит счёт по вашему ref
GET /v1/invoices/:idНаходит счёт по id
POST /v1/invoices/:id/networkСамостоятельный выбор сети для счёта (страница оплаты в вашем оформлении): возвращает address и pay_amount для показа клиенту
POST /v1/invoices/:id/closeЗакрывает ожидающий оплаты счёт, по которому не было переводов
POST /v1/deposit-accountsОткрывает (201) или возвращает (200) депозитный аккаунт одного клиента: постоянный адрес в каждой сети
GET /v1/deposit-accounts?customer_ref=…Находит депозитный аккаунт по customer_ref
GET /v1/deposit-accounts/:idНаходит депозитный аккаунт по id
GET /v1/depositsСписок депозитов одного аккаунта (account_id или customer_ref, limit 1–200, по умолчанию 50)
GET /v1/deposits/:idНаходит один депозит
GET /v1/eventsДоставки вебхуков по одному счёту или депозиту (invoice_id или deposit_id)
POST /v1/events/:id/redeliverПовторно отправляет вебхук (202)

Добавьте ?probe=1 к запросу счёта или депозитного аккаунта, чтобы заодно проверить блокчейн (не чаще раза в 10 секунд); без него вы получите последнее состояние от нашего сканера, который проверяет каждую минуту.

Создание счёта POST /v1/invoices

Вызовите POST /v1/invoices, когда клиент оформляет заказ, и перенаправьте его на pay_url из ответа.

curl
curl -X POST https://blockwallets.io/v1/invoices \
  -H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
  -d '{"ref":"order_1042","amount":4200,"title":"Order #1042",
       "return_url":"https://shop.example/cart","success_url":"https://shop.example/thanks?order=1042",
       "meta":{"user_id":42}}'
ПолеОбязательноеОписание
refДаНомер вашего заказа: 1–64 символа — буквы, цифры и _ . : -. Уникален в пределах режима; повторная отправка того же ref с теми же полями возвращает тот же счёт, с другими полями — 409
amountДаСумма в центах США целым числом: 4200 = $42.00. После выбора сети не меньше минимума этой сети
titleДаЧто клиент видит на странице оплаты, до 64 символов
return_urlДаКуда ведёт «Назад» на странице оплаты; должен быть на одном из доменов вашего сайта
success_urlНетКуда попадает клиент после оплаты; по умолчанию return_url
networkНетЗаранее выбрать id сети из таблицы сетей; если не указать, клиент выберет на странице оплаты
customer_refНетВаш id клиента, до 64 символов, возвращается как есть
lifetimeНетСрок жизни в секундах, 600 – 43200, по умолчанию 3600
amount_ruleНет"any" = зачислять всё, что пришло (пополнения): paid сразу после подтверждения. Если не указать, действует «Правило суммы» в разделе «Настройки › Правила приёма платежей и ставки» кабинета
accuracy_percentНетКакая недоплата ещё считается оплатой, 0 – 5 (процентов), по умолчанию 0
subtract_percentНетДоля комиссии платформы, которую платит клиент, 0 – 100 (процентов), добавляется к pay_amount; если не указать, действует значение по умолчанию из кабинета
payment_multipleНетМожно ли доплатить недостающую сумму на тот же адрес; по умолчанию берётся из кабинета (включено, если вы не меняли). false: первый же недоплаченный перевод завершается как wrong_amount
metaНетЛюбой JSON-объект до 2 КБ, возвращается как есть в запросах и вебхуках
currencyНетТолько USD (по умолчанию); любое другое значение даёт 422

Каждый URL должен быть на одном из доменов вашего сайта (кабинет → «Разработчикам › Интеграция и ключи»). Ответ — объект счёта ниже; network, address и pay_amount заполняются после выбора сети.

Объект счёта

Идентификаторы начинаются с inv_. amount — в центах США; pay_amount и paid_amount — количество монет десятичной строкой в выбранной сети.

json
{
  "id": "inv_01J8…",
  "ref": "order_1042",
  "mode": "live",
  "status": "pending",
  "amount": 4200,
  "currency": "USD",
  "title": "Order #1042",
  "meta": { "user_id": 42 },
  "network": null,
  "address": null,
  "pay_amount": null,
  "paid_amount": null,
  "payments": [],
  "pay_url": "https://blockwallets.io/pay/inv_01J8…",
  "return_url": "https://shop.example/cart",
  "success_url": "https://shop.example/thanks?order=1042",
  "created_at": "2026-11-03T08:00:00.000Z",
  "expires_at": "2026-11-03T09:00:00.000Z",
  "paid_at": null,
  "closed_at": null
}
statusЗначениеЧто делаете вы
pendingОжидает оплаты—
confirmingПеревод виден и подтверждается, либо пришло меньше нужного и можно доплатить—
paidОплаченОтгрузите или зачислите заказ
paid_overОплачен с переплатойТо же; излишек на вашем балансе
wrong_amountЗавершён с суммой меньше полной (по истечении срока или при первом недоплаченном переводе, если payment_multiple равен false)Сервисы с пополнением могут зачислить пришедшее (paid_amount; у монет с курсом есть и paid_cents); магазины просят клиента доплатить остаток
closedИстёк, ничего не получено, или вы закрыли его— (деньги, пришедшие позже, всё равно зачисляются и приходят в уведомлении)

Другие поля: pay_url (страница оплаты), payments (каждый перевод с txid, amount, confirmations и confirmed), expires_at, paid_at, closed_at; у BTC, LTC, DOGE, BCH и родных монет есть также rate (долларов США за монету, фиксируется на 30 минут), rate_locked_until и paid_cents (сколько уже пришло, в центах США).

Сети

Передавайте id как network. GET /v1/networks возвращает сети, открытые сейчас в вашем режиме; сеть может быть приостановлена, поэтому лучше читать этот список, чем зашивать значения в код.

networkМонетаБлокчейнМинимум
USDT_TRC20USDTTRON$1
USDT_BEP20USDTBNB Chain$1
USDC_BEP20USDCBNB Chain$1
USDT_ERC20USDTEthereum$5
USDC_ERC20USDCEthereum$5
USDC_BASEUSDCBase$1
USDT_POLYGONUSDTPolygon$1
USDC_POLYGONUSDCPolygon$1
USDT_ARBITRUMUSDTArbitrum$1
USDC_ARBITRUMUSDCArbitrum$1
USDT_OPTIMISMUSDTOptimism$1
USDC_OPTIMISMUSDCOptimism$1
USDT_AVALANCHEUSDTAvalanche$1
USDC_AVALANCHEUSDCAvalanche$1
USDT_XLAYERUSDTX Layer$1
USDC_XLAYERUSDCX Layer$1
USD1_BEP20USD1BNB Chain$1
FDUSD_BEP20FDUSDBNB Chain$1
DAI_ERC20DAIEthereum$5
DAI_ARBITRUMDAIArbitrum$1
DAI_BASEDAIBase$1
BTCBTCBitcoin$5
LTCLTCLitecoin$1
DOGEDOGEDogecoin$1
BCHBCHBitcoin Cash$1
TRXTRXTRON$1
BNBBNBBNB Chain$1
ETHETHEthereum$5
ETH_BASEETHBase$1
ETH_ARBITRUMETHArbitrum$1
ETH_OPTIMISMETHOptimism$1
POLPOLPolygon$1
AVAXAVAXAvalanche$1
OKBOKBX Layer$1
USDT_SOLUSDTSolana$1
USDC_SOLUSDCSolana$1
SOLSOLSolana$1
USDT_TONUSDTTON$1
TONTONTON$1

Депозитные аккаунты (статические адреса) POST /v1/deposit-accounts

POST /v1/deposit-accounts с {"customer_ref": "user_42"} выдаёт этому клиенту постоянный адрес в каждой сети (все сети EVM используют один адрес). Всё, что он отправит, зачисляется в долларах США, по одному вебхуку deposit.credited на каждый перевод.

curl
curl -X POST https://blockwallets.io/v1/deposit-accounts \
  -H "Authorization: Bearer $BW_KEY" -H "Content-Type: application/json" \
  -d '{"customer_ref":"user_42"}'
json
{
  "id": "dac_01J8…",
  "mode": "live",
  "customer_ref": "user_42",
  "deposit_url": "https://blockwallets.io/deposit/dac_01J8…",
  "min_amount": 100,
  "currency": "USD",
  "networks": [
    { "id": "USDT_TRC20", "chain": "tron", "token": "USDT", "address": "TXy4…8kQ2", "min_amount": 100, "confirmations": 1, … },
    { "id": "USDC_BASE", "chain": "base", "token": "USDC", "address": "0x5aE1…", "min_amount": 100, "confirmations": 20, … }
  ]
}

Переводы ниже минимума (обычно $1, BTC $5) записываются как below_min и автоматически не зачисляются; чтобы их зачислили, свяжитесь с нами.

Вебхуки

Мы отправляем POST с JSON на URL вебхука из кабинета («Разработчикам › Интеграция и ключи»; у Live и Test свои URL и секрет). Тело — это событие:

http
POST /your/webhook
X-BW-Event: ev_01J8…
X-BW-Delivery: 1
X-BW-Signature: t=1793693052,v1=5f0c9b…

{"id":"ev_01J8…","type":"invoice.paid","created_at":"2026-11-03T08:04:12.000Z","invoice":{"id":"inv_01J8…","ref":"order_1042","status":"paid","amount":4200,…}}
СобытиеКогда
invoice.paidСчёт стал paid или paid_over (включая деньги, пришедшие после истечения срока)
invoice.wrong_amountСчёт завершился как wrong_amount
invoice.closedСчёт истёк, ничего не получено, или вы закрыли его
deposit.creditedПеревод на депозитный аккаунт зачислен

Проверяйте по исходному телу до разбора, отклоняйте t, отличающийся от ваших часов более чем на 300 секунд, и сравнивайте за постоянное время. invoice / deposit в теле — тот же объект, что возвращает запрос.

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

// rawBody: the request body exactly as received (a string), header: X-BW-Signature
function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.trim().split("=")));
  const t = Number(parts.t);
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  return typeof parts.v1 === "string" && parts.v1.length === expected.length
    && crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}

Ответ 2xx считается доставкой; иначе повторяем через 1 минуту, 5 минут, 30 минут, 2 часа, 12 часов, 24 часа и ещё 24 часа (всего 8 попыток).

События и повторная отправка

GET /v1/events?invoice_id=inv_… (или deposit_id=dep_…) показывает вебхуки по одному счёту или депозиту с их state, attempts, last_status и last_error. POST /v1/events/ev_…/redeliver сразу ставит вебхук в очередь заново, например после того, как вы исправили свой эндпоинт. Раздел «Разработчикам › Журнал вебхуков» в кабинете показывает каждую попытку с запросом и ответом.

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

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