# Bank Ramp: Setup & Customers

> Coming soon, upon request — this feature is turned on for your tenant by the Aurea team. [Contact us](https://www.aureahub.com/contact)

The bank ramp turns bank transfers into stablecoins and back for your users [Coming soon, upon request](https://docs.aureahub.com/docs/feature-availability.md). This page sets it up for your tenant and makes your users its customers, with their KYC; [Pay-In](https://docs.aureahub.com/docs/guide-fiat-payin.md) and [Payout](https://docs.aureahub.com/docs/guide-fiat-payout.md) move the money.

## Overview

- **An Aurea service.** Your apps call Aurea's API with the user's access token; there is no other account, key or dashboard to manage.
- **Per environment.** The sandbox (`isTestnet: true`) and production each have their own settings, their own KYC for each user and their own webhook. Start in the sandbox ([Environments & Test Data](https://docs.aureahub.com/docs/guide-environments.md)): a user approved there onboards again in production.
- **Read what your tenant offers** before building a screen: [What Your Tenant Offers](https://docs.aureahub.com/docs/bank-settings.md) (`GET /v1/ramp/bank/settings`) answers whether the bank ramp is on (`switchedOn`), its functions and modes, the pairs and the fees, from Aurea's records only — call it whenever your app builds its menu.

Local currencies through local banks and mobile money, and the desk's currencies, have pages of their own: [Local Rails](https://docs.aureahub.com/docs/guide-bank-local.md) and [Desk Orders](https://docs.aureahub.com/docs/guide-bank-desk.md).

## What Aurea Sets Up

Ask your Aurea contact, for the sandbox first and then for production, to:

1. **Connect the bank ramp** for your tenant. Until then, its routes answer `503` `BANK_RAMP_NOT_CONFIGURED` and nothing is sent anywhere. Once connected, every change to a user's KYC, deposits, transactions and payouts reaches Aurea with nothing to do on your side.
2. **Switch on the functions** you offer: KYC, pay-in, payout. A request for a function that is off answers `403` `BANK_RAMP_FUNCTION_OFF`.
3. **Choose where pay-ins go**: to the user's Aurea wallets (the *Aurea wallets* mode), to addresses outside Aurea that the user proved they own (the *standalone* mode), or both. Asking for a proof while the standalone mode is off answers `403` `BANK_RAMP_MODE_OFF`; a pay-in to an address the modes do not allow, `400` `BANK_RAMP_DESTINATION_NOT_ALLOWED`.
4. **Choose the pairs** — currency and network — offered for pay-in and for payout. Another pair answers `400` `BANK_RAMP_PAIR_UNAVAILABLE` with the pairs offered.
5. **Set your fee**, if you charge one: a business fee per flow (pay-in, payout) and bank payment method type. The pay-in fee is taken from each deposit; the payout fee shows in each payout quote's breakdown.
6. **Register your return URLs** — where the hosted onboarding page sends the user back. It returns straight to your URL, so it must be an `https://` page (`400` `RETURN_URL_NOT_HTTPS`). Once your tenant has any return URL, any other answers `400` `RETURN_URL_NOT_ALLOWED`; a tenant with none yet is not checked.

## What You Set Up

- **Your webhook endpoints**, if your server should hear about each change without asking: the `ramp.*` events ([Webhooks & Events](https://docs.aureahub.com/docs/guide-events.md)).
- **Your screens**, from what your tenant offers (What Your Tenant Offers): show only what will work.

## Two Ways to Onboard

A user onboards once per environment, in one of two ways — which one serves your users is agreed for your tenant when the bank ramp is set up:

- **The hosted onboarding**: your app opens the bank ramp's KYC page and reads the result — [Pay-In](https://docs.aureahub.com/docs/guide-fiat-payin.md), steps 1 to 3 ([Onboarding Session](https://docs.aureahub.com/docs/payin-session.md), [Onboarding Status](https://docs.aureahub.com/docs/payin-status.md), [Sync KYC Status](https://docs.aureahub.com/docs/payin-sync-status.md)). It uses the settings above.
- **The customer routes** (`/v1/ramp/bank/customer…`) [Coming soon, upon request](https://docs.aureahub.com/docs/feature-availability.md): the user becomes a customer — a person or a company — with your app sending the KYC data or the bank ramp's own pages taking it, and your app links the addresses the bank ramp pays to and takes from. They have settings of their own (below), and do not open an IBAN or move money.

For the customer routes:

- Called with the user's access token. **One customer per user and environment**, each with its own settings and documents.
- **Aurea keeps nothing of the KYC data** your app sends — no name, no address, no document's content — and writes none of it to its logs: only the customer's states, the names of refused fields, and each document's id, type, size and SHA-256. A body that does not pass is refused with the names of the fields, never their values.
- They send no event to your server: read the customer ([Get the Customer](https://docs.aureahub.com/docs/bank-customer-get.md)) when your app needs its state.

## The Customer Routes' Settings

Aurea sets them up with your tenant, environment by environment. What is set, and what a request answers without it:

| Setting | Values | Without it |
| --- | --- | --- |
| Connection | Your tenant's bank ramp application in the environment, and — for the hosted pages — its sign-in client and the redirect URIs it accepts | `503` `BANK_RAMP_NOT_CONFIGURED`, nothing sent or kept |
| KYC | On or off | `403` `BANK_RAMP_FUNCTION_OFF` (`details.function` `kyc`) on every route that onboards or sends data |
| KYC strategy | `reliance`, `identity_sharing` or `hosted_oauth` (below) | `403` `BANK_RAMP_KYC_STRATEGY_OFF` on the routes of another strategy, with your strategy in `details.kycStrategy` |
| Customer kinds | `personal`, `corporate`, or both | `400` `BANK_RAMP_PROFILE_KIND_UNAVAILABLE`, with `details.available` |
| Aurea wallets mode | On or off: the user's Aurea wallets can be linked | `403` `BANK_RAMP_MODE_OFF` (`details.mode` `aureaWallets`) |
| Standalone mode | On or off: addresses outside Aurea can be proven and linked | `403` `BANK_RAMP_MODE_OFF` (`details.mode` `standalone`) |
| Networks | Any of `ethereum`, `gnosis`, `polygon`, `arbitrum`, `base` — in the sandbox, each chain's test network | `400` `BANK_RAMP_PAIR_UNAVAILABLE`, with `details.available` |

- **Reads always answer**: a user's customer, documents, wallet links, addresses and hosted authorization are answered whatever the settings, so a user always sees what they have. Only [Get the Customer](https://docs.aureahub.com/docs/bank-customer-get.md) for a user with no customer needs the KYC on.
- Your app learns your strategy from `verification.kycStrategy` in every customer answer (`null` while the KYC is off). [What Your Tenant Offers](https://docs.aureahub.com/docs/bank-settings.md) (`GET /v1/ramp/bank/settings`) describes the hosted onboarding's settings, not these.
- A switch-off applies from the next request.

## KYC Strategies

| Strategy | Your app sends | Routes |
| --- | --- | --- |
| `reliance` | Your tenant runs its own KYC (a bank, for example) and sends the result: the details, the risk form, every verification and its documents. | [Create a Customer](https://docs.aureahub.com/docs/bank-customer-create.md), [Upload a Document](https://docs.aureahub.com/docs/bank-customer-file-upload.md), [Send Details](https://docs.aureahub.com/docs/bank-customer-details.md), [Send the Risk Form](https://docs.aureahub.com/docs/bank-customer-form.md), [Send Verifications](https://docs.aureahub.com/docs/bank-customer-verifications.md) |
| `identity_sharing` | Your tenant verifies its users with its own KYC vendor account and shares the applicant (a person only), then sends the risk form and the `sourceOfFunds` verification with its documents. | Create a Customer, [Share a KYC Applicant](https://docs.aureahub.com/docs/bank-customer-share.md), Upload a Document, Send the Risk Form, Send Verifications (`sourceOfFunds` only) |
| `hosted_oauth` | Nothing: the user signs up and completes the KYC on the bank ramp's own pages, and lets your tenant's application act for them. | [Start Hosted Onboarding](https://docs.aureahub.com/docs/bank-customer-authorize.md), [Complete Hosted Onboarding](https://docs.aureahub.com/docs/bank-customer-authorize-complete.md), [Sync the Customer](https://docs.aureahub.com/docs/bank-customer-sync.md) |

## Customer States

```text
forward:  created → incomplete → pending → review → approved or rejected
back:     pending → incomplete;  review → pending or incomplete
closing:  any state but closed → closed;  rejected → closed only;  closed is final
```

- **`state`** is the bank ramp's: `created` (nothing sent yet), `incomplete` (a section needs data), `pending` (everything sent, in review), `review` (held for a manual review), `approved`, `rejected` (final) and `closed` (with `closedReason`). Unlike most states in Aurea, it can go back — but only along the moves the bank ramp documents. A move outside them is kept out, and the customer keeps its state.
- **`verification.nextStep`** tells your app what to do: `start_onboarding`, `continue_onboarding` (send what `missing` names), `wait_for_review`, `approved`, `rejected`, `closed`.
- **`errorFields`** names the fields the bank ramp's review refused: correct them and send the section again.
- The bank ramp's changes reach Aurea by its notifications, and the newest wins: a late notification of an older change changes nothing. [Sync the Customer](https://docs.aureahub.com/docs/bank-customer-sync.md) reads the customer now.

## Your App Sends the Data

With `reliance` or `identity_sharing`:

1. **Create the customer** with its kind ([Create a Customer](https://docs.aureahub.com/docs/bank-customer-create.md)). Safe to repeat: the customer's id is Aurea's, and a call that stopped half way is finished by the next.
2. **Upload the documents** the verifications need, one file each — PDF or JPEG, at most 5 MB ([Upload a Document](https://docs.aureahub.com/docs/bank-customer-file-upload.md)).
3. **Send the sections**: with `reliance` the details, the risk form and the verifications; with `identity_sharing` the shared applicant, the risk form and the `sourceOfFunds` verification. Each answers `202`: the bank ramp received it and reviews it in its own time.
4. **Read the customer** until `nextStep` is `approved` — `continue_onboarding` with `missing` and `errorFields` says what to send again.

```javascript
const API = 'https://api.aureahub.com/v1/ramp/bank/customer';
const headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` };
const send = (method, path, body) =>
  fetch(API + path, { method, headers, body: JSON.stringify({ isTestnet: true, ...body }) })
    .then(async (r) => (r.ok ? r.json() : Promise.reject(await r.json())));

// reliance, a person (the documents uploaded first: frontId, backId, proofId)
await send('POST', '', { kind: 'personal' });
await send('PATCH', '/details', { personal: details });     // firstName … email, idDocument
await send('PATCH', '/form', { personal: riskForm });       // occupation … taxResidenceCountry
await send('PATCH', '/verifications', {
  personal: [
    { kind: 'idDocument', documents: [{ fileId: frontId, side: 'front' }, { fileId: backId, side: 'back' }] },
    { kind: 'proofOfResidency', documents: [{ fileId: proofId, kind: 'proofOfResidency' }] }
  ]
});

const { verification } = await fetch(API + '?isTestnet=true', { headers }).then((r) => r.json());
// verification.nextStep: wait_for_review … approved
```

## The Bank Ramp's Pages

With `hosted_oauth`:

1. [Start Hosted Onboarding](https://docs.aureahub.com/docs/bank-customer-authorize.md) answers a link to the bank ramp's pages for the user, with a `redirectUri` registered for your tenant.
2. The user signs up, completes the KYC and lets your tenant's application act for them; the bank ramp sends them back to `redirectUri` with `code` and `state`.
3. [Complete Hosted Onboarding](https://docs.aureahub.com/docs/bank-customer-authorize-complete.md) makes the user's profile your tenant's customer. Aurea keeps the user's authorization, encrypted.
4. **There are no notifications in this mode**: [Sync the Customer](https://docs.aureahub.com/docs/bank-customer-sync.md) reads the customer with the user's authorization. When the bank ramp ends it — `409` `BANK_RAMP_AUTHORIZATION_EXPIRED`, or `lastError` in [Hosted Authorization](https://docs.aureahub.com/docs/bank-customer-authorization.md) — the user authorizes again. [Forget the Authorization](https://docs.aureahub.com/docs/bank-customer-authorization-forget.md) wipes it.

## Wallets and Addresses

The bank ramp pays to and takes from an address on a chain only once the address signed its fixed message for the customer.

- **The user's Aurea wallets** (Aurea wallets mode): [Link a Wallet](https://docs.aureahub.com/docs/bank-customer-wallet-link.md). Aurea signs for a custodial wallet; a client-side or MPC wallet signs the message (or its digest) on the device and sends it with [Send a Link Signature](https://docs.aureahub.com/docs/bank-customer-wallet-signature.md). A watch-only wallet cannot be linked, and a contract wallet is proven as an address.
- **Addresses outside Aurea** (standalone mode): [Ask for a Challenge](https://docs.aureahub.com/docs/bank-customer-address-challenge.md), then [Prove and Link an Address](https://docs.aureahub.com/docs/bank-customer-address-verify.md) with two signatures — Aurea's challenge and the bank ramp's message. An account signs both; a smart account signs with ERC-1271, or the bank ramp's message on chain. [Stop Using an Address](https://docs.aureahub.com/docs/bank-customer-address-revoke.md) revokes it in Aurea.
- One live link per customer, address and chain. [List Wallet Links](https://docs.aureahub.com/docs/bank-customer-wallets.md) and [List Addresses](https://docs.aureahub.com/docs/bank-customer-addresses.md) answer what is linked.
- These are not the proven addresses of the hosted flow ([Pay-In › To an Address the User Owns](https://docs.aureahub.com/docs/guide-fiat-payin.md)): a proof made there is not a link here, and the other way round.

## Refusals

Every refusal carries its code in `details.code`. The bank ramp's own answers have `"error": "BankRampProviderError"`, `details.providerStatus` when it answered, and never its own words.

| details.code | Status | Meaning |
| --- | --- | --- |
| BANK_RAMP_FUNCTION_OFF | 403 | Your tenant's KYC is off in that environment. |
| BANK_RAMP_KYC_STRATEGY_OFF | 403 | Your tenant's KYC strategy does not go this way (`details.kycStrategy`). |
| BANK_RAMP_MODE_OFF | 403 | The Aurea wallets or standalone mode is off (`details.mode`). |
| BANK_RAMP_PROFILE_KIND_UNAVAILABLE | 400 | A kind of customer your tenant does not offer. |
| BANK_RAMP_PAIR_UNAVAILABLE | 400 | A network your tenant does not offer. |
| BANK_RAMP_NOT_CONFIGURED | 503 | Aurea has not connected your tenant's bank ramp in that environment (or its hosted pages). |
| BANK_RAMP_CUSTOMER_NOT_FOUND | 404 | The user is no customer the bank ramp confirmed in that environment. |
| BANK_RAMP_CUSTOMER_KIND_MISMATCH | 409 | The user is a customer of the other kind, or a company sent to Share a KYC Applicant. |
| BANK_RAMP_CUSTOMER_EXISTS | 409 | Hosted onboarding: the user is another customer, or the profile is another user's. |
| BANK_RAMP_KYC_DATA_INVALID | 400 | A KYC body that does not pass; `details.fields` names the fields. |
| BANK_RAMP_KYC_VERIFICATION_UNAVAILABLE | 400 | A verification kind your strategy does not send; `details.allowed`. |
| BANK_RAMP_KYC_FILE_INVALID | 400 | No file, or not a PDF or JPEG of at most 5 MB. |
| BANK_RAMP_KYC_FILE_UNKNOWN | 400 | A verification names a document not uploaded for this customer. |
| BANK_RAMP_REDIRECT_URI_INVALID | 400 | A redirect URI the bank ramp cannot send the user back to (`details.reason`). |
| BANK_RAMP_AUTHORIZATION_INVALID | 400 | A state or code that does not pass: start the hosted onboarding again. |
| BANK_RAMP_AUTHORIZATION_NO_PROFILE | 409 | The user has no profile at the bank ramp yet. |
| BANK_RAMP_AUTHORIZATION_EXPIRED | 409 | The bank ramp ended the user's authorization: the user authorizes again. |
| BANK_RAMP_AUTHORIZATION_NOT_FOUND | 404 | No authorization kept for the user in that environment. |
| BANK_RAMP_WALLET_NOT_FOUND | 404 | Not one of the user's wallets. |
| BANK_RAMP_WALLET_NOT_SIGNABLE | 409 | A wallet nobody can link (`details.reason`: `environment`, `chain`, `watch_only`, `contract`). |
| BANK_RAMP_LINK_NOT_FOUND | 404 | No such wallet link of the user. |
| BANK_RAMP_LINK_NOT_AWAITING_SIGNATURE | 409 | The link is not waiting for a signature. |
| BANK_RAMP_LINK_EXPIRED | 409 | The link's 15 minutes are over: link the wallet again. |
| BANK_RAMP_SIGNATURE_INVALID | 400 | A link signature that is not the wallet's. |
| BANK_RAMP_ADDRESS_INVALID | 400 | Not an EVM address, a wrong checksum, or the zero address. |
| BANK_RAMP_ADDRESS_CHALLENGE_LIMIT | 409 | Five open challenges already. |
| BANK_RAMP_ADDRESS_CHALLENGE_NOT_FOUND | 404 | No such challenge of the user. |
| BANK_RAMP_ADDRESS_CHALLENGE_SPENT | 409 | The challenge is used, expired or burnt (`details.reason`). |
| BANK_RAMP_ADDRESS_SIGNATURE_INVALID | 400 | A signature that is not the address's (`details.signature`: `challenge` or `link`). |
| BANK_RAMP_ADDRESS_UNVERIFIED | 503 | The chain's node did not answer a smart account's check: retry. |
| BANK_RAMP_ADDRESS_NOT_FOUND | 404 | The user holds no such address. |
| BANK_RAMP_ADDRESS_IN_USE | 409 | The address is in use (`details.reason`: `iban` or `orders`). |
| BANK_RAMP_LINK_NOT_SIGNED | — | In `failureCode`: the bank ramp stopped waiting for a smart account's on-chain signature. |
| BANK_RAMP_INVALID_REQUEST | 400 | The bank ramp refused the request's fields (`details.fields` when it names them). |
| BANK_RAMP_FORBIDDEN, BANK_RAMP_PARTNER_REQUIRED | 403 | The bank ramp refused the operation to your tenant's application; the second, until the bank ramp allows it for your tenant. |
| BANK_RAMP_NOT_FOUND, BANK_RAMP_CONFLICT | 404, 409 | The bank ramp could not find it, or already has it (a section in review). |
| BANK_RAMP_AUTHENTICATION_FAILED, BANK_RAMP_UPSTREAM_ERROR, BANK_RAMP_UNEXPECTED_RESPONSE, BANK_RAMP_PROFILE_MISMATCH | 502 | The bank ramp refused Aurea's connection, failed, or answered something Aurea could not read. |
| BANK_RAMP_UNAVAILABLE, BANK_RAMP_RATE_LIMITED, BANK_RAMP_TIMEOUT, BANK_RAMP_UNREACHABLE | 503 | The bank ramp is unavailable, limiting requests (`details.retryAfterSeconds`), slow or unreachable: retry later. |

Create a Customer and Link a Wallet also take an `Idempotency-Key`, with the `IDEMPOTENCY_*` refusals of [Idempotency](https://docs.aureahub.com/docs/idempotency.md). A frozen tenant, user or wallet answers `423` before a link is signed ([Freezes & Quarantines](https://docs.aureahub.com/docs/guide-freezes.md)).

---

Web version: https://docs.aureahub.com/#guide-bank-customers
