Skip to main content
In this guide, you’ll learn how to use the HIFI Sandbox API to simulate money movement. You’ll create users, complete KYC, set up a virtual account, simulate a deposit to fund a wallet, and execute a transfer between wallets. ⏱️ Time to complete: 10-15 minutes 🎯 What you’ll build: A complete setup flow where you create a user, complete KYC, set up a virtual account, simulate a deposit to fund the wallet, and execute a transfer between wallets.

Sandbox Environment

This guide uses the Sandbox API where:
  • ✅ All transactions are simulated - no real money moves
  • ✅ KYC applications are typically automatically approved
  • ✅ Transactions complete instantly for testing
  • ✅ You can experiment freely without financial risk
The sandbox behaves identically to production, making it perfect for integration testing.

Prerequisites

Before you start, make sure you have:
  • API keys from the Dashboard (Get API keys)
  • A tool for making API calls (cURL, Postman, or similar)
  • Basic understanding of REST APIs
  • Your sandbox endpoint: https://sandbox.hifibridge.com
All examples in this guide use the sandbox environment. When you’re ready for production, simply replace the sandbox URL with the production endpoint and use your production API keys.

What you’ll build

Here’s what we’ll accomplish in this guide:
  1. User Creation - Create a user and accept Terms of Service
  2. KYC Process - Complete verification to unlock fiat rails
  3. Set Up Virtual Account - Create a virtual account for receiving deposits
  4. Simulate Deposit - Fund the wallet by simulating a deposit (onramp)
  5. Execute a Transfer - Send stablecoins between wallets
  6. Create Offramp Account - Register a bank account for receiving fiat
  7. Create an Offramp - Convert stablecoins back to fiat currency

Create a User

The User object represents an individual or business on HIFI. All transaction activity is associated with a user object. Creating a user is a two-step process:
  1. Generate a Terms of Service link for your end user to review and accept
  2. Create the user once they’ve accepted the terms
Once created, users are automatically provisioned with cryptocurrency wallet addresses, enabling them to immediately send and receive digital assets.
Once your user has accepted the Terms of Service (and you’ve received the webhook event or confirmed acceptance), create the user account with the Create User endpoint.Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/users \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "type": "individual",
  "firstName": "John",
  "lastName": "Doe",
  "email": "[email protected]",
  "dateOfBirth": "1999-01-01",
  "address": {
    "addressLine1": "123 Main St",
    "city": "New York",
    "stateProvinceRegion": "NY",
    "postalCode": "10010",
    "country": "USA"
  },
  "signedAgreementId": "8cb49537-bcf9-41b1-8d8c-c9c200d7341b",
  "requestId": "705f1f8b-a080-467c-b683-174eca409928"
}
'
Response:
{
  "id": "32051b2f-0798-55a7-9c42-b08da4192c97",
  "type": "individual",
  "email": "[email protected]",
  "name": "John Doe",
  "wallets": {
    "INDIVIDUAL": {
      "POLYGON": {
        "address": "0x1b932E54e77Aeb698144550d5a493Ea99E20Daa7"
      },
      "ETHEREUM": {
        "address": "0xC1c767eaB34b3Cc2C33a354f6Ff2c20fCB98D3C9"
      }
    }
  }
}
User created successfully!What you get:
  • User ID (32051b2f-0798-55a7-9c42-b08da4192c97) - Save this for all future operations
  • Wallet addresses - Pre-provisioned on multiple blockchains, ready to use immediately
wallets
object
  • Account status - Active and ready for KYC verification
Automatic Wallet Provisioning: Every user automatically receives wallet addresses on supported blockchain networks (Polygon, Ethereum, etc.). These wallets are fully functional immediately - no additional setup required.

What’s Next?

Now that you have a user, the next step is to complete KYC verification to unlock the ability to move money between fiat and crypto. Continue to the KYC section below.

Complete KYC

To move money between stablecoins and fiat currencies, users must complete KYC verification to unlock a Rail. What is a Rail? A rail is a payment corridor that enables specific currency conversions. For example, the USD rail enables conversions between USD (fiat) and stablecoins like USDC. In this quickstart, we’ll complete KYC for the USD rail, which allows your user to:
  • Deposit USD and receive USDC (onramp)
  • Send USDC and receive USD (offramp)
