# Bank Pay-In

Take a user from zero to money in: bank ramp onboarding (KYC), then a virtual IBAN for bank transfers.

## Overview

The bank ramp handles KYC and the banking rails; Aurea runs the bank ramp for your tenant. A user onboards once, then gets a **virtual IBAN** (Step 4): they send SEPA transfers whenever they like, and the bank ramp converts each transfer to crypto and sends it on-chain to the address you chose.

The bank ramp takes bank transfers only (its card checkout, `POST /v1/ramp/bank/payin/checkout`, answers `403`). To let users pay by card, use the [card onramp](https://docs.aureahub.com/docs/guide-card-onramp.md).

## Before You Start

- Aurea has connected the bank ramp for your tenant and switched on KYC and pay-in in the environment you use — [Bank Ramp Setup](https://docs.aureahub.com/docs/bank-setup.md). Read [Tenant Settings](https://docs.aureahub.com/docs/bank-settings.md) to know what to show.
- Choose the environment on every request: `isTestnet: true` (or a sandbox network) uses the bank ramp's sandbox and the user's sandbox profile. A user has a separate profile, with its own KYC, IBANs and history, in each environment, so pass the same `isTestnet` on the reads too. The examples below are production.

## Step 1: Onboarding Status

```typescript
const status = await fetch('https://api.aureahub.com/v1/ramp/bank/payin/onboarding-status', {
  headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json());

// onboardingStatus: not_started | pending | in_progress | completed | failed
// kycStatus:        not_started | pending | approved | rejected
if (status.canInitiateDeposit) goToStep4();
```

## Step 2: Onboarding Session

`returnUrl` is given to the bank ramp as-is, so it must be an `https://` URL, and one your tenant allows ([Bank Ramp Setup](https://docs.aureahub.com/docs/bank-setup.md)).

```typescript
const session = await fetch('https://api.aureahub.com/v1/ramp/bank/payin/onboard-session', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ returnUrl: 'https://app.example.com/kyc/done', isTestnet: false })
}).then(r => r.json());

if (session.alreadyCompleted) goToStep4();
else await InAppBrowser.open(session.onboardingUrl);
```

## Step 3: Sync After Return

On your `returnUrl`, pull the result from the bank ramp instead of waiting for the webhook. Send the same `isTestnet` as the onboarding session.

**A status that has not moved is a failure, not a reason to start again.** When both statuses still read `not_started` after the user came back, the bank ramp did not create the customer at all: the user was turned away on the hosted page, and nothing tells them apart from someone who never opened the link ([When the Bank Ramp Says No](https://docs.aureahub.com/docs/payin-session.md)). Count the attempts on your side and stop after the second — a third link leads to the same wall.

```typescript
const synced = await fetch('https://api.aureahub.com/v1/ramp/bank/payin/sync-status', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ isTestnet: false })
}).then(r => r.json());

if (synced.canInitiateDeposit) goToStep4();
else if (synced.kycStatus === 'rejected') showKycRejected();
else if (synced.onboardingStatus === 'not_started' && synced.kycStatus === 'not_started') {
  // No customer yet: the hosted page produced nothing. Do not re-offer for ever.
  const attempts = countKycAttempt(userId);  // your own storage, not Aurea's
  if (attempts >= 2) showKycUnavailable();   // offer a person, not the same button
  else offerKycOnceMore();
}
else showKycInReview(); // Aurea is updated when the review ends
```

## Step 4: Virtual IBAN

No amount is involved. `network` selects sandbox or production, so set it explicitly; in production the pay-in pairs today are `EURC` on `Base` and `Solana`; `USDC` on `Base`, `Celo`, `Ethereum`, `PolygonPos` and `Solana`; `USDT` on `Celo` and `Ethereum`; and `PYUSD`, `USDG` and `USDPT` on `Solana` ([Currencies & Networks](https://docs.aureahub.com/docs/bank-currencies.md) has the current list, and your tenant may offer fewer). On an EVM network `destinationAddress` is required; on a Solana network it can be omitted, and the user's Solana wallet of that environment receives the funds. The funds can only go to one of the user's Aurea wallets — or, with the standalone mode, to an address the user proved they own ([Standalone Pay-In](https://docs.aureahub.com/docs/guide-standalone-payin.md)).

```typescript
const iban = await fetch('https://api.aureahub.com/v1/ramp/bank/payin/initiate', {
  method: 'POST',
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', 'Idempotency-Key': ibanRequestKey },
  body: JSON.stringify({ cryptoCurrency: 'EURC', network: 'Solana' }) // the user's Solana wallet receives the funds
}).then(r => r.json());

// Show iban.iban, iban.bic, iban.accountHolderName, iban.bankName.
// Refresh by calling /initiate again after iban.expiresAt.
```

## Step 5: Follow the Money

Read the results, or let Aurea post each change to your server ([Events to Your Server](https://docs.aureahub.com/docs/guide-events.md)):

- Bank transfers to a virtual IBAN: [Get Deposits](https://docs.aureahub.com/docs/payin-deposits.md) — `pending` until the bank ramp settles them, then `completed` (the user also gets a push notification). A deposit the bank ramp reviews shows why in `noahSubStatus` and `requestForInformation`; a rejected one is `failed` with its `refunds`.
- The conversion and the on-chain delivery of each transfer, both with the deposit that paid for them: [List Customer Transactions](https://docs.aureahub.com/docs/payin-transactions.md). The bank ramp transactions also appear in the [Unified Feed](https://docs.aureahub.com/docs/agg-tx-list.md).

```typescript
const { deposits } = await fetch('https://api.aureahub.com/v1/ramp/bank/payin/deposits?limit=20', {
  headers: { Authorization: `Bearer ${token}` }
}).then(r => r.json());
```

---

Web version: https://docs.aureahub.com/#guide-fiat-payin
