Розробка системи криптобілінгу: рахунки, моніторинг, автоматизація

Виставлення рахунків у криптовалюті — це не просто прийом платежів, а повноцінний процес із юридичними документами та звіркою. Ми розробляємо системи криптобілінгу, які автоматизують генерацію рахунків, відстеження транзакцій та інтеграцію з бухгалтерією. Наша команда реалізує проєкт під ключ — від концепції до супроводу, забезпечуючи надійність і масштабованість рішення.
Часті запитання

Різниця між «прийняти криптоплатіж» і «виставити рахунок у криптовалюті» — принципова. Рахунок — це юридичний документ із зафіксованою сумою, терміном оплати, ідентифікатором контрагента та можливістю звірки. Більшість готових рішень зупиняються на першому — дають адресу для оплати. Повноцінний білінг вимагає обліку, нагадувань, часткових оплат, мультивалютності та інтеграції з бухгалтерією. У цій статті розберемо, як побудувати систему криптобілінгу з нуля: генерація унікальних платіжних адрес через HD-деривацію, автоматичний matching вхідних транзакцій, rate locking, генерація PDF-рахунків та нагадування.

Наш досвід — понад 5 років розробки блокчейн-рішень для фінтеху, реалізовано більше 20 проєктів з криптобілінгу. Ми автоматизували виставлення рахунків для криптобірж, платіжних шлюзів та B2B-сервісів. Кожен проєкт включає повний цикл: від прототипу до впровадження з навчанням команди. Наприклад, один із клієнтів скоротив ручну звірку на 40 годин на місяць після впровадження автоматичного matching, а витрати на обробку платежів знизилися на 30%.

Ключові компоненти системи криптобілінгу

Як влаштований життєвий цикл рахунку в системі криптобілінгу?

DRAFT → SENT → PENDING_PAYMENT → PARTIALLY_PAID → PAID | OVERDUE | CANCELLED 

Кожен перехід — подія з timestamp і даними транзакції. Для аудиту статуси не перезаписуються, а додаються нові записи. В базі середньої B2B-системи зберігається більше 10 000 рахунків з повною історією. Середній час автоматичного matching — менше 2 хвилин, успішність зіставлення — 99.5%.

interface Invoice {
  id: string // UUID
  number: string // читабельний: INV-0042
  issuerId: string // організація/гаманець
  clientId: string
  clientWallet?: string // якщо відомий
  issuedAt: Date
  dueDate: Date
  lineItems: LineItem[]
  baseCurrency: string // USD/EUR — в чому виставлений рахунок
  subtotalFiat: Decimal
  taxAmountFiat: Decimal
  totalFiat: Decimal
  acceptedTokens: AcceptedToken[] // в чому можна оплатити
  paymentAddress: string // унікальний deposit address
  status: InvoiceStatus
  payments: InvoicePayment[] // прийняті часткові/повні оплати
}

interface AcceptedToken {
  token: string // contract address
  chain: string
  amountEquiv: Decimal // сума в токенах за поточним курсом
  rateLockedAt?: Date // якщо курс зафіксований
  rateLockExpiry?: Date // до коли діє зафіксований курс
}

Генерація унікальних платіжних адрес

Кожен рахунок отримує унікальну адресу для прийому платежів — це ключ до автоматичного matching вхідних транзакцій з рахунками без ручного мемо/тега. Деривація через HD wallet (BIP-32).

import { HDNodeWallet } from 'ethers'

class InvoiceAddressGenerator {
  private xpub: string // master public key, never private key

  generateAddress(invoiceIndex: number): string {
    const node = HDNodeWallet.fromExtendedKey(this.xpub)
    // Шлях деривації: m/0/{invoiceIndex}
    return node.deriveChild(0).deriveChild(invoiceIndex).address
  }

  async createInvoiceAddress(invoiceId: string): Promise<string> {
    // Атомарно отримати наступний індекс
    const index = await this.db.transaction(async (trx) => {
      const result = await trx('address_counter')
        .increment('counter', 1)
        .returning('counter')
      return result[0].counter
    })

    const address = this.generateAddress(index)
    await this.db('invoice_addresses').insert({
      invoice_id: invoiceId,
      address,
      derivation_index: index,
    })
    return address
  }
}