Rail-Specific Requirements: Each rail has different KYC requirements based on regulatory needs. Visit our Rails page to learn about available rails and their specific requirements.
The easiest way to collect KYC information is using KYC Links, which provide a hosted, user-friendly flow. Generate a KYC link and redirect your user to complete verification. Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/kyc-link \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
  "rails": ["USD"],
  "redirectUrl": "https://yourapp.com/kyc-complete"
}
'
Response:
{
  "kycLinkUrl": "https://dashboard.hifibridge.com/sandbox/kyc-link?sessionToken=768fb84ad65284cb5fffda212f5e779829318acwdab5a36efbf83c4f44369c73"
}
What to do:
  1. Redirect your user to the kycLinkUrl - They’ll complete KYC on HIFI’s hosted page
  2. User completes KYC - They fill out information and upload documents
  3. User is redirected back - After completion, they’re sent to your redirectUrl with ?userId=...
  4. Monitor status - Check KYC status via API or webhooks
KYC Links Benefits: KYC Links handle all the complexity of document uploads, validation, and submission automatically. This is the recommended approach for most integrations. Learn more about KYC Links →

Alternative: Use API

If you need full control over the KYC collection process, you can submit KYC programmatically using the API. This approach requires you to:
  1. Retrieve KYC requirements
  2. Update KYC information
  3. Upload identity documents
  4. Submit the KYC application
  5. Monitor approval status
For detailed instructions on programmatic KYC submission, see our Submit KYC Guide.

Check KYC Status

After your user completes KYC (via KYC Link or programmatic submission), check their status: Request:
curl --request GET \
     --url 'https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/kyc/status?rails=USD' \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY'
Response:
{
  "status": "ACTIVE",
  "message": "",
  "reviewResult": {
    "reviewAnswer": "APPROVED",
    "reviewRejectType": "",
    "rejectReasons": [],
    "comment": ""
  }
}
KYC approved! When status is ACTIVE, the USD rail is unlocked and the user can proceed with transfers.
Sandbox Auto-Approval: In the sandbox environment, KYC applications are typically automatically approved within minutes for testing purposes. In production, the review process typically takes 1-3 business days.
You can monitor KYC status by:
  1. Polling the Retrieve KYC Status endpoint
  2. Listening for KYC.STATUS_UPDATE webhook events

Create Virtual Account

Now that your user has passed KYC, you can add a Virtual Account to enable onramping (converting fiat deposits into stablecoins). A Virtual Account is a bank account number automatically created by HIFI that your user can deposit money into. When fiat arrives, it’s automatically converted to the specified stablecoin and sent to the user’s wallet. The parameters you specify determine the conversion:
  • sourceCurrency - Fiat currency to deposit (e.g., usd)
  • destinationCurrency - Stablecoin to receive (e.g., usdc)
  • destinationChain - Blockchain network (e.g., POLYGON)
Let’s create a virtual account that converts USD deposits into USDC on Polygon: Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/virtual-accounts \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "sourceCurrency": "usd",
  "destinationCurrency": "usdc",
  "destinationChain": "POLYGON"
}
'
Response:
{
  "message": "Virtual account created successfully",
  "accountInfo": {
    "id": "938e3b36-3be7-5535-ba12-8d89eb683e6b",
    "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
    "source": {
      "paymentRail": ["ach", "wire", "rtp"],
      "currency": "usd"
    },
    "destination": {
      "chain": "POLYGON",
      "currency": "usdc",
      "walletAddress": "0x1b932E54e77Aeb698144550d5a493Ea99E20Daa7",
      "externalWalletId": null
    },
    "status": "activated",
    "depositInstructions": {
      "bankName": "Cross River Bank",
      "bankAddress": "885 Teaneck Road, Teaneck, NJ 07666",
      "beneficiary": {
        "name": "John Doe",
        "address": "123 Main St, New York, NY, 10010, US"
      },
      "ach": {
        "routingNumber": "021214891",
        "accountNumber": "344176915009"
      },
      "wire": {
        "routingNumber": "021214891",
        "accountNumber": "344176915009"
      },
      "rtp": {
        "routingNumber": "021214891",
        "accountNumber": "344176915009"
      },
      "instruction": "Please deposit USD to the bank account provided. Ensure the beneficiary name matches the account holder name, or the payment may be rejected."
    }
  }
}
Virtual account created! Your user can now deposit USD to onramp into USDC. Important Fields:
accountInfo.id
string
The unique virtual account ID. Save this for retrieving account details and monitoring deposits.
accountInfo.depositInstructions
object
Most Important: Bank account details your user needs to send money to. Share these instructions with your user so they can deposit funds via their bank (wire transfer, ACH, or RTP).
How to Use: Provide these deposit instructions to your end user through your app/website. When they send money to this account via their bank, HIFI automatically detects the deposit, converts it to USDC, and sends it to their wallet.

Simulate Deposit

Before we can transfer funds, we need to fund the user’s wallet. In sandbox, we’ll simulate a deposit to the virtual account, which will trigger an onramp and deposit USDC into the user’s wallet. What is an Onramp? An onramp converts fiat money deposited into a virtual account into stablecoins and sends them to the user’s wallet.

How Onramps Work

