> ## Documentation Index
> Fetch the complete documentation index at: https://docs.privy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless bank deposits

> Integrate bank transfer onramps (ACH, wire, SEPA) directly with the Bridge API, without Privy modal UI

Your app can build bank transfer onramps directly against the Bridge API, without Privy's modal UI. This gives full control over the KYC, virtual account, and fiat-to-crypto conversion experience.

This is the headless counterpart to the [`useFundWalletWithBankDeposit`](/wallets/funding/bank-deposits) hook. Use the hook when Privy's prebuilt modal fits your flow. Use the headless API when your app needs a fully custom experience.

<Info>
  Headless bank deposits use the same Bridge integration as [fiat
  offramps](/financial-flows/transfers/fiat-offramp). A user who completes terms of service and KYC
  once can both onramp and offramp.
</Info>

## Prerequisites

Headless bank deposits require Bridge API keys. If your app does not already have a Bridge account, [create a Bridge account](https://dashboard.bridge.xyz/get-started?=privy) and obtain API keys.

Then, enable the bank transfer method on the [Account Funding](https://dashboard.privy.io/apps?page=funding) page in the Privy dashboard. Enter your Bridge API keys when prompted, and save.

<img src="https://mintcdn.com/privy-c2af3412/YvGXGsI-T4KAqoan/images/funding/bridge.png?fit=max&auto=format&n=YvGXGsI-T4KAqoan&q=85&s=7c9bc691f29634777c9872ef445f4171" alt="Bridge Configuration" width="1843" height="1317" data-path="images/funding/bridge.png" />

## Register the user

The first time a user onramps, they must agree to Bridge's terms of service and complete KYC verification.

### Request a terms of service agreement

Request a terms of service URL for the user:

<View title="cURL" icon="terminal">
  ```bash theme={"system"}
  curl --request POST \
    --url https://api.privy.io/v1/users/{user_id}/fiat/tos \
    --header 'Authorization: Basic <encoded-value>' \
    --header 'Content-Type: application/json' \
    --header 'privy-app-id: <privy-app-id>' \
    --data '{
    "provider": "bridge-sandbox"
  }'
  ```
</View>

Add a `redirect_uri` query parameter to the returned URL so the user returns to your app after signing. On redirect, the URL includes a `signed_agreement_id` parameter to use in the KYC step.

### Submit KYC information

Check the user's KYC status:

<View title="cURL" icon="terminal">
  ```bash theme={"system"}
  curl --request GET \
    --url https://api.privy.io/v1/users/{user_id}/fiat/kyc \
    --header 'Authorization: Basic <encoded-value>' \
    --header 'privy-app-id: <privy-app-id>'
  ```
</View>

If the user is not yet verified, submit their KYC information:

<View title="cURL" icon="terminal">
  ```bash theme={"system"}
  curl --request POST \
    --url https://api.privy.io/v1/users/{user_id}/fiat/kyc \
    --header 'Authorization: Basic <encoded-value>' \
    --header 'Content-Type: application/json' \
    --header 'privy-app-id: <privy-app-id>' \
    --data '{
    "provider": "bridge-sandbox",
    "data": {
      "type": "individual",
      "first_name": "John",
      "last_name": "Doe",
      "email": "user@example.com",
      "phone": "+59898222122",
      "residential_address": {
        "street_line_1": "1234 Lombard Street",
        "street_line_2": "Apt 2F",
        "city": "San Francisco",
        "subdivision": "CA",
        "postal_code": "94109",
        "country": "USA"
      },
      "signed_agreement_id": "123",
      "birth_date": "1989-09-09",
      "identifying_information": [
        {
          "type": "ssn",
          "number": "111-11-1111",
          "issuing_country": "USA",
          "image_front": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
          "image_back": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
        }
      ]
    }
  }'
  ```
</View>

<Info>
  KYC review takes about 1-2 minutes. Some submissions require manual review, which can take a few
  hours.
</Info>

## Initiate the onramp

Once the user is verified, trigger the onramp. Specify the fiat `source` and the crypto `destination` wallet:

<View title="cURL" icon="terminal">
  ```bash theme={"system"}
  curl --request POST \
    --url https://api.privy.io/v1/users/{user_id}/fiat/onramp \
    --header 'Authorization: Basic <encoded-value>' \
    --header 'Content-Type: application/json' \
    --header 'privy-app-id: <privy-app-id>' \
    --data '{
    "amount": "100.00",
    "provider": "bridge-sandbox",
    "source": {
      "currency": "usd",
      "payment_rail": "ach_push"
    },
    "destination": {
      "currency": "usdc",
      "chain": "base",
      "to_address": "<destination_wallet_address>"
    }
  }'
  ```
</View>

The response returns bank deposit instructions. The user sends fiat to the provider to receive stablecoins in the destination wallet:

```json theme={"system"}
{
  "id": "3a61a69a-1f20-4113-85f5-997078166729",
  "deposit_instructions": {
    "amount": "100.0",
    "currency": "usd",
    "payment_rail": "ach_push",
    "account_holder_name": "account_holder_name",
    "bank_account_number": "11223344556677",
    "bank_routing_number": "123456789",
    "bank_name": "Bank of Nowhere",
    "deposit_message": "BRGFU2Z9TJPJXCS7ZZK2",
    "iban": "iban"
  },
  "status": "awaiting_funds"
}
```

## Complete the bank transfer

The user must follow the deposit instructions exactly, including the `deposit_message`. Bridge supports ACH, wire, and SEPA rails. If the instructions are not followed correctly, the onramp fails.

## Track status

To check the status of an onramp, open the [Wallets page](https://dashboard.privy.io/apps?tab=wallets\&page=wallets) in the Privy dashboard, select the wallet, and open the [Fiat transactions tab](https://dashboard.privy.io/apps?tab=wallets\&wallet-tab=fiat\&page=wallets).
