Разработка White-label платёжного шлюза
White-label шлюз — это не просто "платёжный шлюз с чужим логотипом". Это полноценная платёжная платформа, которую клиент продаёт под своим брендом своим клиентам. Это меняет всю архитектуру: нужна мультиарендность, изоляция данных между мерчантами, API для партнёрской интеграции, биллинг по использованию, white-label UI kit.
Архитектурные уровни
┌─────────────────────────────────────────────────────┐
│ White-label клиент (Tenant) │
│ Собственный домен, логотип, цвета │
├─────────────────────────────────────────────────────┤
│ Merchant Layer │
│ Мерчанты создают платёжные ссылки, API ключи │
├─────────────────────────────────────────────────────┤
│ Core Gateway Engine │
│ Мультисеть, мониторинг, подтверждения, webhook │
├─────────────────────────────────────────────────────┤
│ Blockchain Infrastructure │
│ Ноды / RPC провайдеры по каждой сети │
└─────────────────────────────────────────────────────┘
Каждый tenant имеет: отдельный домен (или поддомен), брандированный checkout UI, изолированные HD wallet деривации, отдельный биллинг.
Мультиарендность и изоляция
Стратегия деривации адресов
Каждый tenant получает собственный master xpub, из которого деривируются адреса его мерчантов и их заказов. Структура пути деривации:
m / purpose' / coin_type' / tenant_id' / merchant_id / order_index
Пример для EVM-сетей:
import { HDNodeWallet } from "ethers";
class TenantWalletManager {
private masterNode: HDNodeWallet;
constructor(masterMnemonic: string) {
this.masterNode = HDNodeWallet.fromPhrase(masterMnemonic);
}
getTenantXpub(tenantId: number): string {
// Деривируем на уровне tenant — отдаём xpub, не приватный ключ
return this.masterNode
.deriveChild(44 + 0x80000000) // purpose 44'
.deriveChild(60 + 0x80000000) // ETH coin_type 60'
.deriveChild(tenantId + 0x80000000) // tenant (hardened)
.neuter()
.extendedKey; // публичный xpub
}
getDepositAddress(tenantXpub: string, merchantId: number, orderIndex: number): string {
const tenantNode = HDNodeWallet.fromExtendedKey(tenantXpub);
return tenantNode
.deriveChild(merchantId)
.deriveChild(orderIndex)
.address;
}
}
Это позволяет tenant'у самостоятельно верифицировать адреса (у него есть свой xpub), но не получить контроль над мастер-ключами.
Изоляция данных в PostgreSQL
Схема с row-level security вместо отдельных баз данных (проще в операциях):
-- RLS политики для изоляции тенантов
ALTER TABLE payments ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON payments
USING (tenant_id = current_setting('app.tenant_id')::uuid);
-- В каждом запросе выставляем контекст
SET LOCAL app.tenant_id = '...';
Для высоконагруженных платформ (100+ тенантов с большим объёмом) — отдельная PostgreSQL схема на тенант через search_path.
API для мерчантов
Мерчанты интегрируются через REST API, аналогично Stripe/PayPal. Аутентификация через API ключи (публичный + секретный):
// Создание платёжного инвойса
// POST /api/v1/invoices
{
"amount": "99.99",
"currency": "USD",
"accepted_coins": ["ETH", "USDT_ERC20", "BTC"],
"order_id": "order_123", // ваш внутренний ID
"customer_email": "[email protected]",
"success_url": "https://shop.example.com/success",
"cancel_url": "https://shop.example.com/cancel",
"metadata": { "product_id": "456" },
"expires_in": 900 // секунды (15 минут)
}
// Ответ
{
"invoice_id": "inv_abc123",
"checkout_url": "https://pay.whitelabel.com/i/inv_abc123",
"status": "pending",
"expires_at": "2024-01-15T10:45:00Z",
"payment_options": [
{
"coin": "ETH",
"address": "0x...",
"amount": "0.02941",
"rate": "3400.00",
"rate_expires_at": "2024-01-15T10:45:00Z"
}
]
}
Webhook система
Вебхуки должны быть надёжными — retry логика, подписи, дедупликация:
interface WebhookEvent {
id: string; // уникальный ID события
type: "payment.confirmed" | "payment.failed" | "payment.expired";
created_at: string;
data: {
invoice_id: string;
amount_paid: string;
currency_paid: string;
txhash: string;
confirmations: number;
};
}
// Подпись: HMAC-SHA256(webhookSecret, `${timestamp}.${JSON.stringify(payload)}`)
// Заголовок: X-Signature: t=1705312200,v1=abcdef...
Retry schedule при неуспешной доставке: 1мин → 5мин → 30мин → 2ч → 8ч → 24ч. После 6 неудачных попыток — помечаем как failed, dashboard мерчанта показывает failed webhooks с возможностью ручного retry.
Checkout UI как white-label компонент
Фронтенд должен поддерживать полную кастомизацию под бренд тенанта:
// Конфигурация тенанта из БД
interface TenantTheme {
primaryColor: string;
logoUrl: string;
fontFamily: string;
borderRadius: "none" | "sm" | "md" | "lg" | "full";
darkMode: boolean;
}
// Next.js приложение с динамическим CSS
// При загрузке checkout страницы — запрос темы тенанта
// CSS variables инжектируются в <head>
const theme = await getTenantTheme(tenantId);
const css = `
:root {
--color-primary: ${theme.primaryColor};
--border-radius: ${borderRadiusMap[theme.borderRadius]};
--font-family: ${theme.fontFamily};
}
`;
Компоненты: выбор монеты → QR-код с адресом → countdown таймер → статус подтверждений → success/fail экран.
Custom domain: каждый тенант может подключить свой домен (pay.theirclient.com). Реализуется через Cloudflare для бизнеса (Cloudflare for SaaS) или nginx с автоматическим Let's Encrypt через Caddy.
Биллинг тенантов
Модели монетизации:
| Модель | Реализация |
|---|---|
| Процент от объёма | Удержание X% при sweep на hot wallet |
| Фиксированная плата за транзакцию | Добавляем fee к сумме инвойса или вычитаем при sweep |
| Subscription | Ежемесячный платёж, доступ к API |
| Комбинированная | Subscription + reduced transaction fee |
Sweep with fee deduction:
async function sweepWithFee(depositAddress: string, amount: bigint, tenantId: string) {
const tenant = await getTenant(tenantId);
const feeRate = tenant.feeRate; // например 0.01 = 1%
const fee = amount * BigInt(Math.floor(feeRate * 10000)) / 10000n;
await sendTransaction(PLATFORM_FEE_WALLET, fee);
await sendTransaction(tenant.hotWallet, amount - fee);
}
Безопасность и compliance
API Key management: генерация через crypto.randomBytes(32).toString('hex'), хранение только хешированного значения в БД (sha256), показываем один раз при создании.
Rate limiting: отдельные лимиты на каждый API ключ, возможность настройки тенантом через dashboard. Redis + sliding window алгоритм.
IP whitelist: мерчанты могут ограничить API ключ конкретными IP. Обязательно для production интеграций.
Audit log: все административные действия тенанта (создание/отзыв ключей, изменение настроек, запросы на вывод) логируются в immutable таблицу.
AML: опциональная интеграция с Chainalysis или Elliptic для проверки адресов отправителей по санкционным спискам. Актуально если платформа работает в регулируемых юрисдикциях.
Инфраструктура
Load Balancer (nginx/Caddy)
├── API Gateway (Node.js/Fastify)
├── Checkout Frontend (Next.js)
└── Admin Dashboard (Next.js)
Background Services
├── Block Monitor Workers (по одному на сеть)
├── Confirmation Tracker
├── Sweep Worker
├── Webhook Delivery Worker
└── Rate Sync Worker (цены)
Data Layer
├── PostgreSQL (primary + read replicas)
├── Redis (caches, queues, rate limits)
└── S3-compatible (логи, экспорты)
Сроки разработки
| Компонент | Срок |
|---|---|
| Core gateway engine (мониторинг, подтверждения, sweep) | 1–2 нед |
| Merchant API + webhook система | 1 нед |
| Checkout UI с white-label темизацией | 1 нед |
| Tenant management + биллинг | 1 нед |
| Admin dashboard для тенантов | 1–2 нед |
| Custom domain + SSL автоматизация | 3–5 дней |
| Тестирование, security review, hardening | 1–2 нед |
Минимальный срок от нуля до production-ready MVP: 6–8 недель. С поддержкой 5–6 сетей, брандированным checkout, webhook системой и базовым dashboard. Полноценная платформа с enterprise фичами — 3 месяца.