In production, onramping happens automatically when your user sends money from their bank to the virtual account. HIFI detects the deposit and automatically triggers the conversion. In sandbox, we use a simulation endpoint to mimic an incoming deposit without requiring real bank transfers.

Simulate Deposit (Sandbox)

Since we’re in sandbox, use the simulate endpoint to create a test deposit: Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/virtual-accounts/938e3b36-3be7-5535-ba12-8d89eb683e6b/simulate-deposit \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "paymentRail": "wire",
  "source": {
    "routingNumber": "021000021",
    "accountNumber": "516843515316",
    "name": "Jane Doe",
    "bankName": "JP Morgan Chase"
  },
  "amount": "2",
  "requestId": "32639f89-5fcc-4e31-8abe-0e710ba2e4a1",
  "reference": "This is a test deposit"
}
'
Request Fields:
paymentRail
string
required
How the money is being sent: wire, ach, or rtp
source
object
required
Simulates the sender’s bank information. This represents the bank account sending money TO the virtual account.
amount
string
required
Amount of USD being deposited (will convert to equivalent USDC).
requestId
string
required
Unique identifier for this deposit simulation (UUID).
Response:
{
  "message": "Sandbox deposit triggered"
}
Deposit simulated! HIFI will process the deposit and create an onramp transaction.

Monitor Onramp Status

HIFI creates an onramp transaction when a deposit is detected. You’ll receive a ONRAMP.CREATE webhook event with transaction details. Onramp Status Progression:
  1. FIAT_PENDING - Waiting for fiat to settle
  2. CRYPTO_PENDING - Converting and sending crypto
  3. COMPLETE - USDC delivered to wallet
Monitor via:
  • Webhooks: Subscribe to ONRAMP.UPDATE events for real-time notifications
  • Polling: Call Retrieve an onramp with the transaction ID
Learn More: For detailed information about receiving money, see the Receive Money Guide.
Wait for Completion: Wait for the onramp status to reach COMPLETE before proceeding with the transfer. This ensures the user’s wallet has funds available.

Execute a Transfer

Now that your user has funds in their wallet, you can execute a transfer - sending stablecoins directly between user wallets on the blockchain. What is a Transfer? A transfer sends stablecoins from one user’s wallet to another user’s wallet. No fiat conversion occurs - this is pure crypto-to-crypto movement.

Create Transfer

Send stablecoins from one user to another using the Create a crypto transfer endpoint. Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/wallets/transfers \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "source": {
    "userId": "32051b2f-0798-55a7-9c42-b08da4192c97"
  },
  "destination": {
    "userId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87"
  },
  "requestId": "a40ea2aa-7937-4be9-bb1f-b75f1489bcc6",
  "amount": 1,
  "currency": "usdc",
  "chain": "POLYGON"
}
'
Request Fields:
requestId
string
required
Unique identifier (UUID) for this transfer request. Ensures idempotency - retrying with the same ID won’t create duplicate transfers.
source
object
required
Source of the transfer.
destination
object
required
Destination of the transfer.
amount
number
required
Amount of stablecoins to transfer.
currency
string
required
Stablecoin to transfer (e.g., usdc, usdt).
chain
string
required
Blockchain network for the transfer (e.g., POLYGON, ETHEREUM).
Response:
{
  "transferType": "WALLET.TRANSFER",
  "transferDetails": {
    "id": "1a1ad1dd-ad72-4f3f-910b-c45dcf09875f",
    "requestId": "a40ea2aa-7937-4be9-bb1f-b75f1489bcc6",
    "createdAt": "2025-09-26T03:04:11.092Z",
    "updatedAt": "2025-09-26T03:04:11.092Z",
    "chain": "POLYGON",
    "currency": "usdc",
    "contractAddress": "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
    "status": "CREATED",
    "failedReason": null,
    "source": {
      "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
      "walletAddress": "0x1b932E54e77Aeb698144550d5a493Ea99E20Daa7",
      "walletType": "INDIVIDUAL",
      "user": {
        "email": "[email protected]",
        "lastName": "Doe",
        "firstName": "John",
        "businessName": null
      }
    },
    "destination": {
      "userId": "30669fcc-b15e-4137-b4fc-9e8f7f659a87",
      "walletAddress": "0x1b932E54e77Aeb688144550d5a493Ea99E20Daa7",
      "user": {
        "email": "[email protected]",
        "lastName": "Doe",
        "firstName": "Jane",
        "businessName": null
      }
    },
    "amount": 1,
    "amountIncludeDeveloperFee": 1,
    "receipt": {
      "transactionHash": null,
      "userOpHash": null
    }
  }
}
Transfer created! Important Fields:
transferDetails.id
string
Unique transfer ID. Save this to check status using the Retrieve a crypto transfer endpoint.
transferDetails.status
string
Transfer status. Starts as CREATED, then progresses through: - CREATED - Transfer initiated - PENDING - Being processed on blockchain - COMPLETE - Successfully delivered - FAILED - Transfer failed (see failedReason)

