Integrating Bank Transfer for Crypto Purchase – SEPA, SWIFT, Open Banking

Buying cryptocurrency via bank transfer is a challenge every on-ramp service faces when aiming for minimal fees and maximum limits. Mastercard/Visa cards charge 2–4%, while SEPA or SWIFT cost 0–1% – for volumes of $100K+ this translates into real savings. For example, on one of our platforms switchi

Blockchain Development Services

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1452
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1310
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    1005
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1270
  • image_logo-advance_0.webp
    B2B Advance company logo design
    719
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    1012

Buying cryptocurrency via bank transfer is a challenge every on-ramp service faces when aiming for minimal fees and maximum limits. Mastercard/Visa cards charge 2–4%, while SEPA or SWIFT cost 0–1% – for volumes of $100K+ this translates into real savings. For example, on one of our platforms switching from cards to SEPA cut commission costs by $40,000 per year on a $2M volume. On another project, savings reached $150,000 per year on a $5M volume. We have set up dozens of such integrations for crypto platforms: from provider selection (Modulr, ClearBank, Railsr) to full automation of payment matching.

Types of Bank Transfers

Type Region Time Fee (approx) Limits
SEPA Credit Transfer Europe (EUR) 1 business day 0–1% $100K+
SEPA Instant Europe (EUR) Up to 10 seconds 0–1% Bank-limited
SWIFT International 2–5 days $15–50 + spread $1M+
ACH USA (USD) 1–3 days 0–0.5% $100K+
Faster Payments UK (GBP) Instant 0% £1M
Open Banking EU/UK Instant 0–0.5% Bank-dependent

Why Bank Transfer is Cheaper than Card?

Fee comparison: card on-ramp charges 2–4%, bank transfer charges 0–1% – three times cheaper for large amounts. Limits: cards are usually capped at $10K per transaction, bank transfers at $100K and above. The downside is speed, but Open Banking addresses that. For large investors and institutional clients, bank transfers become the only option – cards cannot handle amounts from $500K.

Architecture of Accepting Bank Transfers

Example Deposit Service Implementation
class BankTransferDepositService: async def create_deposit_order( self, user: User, amount: Decimal, currency: str, crypto_currency: str, ) -> DepositOrder: 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: import random, string code = ''.join(random.choices(string.ascii_uppercase + string.digits, k=8)) return f"DEP{user_id:06d}{code}" 

What's Included in the Setup

  • Integration with a banking provider (Modulr, ClearBank, Railsr) via API
  • Generation of a unique reference and its display to the user
  • Webhook handler for incoming payments with reference matching
  • Automatic return of unidentified payments
  • Choice of rate protection strategy (fixation or calculation upon receipt)
  • Testing of the full cycle: order creation → transfer → crediting
  • Integration documentation and support during launch

Open Banking Integration (TrueLayer)

Open Banking allows the user to authorize a payment directly from their bank, without manual entry of details and SEPA delays. This removes the main barrier – speed. More about the protocol can be read on Wikipedia.

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"] } 

The user receives a redirect to their bank's page for confirmation. After confirmation – money arrives instantly.

How Does Incoming Payment Matching Work?

The main challenge of bank transfers is correctly identifying the sender. The system receives incoming payment notifications from the Banking-as-a-Service provider via webhook:

@app.post("/webhooks/banking/incoming") async def incoming_payment_webhook(request: Request): data = await request.json() payment = data["payment"] reference = extract_reference(payment["remittance_information"]) if not reference: await flag_for_manual_review(payment) return 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: import re match = re.search(r'DEP\d{6}[A-Z0-9]{8}', remittance_info) return match.group(0) if match else None 

How to Protect Against Exchange Rate Fluctuations?

Unlike card payments, bank transfers have a delay of 1–3 days. During that time the rate can change significantly. Two approaches:

Strategy Rate Platform Risk UX
Rate fixation at order creation Known immediately High (requires hedging) Good
Rate calculation upon receipt Unknown until crediting Low Medium
  • Rate is fixed at order creation – user sees how much crypto they'll receive. Platform bears risk. Requires hedging via forward contract or immediate crypto purchase upon fiat receipt.
  • Rate is calculated upon receipt – user gets crypto at the current rate. Lower platform risk, worse UX.

Most platforms use the second approach for bank transfers and clearly inform the user.

Return of Unidentified Payments

Mandatory process: if an incoming payment cannot be matched to a deposit within 24–48 hours, it is returned to the sender via reverse transfer. Holding unidentified funds is a regulatory violation.

How We Work

  1. Analysis – we study your platform, volumes, liquidity requirements.
  2. Design – choose a provider, define matching scheme and rate strategy.
  3. Implementation – write API integration with the bank, set up webhooks, automate returns.
  4. Testing – cover with unit tests, simulate deposits, test with a real bank.
  5. Deployment – phased rollout with monitoring and support.

Our engineers have 10+ years of experience in blockchain development and have successfully launched 50+ fiat on-ramp integrations. We guarantee quality and deadlines.

Contact us for a project evaluation – our team is ready to discuss details. Request a consultation, and we'll propose the optimal architecture for your crypto platform.