Privy enables programmable account funding via bank transfer by natively integrating Bridge directly within Privy’s API. This recipe details how your app can use Privy to provide a seamless, customizable fiat/crypto conversion experience for your users.

Using Privy’s APIs, you can:

  • Link a Privy user with a Bridge customer account and their external bank accounts
  • Onramp (convert fiat to crypto)
  • Offramp (convert crypto to fiat)
  • Switch between Bridge sandbox and production environments

Setup

Configure your app to use Bridge for account funding

If you don’t already have a Bridge account, request access at Bridge and get Bridge API keys.

Then, turn on the bank transfer method on the Account Funding page in the Privy dashboard. Enter your Bridge API keys when prompted, and save.

Register a new user for onramp or offramp

When a user is onramping or offramping via Bridge for the first time, they must agree to their terms of service, as well as go through the KYC process.

Provide a terms of service agreement to the user

First, the user must agree to the onramp provider’s terms of service. Request a new terms of service url for a user:

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

Then, add the query param redirect_uri to the url, so that after the user goes to that link and signs the terms of service, the user is redirected to your app. Upon redirect, a signed_agreement_id parameter will be in the url, which you will use for the next KYC step.

Submit the user’s KYC information

In order to onramp or offramp, the user must first be KYC’d. You can check their KYC status like so:

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>'

If the user is not KYC’d yet, gather and submit their KYC information:

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": "[email protected]",
    "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..."
      }
    ]
  }
}'

Note: After submission, the KYC process takes about 1-2 minutes to undergo review. Sometimes, a manual review is required, which can take longer (a few hours).

Onramp funds

This assumes that all the above steps have been completed.

Trigger the onramp flow

Once the user is KYC’d, you can trigger the onramp flow.

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": "0x38Bc05d7b69F63D05337829fA5Dc4896F179B5fA"
  }
}'

This will return deposit instructions for the user to complete, since they will need to send fiat funds to the onramp provider in order to receive stablecoins in their wallet. For example:

{
  "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_address": "1800 North Pole St., Orlando, FL 32801",
    "bank_beneficiary_address": "1234 Elm St, Springfield, IL 12345",
    "bank_beneficiary_name": "Bridge Ventures Inc",
    "bank_name": "Bank of Nowhere",
    "bank_routing_number": "123456789",
    "bic": "bic",
    "deposit_message": "BRGFU2Z9TJPJXCS7ZZK2",
    "iban": "iban"
  },
  "status": "awaiting_funds"
}

Follow bank deposit instructions

If the onramp method is a bank transfer, the user will need to follow the specific instructions to send a bank deposit with the specified deposit message. If these instructions are not followed correctly, the onramp will fail.

Offramp

This assumes that that the Terms of Service and KYC process have been completed for the user.

Register a fiat account to offramp to

In order for Bridge to offramp and send fiat funds to the user, the user must first register a fiat account (e.g. bank account) with them.

curl --request POST \
  --url https://api.privy.io/v1/users/{user_id}/fiat/accounts \
  --header 'Authorization: Basic <encoded-value>' \
  --header 'Content-Type: application/json' \
  --header 'privy-app-id: <privy-app-id>' \
  --data '{
  "provider": "bridge-sandbox",
  "account_owner_name": "John Doe",
  "currency": "usd",
  "bank_name": "Chase",
  "account": {
    "account_number": "1234567899",
    "routing_number": "121212121",
    "checking_or_savings": "checking"
    },
  "address": {
    "street_line_1": "123 Washington St",
    "street_line_2": "Apt 2F",
    "city": "New York",
    "state": "NY",
    "postal_code": "10001",
    "country": "USA"
  },
  "first_name": "John",
  "last_name": "Doe"
}'

Trigger the offramp flow

Once the user has a fiat account registered, you can trigger the offramp flow. In this flow, stablecoins must be sent from the user’s wallet to the onramp provider’s on-chain address.


curl --request POST \
  --url https://api.privy.io/v1/users/{user_id}/fiat/offramp \
  --header 'Authorization: Basic <encoded-value>' \
  --header 'Content-Type: application/json' \
  --header 'privy-app-id: <privy-app-id>' \
  --data '{
  "provider": "bridge-sandbox",
  "amount": "100.00",
  "source": {
    "currency": "usdc",
    "chain": "base",
    "from_address": "0xc24272abc794b973b896715db40a72714a030323"
  },
  "destination": {
    "currency": "usd",
    "payment_rail": "ach_push",
    "external_account_id": "a068d2dd-743a-4011-9b62-8ad33cc7a7be"
  }
}'

This will return deposit instructions for the user to complete, since they will need to send their stablecoins to the onramp provider’s on-chain address in order to receive fiat funds in their account.

Use Privy to complete this send. As an example of how to do this, see the Send USDC recipe.

To check on a status of an onramp or offramp, you can go to the Wallets page in the Privy dashboard, and click on the wallet. On the sidebar, go to the Fiat transactions tab.