Monitor Transfer Status

Transfer Status Progression:
  1. CREATED - Transfer initiated
  2. PENDING - Being processed on blockchain
  3. COMPLETE - Successfully delivered
  4. FAILED - Transfer failed (see failedReason)
Monitor via:
  • Webhooks: Subscribe to WALLET.TRANSFER.UPDATE events for real-time notifications
  • Polling: Call Retrieve a crypto transfer with the transfer ID
Learn More: For detailed information about other transaction types, see: - Receive Money - Convert fiat to stablecoins - Send Money - Convert stablecoins to fiat
Sandbox Simulation: No real money moves in sandbox. All transfers are simulated, but the API requests and responses are identical to production.

Create an Offramp

Now let’s convert stablecoins back to USD using an offramp. An offramp converts USDC to USD and sends it to a user’s bank account.

Create Offramp Account

Before creating an offramp, users need to register their bank account as an offramp account. This account will receive fiat currency when stablecoins are converted. Create an offramp account using the Create Account endpoint:
curl -X POST "https://sandbox.hifibridge.com/v2/users/32051b2f-0798-55a7-9c42-b08da4192c97/accounts" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rail": "offramp",
    "type": "us",
    "accountHolder": {
      "type": "individual",
      "name": "John Doe",
      "phone": "+18573491112",
      "email": "[email protected]",
      "address": {
        "addressLine1": "123 Main St",
        "city": "New York",
        "stateProvinceRegion": "NY",
        "postalCode": "10010",
        "country": "USA"
      }
    },
    "us": {
      "transferType": "wire",
      "accountType": "checking",
      "accountNumber": "99485843",
      "routingNumber": "011002877",
      "bankName": "HIFI Bank",
      "currency": "usd"
    }
  }'
Response:
{
  "status": "ACTIVE",
  "id": "583eb259-e78b-4f0c-a4b5-a8957876fa6f",
  "message": "Account created successfully"
}
Account created! Save the id - you’ll need it when creating offramps.
Monitor Account Status: Account status indicates whether the account is ready to use:
  • ACTIVE - Account is validated and ready for offramps
  • PENDING - Account is being validated (wait for activation)
  • REJECTED - Validation failed (check invalidFields for details)
Monitor via webhooks (ACCOUNT.UPDATE) or by polling the Retrieve an account endpoint.
More Account Types: For additional regions and currencies (China, Hong Kong, Nigeria, and more), see the Offramp Accounts Guide.

Create Offramp Request

Create an offramp request to get a quote for converting USDC to USD: Request:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/offramps \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY' \
     --header 'content-type: application/json' \
     --data '
{
  "requestId": "c5f8a2b1-3d4e-5f6a-7b8c-9d0e1f2a3b4c",
  "source": {
    "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
    "currency": "usdc",
    "chain": "POLYGON",
    "amount": 1
  },
  "destination": {
    "userId": "32051b2f-0798-55a7-9c42-b08da4192c97",
    "currency": "usd",
    "accountId": "583eb259-e78b-4f0c-a4b5-a8957876fa6f"
  }
}
'
Response:
{
  "transferType": "OFFRAMP",
  "transferDetails": {
    "id": "b838908b-95d0-4ebb-a2c6-8f0c142bcdd7",
    "status": "OPEN_QUOTE",
    "quoteInformation": {
      "exchangeRate": "0.99",
      "expiresAt": "2025-09-26T03:20:00.000Z"
    }
  }
}
Accept the quote to execute the conversion:
curl --request POST \
     --url https://sandbox.hifibridge.com/v2/offramps/b838908b-95d0-4ebb-a2c6-8f0c142bcdd7/quote/accept \
     --header 'accept: application/json' \
     --header 'authorization: Bearer YOUR_API_KEY'
Offramp initiated! Monitor status via webhooks (OFFRAMP.UPDATE) or by polling the Retrieve an offramp endpoint.
Learn More: For detailed offramp information, see the Send Money Guide and Offramp Guide.

🎉 Congratulations!

You’ve successfully completed the HIFI API quickstart! By following the steps above, you can now:
  • ✅ Create users and handle Terms of Service acceptance
  • ✅ Complete the KYC process to unlock fiat rails
  • ✅ Set up virtual accounts for receiving deposits
  • ✅ Simulate deposits to fund wallets
  • ✅ Execute transfers between wallets
  • ✅ Create offramp accounts for receiving fiat
  • ✅ Create offramps to convert stablecoins to fiat

Next Steps

Ready to build your integration? Here’s what to explore next: