Криптоплатежі в e-commerce: кастомний платіжний шлюз
Типова помилка при інтеграції крипти в e-commerce: ставляться до неї як до ще одного payment method у існуючому checkout. Насправді це інший flow — у криптоплатежів немає instant finality (крім L2), немає chargebacks, курс змінюється поки користувач іде до гаманця, а partial payment — реальний edge case, а не теоретичний. За 5 років ми виявили типові вузькі місця: неправильний розрахунок газу, відсутність rollback при частковій оплаті, проблеми з верифікацією транзакцій у L2. Нижче — повний розбір архітектури, від вибору провайдера до бухгалтерської звітності.
Кастомна інтеграція окупається при обсягах від 100 платежів на день у 3 рази швидше, ніж hosted-рішення. Ми займаємося інтеграцією криптоплатежів з початку розвитку цього напрямку і бачили, як магазини втрачали до 12% виручки через неправильну обробку нюансів.
Вибір підходу: hosted vs кастомний
Порівняємо три варіанти:
| Параметр | Готовий сервіс (NOWPayments, CoinGate) | Кастом через API провайдера | Повністю кастомний on-chain |
|---|---|---|---|
| Час запуску | 1-2 дні | 3-5 днів | 2-4 тижні |
| Комісія | 0.5–1% | 0.1–0.5% (тільки мережа) | Тільки gas мережі |
| Підтримка монет | Фіксований список | Будь-які ERC-20/BEP-20 | Будь-які (Solana, Bitcoin) |
| Приватність | Третя сторона бачить транзакції | Провайдер бачить тільки платежі | Повна приватність |
Готовий сервіс — для обсягів до кількох сотень платежів на місяць. Кастомна інтеграція виправдана при:
- Потрібен конкретний set монет/мереж, які не підтримує провайдер
- Вимоги до приватності (клієнт не хоче, щоб третя сторона бачила транзакції)
- Високі обсяги, де комісії провайдера значні
- Специфічна логіка (наприклад, автоматична конвертація через DEX)
Нижче — кастомна інтеграція, оскільки вона потребує більше технічних рішень. Наш досвід: 30+ проєктів, гарантія на код 12 місяців.
WooCommerce: кастомний payment gateway plugin
WooCommerce надає абстрактний клас WC_Payment_Gateway — достатньо його розширити:
class WC_Crypto_Gateway extends WC_Payment_Gateway {
public function __construct() {
$this->id = 'crypto_payment';
$this->title = 'Оплата криптовалютою';
$this->method_description = 'Bitcoin, Ethereum, USDT та інші';
$this->supports = ['products'];
$this->init_form_fields();
$this->init_settings();
add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']);
add_action('woocommerce_api_crypto_payment', [$this, 'handle_webhook']);
}
public function process_payment($order_id): array {
$order = wc_get_order($order_id);
// Створюємо платіж у зовнішньому сервісі або генеруємо адресу
$payment = $this->create_crypto_payment($order);
// Зберігаємо дані для відображення інструкцій
$order->update_meta_data('_crypto_payment_id', $payment['id']);
$order->update_meta_data('_crypto_pay_address', $payment['address']);
$order->update_meta_data('_crypto_pay_amount', $payment['amount']);
$order->update_meta_data('_crypto_expires_at', $payment['expires_at']);
$order->set_status('pending', 'Очікування криптоплатежу');
$order->save();
return [
'result' => 'success',
'redirect' => $this->get_return_url($order),
];
}
public function handle_webhook(): void {
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_PAYMENT_SIGNATURE'] ?? '';
if (!$this->verify_signature($payload, $signature)) {
wp_die('Invalid signature', 401);
}
$data = json_decode($payload, true);
$order = wc_get_order($data['order_id']);
if (!$order) wp_die('Order not found', 404);
if ($data['status'] === 'confirmed') {
$order->payment_complete($data['transaction_hash']);
$order->add_order_note(
sprintf('Криптоплатіж підтверджено. TX: %s', $data['transaction_hash'])
);
}
wp_die('OK', 200);
}
}Сторінка thank you (після редиректу) має показувати адресу, QR-код та суму з таймером. WooCommerce викликає get_return_url() який веде на стандартну thank you сторінку — її можна кастомізувати через woocommerce_thankyou_{gateway_id} action.
Shopify: використання Payment Apps API
Shopify не дозволяє довільний кастомний PHP. Для інтеграції крипти потрібно створити Shopify App через Partner Dashboard, використовувати Payments Apps API.
Принцип: ваша програма реєструється як payment provider. При оформленні замовлення Shopify робить HTTP запит до вашого endpoint з даними замовлення, ви повертаєте URL для редиректу на вашу payment page, і після підтвердження надсилаєте resolved/rejected через GraphQL mutation.
// Shopify викликає цей endpoint
app.post('/shopify/payment', async (req, res) => {
const { gid, amount, currency, cancelUrl, kind } = req.body;
// Створюємо внутрішній платіж
const payment = await createCryptoInvoice({
shopifyOrderGid: gid,
fiatAmount: parseFloat(amount),
fiatCurrency: currency,
});
// Редиректимо на нашу payment сторінку
res.json({
redirect_url: `${process.env.APP_URL}/pay/${payment.id}`,
});
});
// Після підтвердження платежу
async function notifyShopifyPaymentComplete(paymentGid: string, txHash: string) {
const mutation = `
mutation PaymentSessionResolve($id: ID!) {
paymentSessionResolve(id: $id) {
paymentSession {
id
state {
... on PaymentSessionStateResolved {
code
}
}
}
userErrors {
field
message
}
}
}
`;
await shopifyGraphQL(mutation, { id: paymentGid });
}
Як курс і таймер впливають на UX та виручку?
Користувач бачить ціну 99$, натискає "оплатити криптою", і потрапляє на сторінку з сумою 0.0271 ETH. Ця сума дійсна 15–30 хвилин. Якщо користувач зволікає або курс сильно змінюється — потрібен refresh механізм.
Таймер на сторінці оплати має бути не декоративним — при закінченні автоматично оновлюємо invoice:
// Клієнтський код
let expiresAt = new Date(invoice.expiresAt);
const timer = setInterval(async () => {
const remaining = expiresAt.getTime() - Date.now();
if (remaining <= 0) {
clearInterval(timer);
// Запитуємо новий invoice з актуальним курсом
const refreshed = await fetch(`/api/payment/${invoiceId}/refresh`, {
method: 'POST'
});
const newInvoice = await refreshed.json();
expiresAt = new Date(newInvoice.expiresAt);
updateUI(newInvoice); // Оновлюємо QR та суму
}
}, 1000);На бекенді при refresh — перераховуємо суму в крипті за актуальним курсом, оновлюємо запис у БД, та ж адреса (якщо використовуємо unique address per payment).
Reconciliation та звітність
Для бухгалтерії потрібна конвертація крипто-суми у фіат на момент отримання. Фіксуємо в базі: crypto_amount, crypto_currency, fiat_amount, fiat_currency, exchange_rate, confirmed_at. Джерело курсу — Chainlink (on-chain) або CoinGecko API (off-chain) з timestamp. Це критично для податкового обліку.
Що робити при частковій оплаті (partial payment)?
Edge case: користувач надіслав 0.02 ETH замість 0.0271 ETH. Без спеціальної логіки замовлення зависне. Рішення: на рівні воркера перевіряємо, що отримана сума >= expected, інакше позначаємо як partially_paid і генеруємо другий invoice на залишок. Включаємо підтримку мульти-транзакцій в одному замовленні.
Чому варто обрати кастомну інтеграцію?
Кастомна інтеграція дає повний контроль над стеком: від вибору блокчейну до логіки обробки помилок. Ви не залежите від комісій та обмежень провайдера. При обсягах від 100 платежів на день економія на комісіях перевищує вартість розробки вже за 3 місяці. Ми також реалізуємо захист від reentrancy-атак та оптимізуємо gas consumption для масових операцій.
Оптимізація газу при великій кількості платежів
Використовуйте gas price oracle та batch-транзакції через ретранслятор. Це знижує витрати на комісію до 40%.Що входить у роботу
- Технічний аудит поточного магазину (CMS, хостинг, платіжні модулі)
- Вибір архітектури: hosted чи кастомний, on-chain чи L2
- Розробка платіжного шлюзу (WooCommerce, Shopify, кастом)
- Інтеграція з гаманцем (MetaMask, WalletConnect, Ledger)
- Налаштування webhook-ів та статусів замовлень
- Розробка сторінки оплати з QR-кодом і таймером
- Підключення оракула курсу (Chainlink) або біржового API
- Тестування на testnet "під ключ"
- Аудит смарт-контрактів (Slither, Mythril) — при необхідності
- Документація та навчання персоналу
- Пост-релізна підтримка 1 місяць
Отримайте консультацію — ми зв'яжемося протягом 3 годин і покажемо приклад аналогічної інтеграції для вашої ніші. Замовте пілотну інтеграцію на тестовому домені — 3 дні, щоб переконатися в сумісності.