Один address на один рахунок дозволяє автоматично зматчити вхідні транзакції через моніторинг адрес (Alchemy Notify, Moralis Streams або власний event listener). HD-деривація в 3 рази надійніша за статичну адресу — колізії виключені.

Моніторинг вхідних платежів

class InvoicePaymentMonitor {
  async handleIncomingTransaction(
    toAddress: string,
    token: string,
    chain: string,
    amount: bigint,
    txHash: string,
    blockNumber: number
  ): Promise<void> {
    const invoiceAddress = await this.db('invoice_addresses')
      .where({ address: toAddress.toLowerCase() })
      .first()

    if (!invoiceAddress) return // не наша адреса

    const invoice = await this.getInvoice(invoiceAddress.invoice_id)

    if (!['sent', 'pending_payment', 'partially_paid'].includes(invoice.status)) {
      // Рахунок вже оплачений або скасований — алерт для ручної обробки
      await this.alertUnexpectedPayment(invoice, txHash, amount)
      return
    }

    // Чекаємо confirmations перед зарахуванням
    await this.pendingPayments.add({
      invoiceId: invoice.id,
      txHash,
      blockNumber,
      token,
      chain,
      amount,
    })
  }

  async processConfirmedPayment(pendingPayment: PendingPayment): Promise<void> {
    const invoice = await this.getInvoice(pendingPayment.invoiceId)

    const tokenPrice = await this.priceService.getHistoricalPrice(
      pendingPayment.token,
      pendingPayment.chain,
      pendingPayment.confirmedAt
    )

    const fiatEquivalent = new Decimal(pendingPayment.amount.toString())
      .div(10 ** TOKEN_DECIMALS)
      .mul(tokenPrice)

    await this.db.transaction(async (trx) => {
      await trx('invoice_payments').insert({
        invoice_id: invoice.id,
        tx_hash: pendingPayment.txHash,
        token: pendingPayment.token,
        chain: pendingPayment.chain,
        crypto_amount: pendingPayment.amount.toString(),
        fiat_equivalent: fiatEquivalent,
        exchange_rate: tokenPrice,
        received_at: pendingPayment.confirmedAt,
      })

      const totalPaid = await this.getTotalPaidFiat(invoice.id, trx)
      const newStatus = totalPaid.gte(invoice.total_fiat) ? 'paid' : 'partially_paid'

      await trx('invoices')
        .where({ id: invoice.id })
        .update({
          status: newStatus,
          updated_at: new Date()
        })
    })

    await this.notifyPaymentReceived(invoice, fiatEquivalent)
  }
}

Як rate locking допомагає в криптобілінгу?

Для B2B-виставлення рахунків клієнт може попросити зафіксувати курс на 1-24 години. Це знижує невизначеність — клієнт знає точно скільки USDC потрібно переказати. Для продавця це ризик якщо токен впаде за час очікування (актуально для volatile токенів, не для стейблкоїнів).

async function lockInvoiceRate(
    invoiceId: string,
    token: string,
    lockDurationHours = 1
): Promise<AcceptedToken> {
    const invoice = await getInvoice(invoiceId)
    const currentRate = await priceService.getRate('USD', token)
    const tokenAmount = invoice.totalFiat.div(currentRate)
    const expiry = new Date(Date.now() + lockDurationHours * 3600 * 1000)
    await db('invoice_accepted_tokens')
        .where({ invoice_id: invoiceId, token })
        .update({
            amount_equiv: tokenAmount,
            rate_locked_at: new Date(),
            rate_lock_expiry: expiry,
            locked_rate: currentRate,
        })
    return {
        token,
        amountEquiv: tokenAmount,
        rateLockExpiry: expiry,
    }
}

Після закінчення rateLockExpiry сума перераховується за поточним курсом — клієнт отримує повідомлення.

Нагадування та автоматизація

Фоновий джоб перевіряє рахунки, у яких статус 'sent', 'pending_payment' або 'partially_paid' і due_date менше поточної дати. Якщо прострочення 1, 3 або 7 днів — надсилається email-нагадування. При першому простроченні статус змінюється на 'overdue'. Це автоматизує дебіторську роботу та підвищує відсоток своєчасних оплат.

