Настройка покупки криптовалюты через банковский перевод
Банковский перевод — самый дешёвый и наиболее распространённый среди крупных покупок on-ramp метод. Комиссии ниже карточных (0–1% vs 2–4%), лимиты значительно выше ($100K+ vs $10K). Главный минус — время: SEPA занимает 1 рабочий день, SWIFT — 2–5 дней, ACH — 1–3 дня.
Типы банковских переводов
SEPA Credit Transfer — Европа, EUR, стандарт 1 рабочий день. SEPA Instant Credit Transfer — до 10 секунд, 24/7, но не все банки поддерживают.
SWIFT — международные переводы, 2–5 дней, высокие fees ($15–50 за перевод со стороны отправителя).
ACH (Automated Clearing House) — США, USD, 1–3 рабочих дня. ACH Same Day — 1 рабочий день.
Faster Payments — UK, GBP, мгновенно, 24/7, лимит £1M.
Open Banking — ЕС/UK, прямое подключение к банку пользователя через PSD2, мгновенные переводы без ручного ввода реквизитов.
Архитектура приёма банковских переводов
class BankTransferDepositService:
async def create_deposit_order(
self,
user: User,
amount: Decimal,
currency: str,
crypto_currency: str,
) -> DepositOrder:
# Генерируем уникальный reference для идентификации платежа
reference = self.generate_reference(user.id)
# Сохраняем ожидаемый платёж
order = await self.db.create_pending_deposit(
user_id=user.id,
reference=reference,
expected_amount=amount,
currency=currency,
crypto_currency=crypto_currency,
expires_at=datetime.now() + timedelta(hours=24),
)
# Возвращаем банковские реквизиты для перевода
return DepositOrder(
order_id=order.id,
bank_name="Modulr Finance",
account_name="Platform Name Ltd",
iban="GB29NWBK60161331926819",
bic="NWBKGB2L",
reference=reference, # ВАЖНО: пользователь должен указать в назначении
amount=amount,
currency=currency,
expires_at=order.expires_at,
)
def generate_reference(self, user_id: int) -> str:
"""Уникальный reference для матчинга входящих платежей"""
import random, string
code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
return f"DEP{user_id:06d}{code}"
Open Banking интеграция (TrueLayer)
Open Banking позволяет пользователю авторизовать платёж прямо из своего банка, без ручного ввода реквизитов и задержки SEPA:
import httpx
class TrueLayerClient:
BASE_URL = "https://payment.truelayer.com"
def __init__(self, client_id: str, client_secret: str):
self.client_id = client_id
self.client_secret = client_secret
async def create_payment(
self,
amount_in_minor: int, # в пенсах/центах
currency: str,
beneficiary_name: str,
beneficiary_iban: str,
reference: str,
user_email: str,
) -> dict:
token = await self.get_access_token()
resp = await httpx.AsyncClient().post(
f"{self.BASE_URL}/v3/payments",
headers={"Authorization": f"Bearer {token}"},
json={
"amount_in_minor": amount_in_minor,
"currency": currency,
"payment_method": {
"type": "bank_transfer",
"provider_filter": {"countries": ["GB", "DE", "FR", "NL"]},
"beneficiary": {
"type": "merchant_account",
"account_holder_name": beneficiary_name,
"account_identifier": {
"type": "iban",
"iban": beneficiary_iban,
}
}
},
"user": {"email": user_email},
"metadata": {"reference": reference},
}
)
data = resp.json()
return {
"payment_id": data["id"],
"redirect_url": data["authorization_flow"]["actions"][0]["uri"]
}
Пользователь получает redirect на страницу своего банка для подтверждения. После подтверждения — деньги поступают мгновенно.
Матчинг входящих платежей
Главная сложность банковских переводов — правильная идентификация отправителя. Система получает уведомления о входящих платежах от Banking-as-a-Service провайдера (Modulr, ClearBank, Railsr) через webhook:
@app.post("/webhooks/banking/incoming")
async def incoming_payment_webhook(request: Request):
data = await request.json()
payment = data["payment"]
# Извлекаем reference из назначения платежа
reference = extract_reference(payment["remittance_information"])
if not reference:
# Платёж без reference — требует ручной обработки
await flag_for_manual_review(payment)
return
# Ищем ожидаемый депозит по reference
pending_order = await db.find_pending_deposit(reference=reference)
if not pending_order:
await flag_for_manual_review(payment)
return
# Проверяем сумму
if abs(payment["amount"] - float(pending_order.expected_amount)) > 0.01:
# Сумма не совпадает — возможно частичный платёж или ошибка
await flag_for_manual_review(payment, pending_order.id)
return
# Конвертируем и зачисляем крипто
await process_confirmed_deposit(pending_order.id, payment)
def extract_reference(remittance_info: str) -> str | None:
"""Извлекает наш reference из текста назначения платежа"""
import re
match = re.search(r'DEP\d{6}[A-Z0-9]{8}', remittance_info)
return match.group(0) if match else None
Возврат неидентифицированных платежей
Обязательный процесс: если входящий платёж не удалось сопоставить с депозитом в течение 24–48 часов, он возвращается отправителю через reverse transfer. Хранение чужих средств без идентификации — регуляторное нарушение.
Курс на момент получения
В отличие от карточных платежей, при банковских переводах есть задержка 1–3 дня. За это время курс может значительно измениться. Два подхода:
Курс фиксируется в момент создания заявки — пользователь видит сколько крипто получит. Риск несёт платформа. Нужно хеджировать через форвардный контракт или немедленную покупку крипто после получения фиата.
Курс рассчитывается в момент получения — пользователь получает крипто по актуальному курсу. Меньше риска для платформы, хуже UX.
Большинство платформ использует второй подход для банковских переводов и явно сообщает об этом пользователю.