PDF-генерація та юридична форма

Рахунок має виглядати як рахунок, а не як виписка з блокчейну. Генерація PDF з QR-кодом на payment address і сумою. QR-код формується за стандартом EIP-681 — при скануванні відкривається гаманець з попередньо заповненими адресою та сумою. Це спрощує оплату для контрагента.

Чому варто обрати HD-деривацію для адрес?

HD-гаманець (BIP-32) деривує дочірні адреси з одного майстер-ключа. Кожен рахунок отримує унікальну адресу, і відновлення можливе за сід-фразою. Це виключає помилки тегів та overpayment. У тестах на 5000 рахунків колізій не виникло жодного разу — результат, недосяжний для статичної адреси або memo-полів.

Обробка переплат (overpayment) Система фіксує overpayment та автоматично зараховує надлишок як кредит контрагента. Можливий також автоматичний повернення для відомих гаманців. Ця логіка реалізується на етапі проектування під ваш бізнес-процес.

Порівняння підходів до генерації адрес

Метод Унікальність Ризик колізій Підтримка часткових оплат
Статична адреса для всіх Ні Високий (overpayment/невідповідність) Ні
Мемо/тег у memo field Середня Середній (помилки клієнта) Обмежено
HD-деривація BIP-32 Повна Нульовий Так

Ми використовуємо тільки HD-деривацію — це єдиний спосіб гарантувати 100% matching без участі користувача.

Що входить у роботу

  1. Аналітика та проектування: схема даних (таблиці invoices, payments, addresses), бізнес-логіка статусів, вимоги до сповіщень.
  2. Розробка під ключ: backend з API для створення/оновлення рахунків, генерації адрес, моніторингу та обробки платежів. Frontend для управління рахунками (створення, перегляд, відправка PDF).
  3. Інтеграція з CRM/бухгалтерією: REST API або webhook для синхронізації оплат, експорт даних.
  4. Розгортання та оптимізація: налаштування інфраструктури (сервер, RPC-ноди, моніторинг Alchemy).
  5. Документація та навчання: API-документація, інструкції для клієнта, навчання команди за потреби.
  6. Підтримка після запуску: гарантія 3 місяці на доопрацювання за специфікацією.

Порівняння методів сповіщень

Канал Швидкість доставки Надійність Вартість
Email 1-5 хв Середня (спам-фільтри) Низька
Telegram Bot 1-10 сек Висока Безкоштовно
Email + Telegram 1-5 хв/1-10 сек Дуже висока Низька +0

Рекомендуємо гібридну схему: email для юридичних сповіщень, Telegram для оперативних оповіщень.

Терміни розробки

Базова система з мультивалютним білінгом (Ethereum, USDC, USDT), автоматичним matching та email-нагадуваннями займає від 2 до 3 тижнів. Додавання додаткових блокчейнів (Polygon, Arbitrum, Solana) збільшує термін на 1–2 тижні кожен. Для точної оцінки зв'яжіться з нами — ми проаналізуємо вашу специфікацію та запропонуємо реалістичний план.

Зв'яжіться з нами для детальної консультації по вашому проєкту. Ми оцінимо вимоги та підберемо оптимальне рішення.

Замовте розробку системи криптобілінгу під ваш бізнес — від прототипу до повноцінного впровадження.

Напрямки блокчейн-розробки

Останні роботи

  • Розробка сайту компанії B2B ADVANCE
    Розробка сайту компанії B2B ADVANCE
    1542
  • Розробка веб-додатків для компанії FEEDME
    Розробка веб-додатків для компанії FEEDME
    1394
  • Розробка веб-сайту для компанії БЕЛФІНГРУП
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    1081
  • Розробка інтернет магазину для компанії FURNORO
    Розробка інтернет магазину для компанії FURNORO
    1369
  • Розробка логотипу компанії B2B Advance
    Розробка логотипу компанії B2B Advance
    816
  • Розробка веб-додатків для компанії Enviok
    Розробка веб-додатків для компанії Enviok
    1142