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
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:- User Creation - Create a user and accept Terms of Service
- KYC Process - Complete verification to unlock fiat rails
- Account Setup - Add virtual accounts (for receiving deposits) and offramp accounts (for withdrawals)
- Execute Transfers:
- Onramp: $2 USD → 2 USDC (User A)
- Transfer: 1 USDC from User A → User B
- Offramp: 1 USDC → $1 USD (User A)
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:- Generate a Terms of Service link for your end user to review and accept
- Create the user once they’ve accepted the terms
Generate Terms of Service Link
Generate Terms of Service Link
Before creating a user, they must accept HIFI’s Terms of Service. Generate a unique acceptance link using the Generate Terms of Service Link endpoint.You’ll provide an Response:What to do with this response:
idempotencyKey (any UUID), which will become your signedAgreementId after the user accepts the terms.Request:- Direct your user to the
url- Present this link to your end user (via email, in your app, etc.) - Save the
signedAgreementId- You’ll need this to create the user in the next step - Wait for acceptance - The
signedAgreementIdbecomes valid only after the user clicks “Accept”
Real-time Notifications: HIFI triggers the
TOS_LINK.UPDATE webhook event
when the user accepts the terms, allowing you to proceed with user creation
immediately. Learn about webhooks →Create User
Create User
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:Response:✅ 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
- 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.Submit 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.
KYC Process
The KYC process follows these steps:- Retrieve KYC Requirements - Get the list of required information for your target rail
- Update KYC Information - Provide required personal information
- Upload KYC Documents - Submit identity verification documents
- Submit KYC - Submit the application for review
- Check KYC Status - Monitor the approval status
Retrieve KYC Requirements
Retrieve KYC Requirements
First, find out what information is needed for the USD rail by calling the Retrieve KYC Requirements endpoint.Request:Response:Response Fields:Now that we know what’s missing, let’s provide the required information.
All mandatory KYC fields needed for the USD rail. These must be provided
before submission.
Additional fields that aren’t mandatory but may help with approval or enable
additional features.
Most Important Field: Lists any missing or invalid data that must be
corrected before KYC submission.
Update KYC Information
Update KYC Information
Provide the missing personal information using the Update KYC endpoint.Request:Response:✅ Personal information updated! Notice the
documents array is still empty - we’ll upload those next.Upload KYC Documents
Upload KYC Documents
Now we need to upload identity verification documents. This is a two-step process:Response:Response Fields:Request:Request Fields:Response:Response Fields:✅ Documents uploaded! All required KYC information is now complete. Time to submit for review.
- Upload the file to get a
fileId - Attach the file to the user’s KYC application
Upload a File
First, upload the identity document (driver’s license, passport, etc.) using the Upload a File endpoint.Request:The file ID. Save this - you’ll use it in the next step to attach this
document to the user’s KYC application.
Original filename of the uploaded file.
File size in bytes.
File type (e.g., image/png, image/jpeg, application/pdf).
Add Documents to KYC
Now attach the uploaded file(s) to the user’s KYC application using the Add Documents endpoint.Driver’s License Requirements: Most identity documents require both front
and back images. For this example, we’ll use the same file ID for both sides,
but in production you should upload and attach separate images.
Document type. Options:
DRIVERS, ID_CARD, PASSPORT, RESIDENCE_PERMITWhich side of the document. Options:
FRONT_SIDE, BACK_SIDE (passports
typically only need FRONT_SIDE)Country that issued the document (ISO country code).
The file ID received from the file upload endpoint.
Number of documents successfully attached.
Array of document objects with IDs, types, and temporary signed URLs for
viewing.
Submit KYC
Submit KYC
With all fields and documents provided, submit the KYC application to unlock the USD rail using the Submit KYC endpoint.Request:Response:✅ KYC application submitted!What happens next?You can either:
- Status starts as
CREATED(immediate) - Transitions to
PENDING(within minutes in sandbox) - Final status:
ACTIVEorREJECTED(typically automatic in sandbox, 1-3 business days in production)
Sandbox Auto-Approval: In the sandbox environment, KYC applications are
typically automatically approved within minutes for testing purposes. However,
certain compliance checks (like PEP screening by banking partners) may still
block approval even in sandbox. In production, the review process typically
takes 1-3 business days.
- Poll the Retrieve KYC Statusendpoint
- Listen for
KYC.STATUS_UPDATEwebhook events
Retrieve KYC Status
Retrieve KYC Status
Check the current KYC status for the USD rail using the Retrieve KYC Status endpoint.Request:Response:✅ KYC approved! The status is
ACTIVE, which means the USD rail is now unlocked and the user can:- Onramp USD to stablecoins
- Offramp stablecoins to USD
Overall KYC status for the rail. Possible values: -
CREATED - Application
submitted, not yet reviewed - PENDING - Being reviewed by compliance team -
ACTIVE - Approved, rail is unlocked - REJECTED - Not approved (see
rejectReasons for details)High-level review outcome for the entire application.
Detailed review results broken down by category (identity documents, personal
information, questionnaire). Useful for diagnosing issues if rejected.
Create Accounts
Now that your user has passed KYC, you can add accounts to enable money movement:- Virtual Account - For onramping (fiat deposits into stablecoins)
- Offramp Account - For offramping (sending stablecoins to fiat)
Account Types
| Feature | Virtual Account | Offramp Account |
|---|---|---|
| Purpose | Receive fiat deposits | Send fiat withdrawals |
| Direction | Fiat → Crypto (Onramp) | Crypto → Fiat (Offramp) |
| Owner | Created by HIFI for the user | User’s external bank account |
| Example | User deposits $100 to virtual account → Receives USDC | User sends USDC → Receives $100 in their bank |
Add Virtual Account
Add Virtual Account
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:Response:✅ Virtual account created! Your user can now deposit USD to onramp into USDC.Response Fields:
sourceCurrency- Fiat currency to deposit (e.g.,usd)destinationCurrency- Stablecoin to receive (e.g.,usdc)destinationChain- Blockchain network (e.g.,POLYGON)
The unique virtual account ID. Save this for retrieving account details
and monitoring deposits.
Supported payment methods for this virtual account:
ach, wire, rtp
(Real-Time Payments).The fiat currency this account accepts (USD in this example).
Blockchain where the converted crypto will be sent.
stablecoins the user will receive after conversion.
The user’s wallet address where USDC will be deposited. This matches the
wallet address assigned when the user was created.
Account status.
activated means it’s ready to receive deposits.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.
Add Offramp Account
Add Offramp Account
An Offramp Account is your user’s external bank account where they want to receive fiat money. When offramping, their stablecoins are converted to fiat and sent to this account.Create a USD offramp bank account for Wire transfers:Request:Request Fields:Response:✅ Offramp account added!Response Fields:
Sandbox Pre-Configuration: For this guide, we’ve simplified the bank
account details. In production, you’ll collect real bank account information
from your users.
Always
offramp for accounts that receive fiat from crypto conversion.Account type based on country. Options:
us, eu, gb, etc.Information about the account owner. Important: Must match the user’s KYC
information for compliance.
US-specific bank account information.
The unique account ID. Save this - you’ll use it when initiating offramp
transfers to this bank account.
Account status.
ACTIVE means it’s ready to receive offramp funds.List of any validation errors. Empty array means all fields are valid.
Make Transfers
Your user can now perform three types of money movement:- Onramp - Convert fiat → stablecoin (via virtual account)
- Crypto Transfer - Send stablecoin between wallets
- Offramp - Convert stablecoin → fiat (to bank account)
Transfer Flows
We’ll demonstrate the entire flow between two users:- User A (John Doe) - The user we just created (
32051b2f-0798-55a7-9c42-b08da4192c97) - User B (Jane Doe) - A pre-existing test user in sandbox (
30669fcc-b15e-4137-b4fc-9e8f7f659a87)
- User A onramps $2 USD → 2 USDC
- User A transfers 1 USDC → User B
- User A offramps 1 USDC → $1 USD to their bank account
Sandbox Simulation: No real money moves in sandbox. All transfers are
simulated, but the API requests and responses are identical to production.
Onramp $2 USD to 2 USDC
Onramp $2 USD to 2 USDC
In production, onramping happens when your user sends real 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.Request Fields:Response:✅ Deposit simulated!Important Fields:Wait for the status to update to
Onramp Flow
Your user would send money via their bank app or wire transfer to:- Bank: Cross River Bank
- Beneficiary: John Doe
- Beneficiary Address: 123 Main St, New York, NY, 10010, US
- Routing Number: 021214891
- Account Number: 344176915009
- Amount: $2.00
Simulate Deposit (Sandbox)
Since we’re in sandbox, use the simulate endpoint to create a test deposit:Request:How the money is being sent:
wire, ach, or rtpSimulates the sender’s bank information. This represents the bank account
sending money TO the virtual account.
Amount of USD being deposited (will convert to equivalent USDC).
Unique identifier for this deposit simulation (UUID).
Monitor Onramp
HIFI will now process the deposit and create an onramp transaction. You’ll receive aONRAMP.CREATE webhook event:Webhook Event Payload:Unique identifier for this onramp transaction. Use this to query transaction
status.
Current status of the onramp. Progression: -
FIAT_PENDING - Waiting for fiat
to settle - CRYPTO_PENDING - Converting and sending crypto - COMPLETE -
USDC delivered to walletSource of the onramp transfer (fiat deposit details).
Destination of the onramp transfer (crypto wallet details).
Transaction receipt information.
Conversion details including exchange rate, fees, and net amounts
sent/received.
COMPLETE, then check User A’s wallet balance to see the 2 USDC!Transfer 1 USDC Between Wallets
Transfer 1 USDC Between Wallets
Now User A will send 1 USDC to User B using the Create a crypto transfer endpoint.Request:Request Fields:Response:Response Fields:
Unique identifier (UUID) for this transfer request. Ensures idempotency -
retrying with the same ID won’t create duplicate transfers.
Source of the crypto transfer.
Destination of the crypto transfer.
Amount of stablecoins to transfer.
stablecoins to transfer (e.g.,
usdc, usdt).Blockchain network for the transfer (e.g.,
POLYGON, ETHEREUM).Unique transfer ID. Save this to check status using the Retrieve a crypto
transfer
endpoint.
Transfer status. Starts as
CREATED, then progresses through: - CREATED -
Transfer initiated - PENDING - Being processed on blockchain - COMPLETE -
Successfully delivered - FAILED - Transfer failed (see failedReason)Details about the sender including wallet address and user information.
Details about the recipient including wallet address and user information.
Transaction receipt information.
If status is
FAILED, this explains why (e.g., insufficient balance, invalid
address).Monitoring Transfers: Subscribe to
WALLET.TRANSFER.UPDATE webhook events
or poll the Retrieve endpoint to track status until COMPLETE.Offramp 1 USDC to $1 USD
Offramp 1 USDC to $1 USD
Finally, User A will convert their remaining 1 USDC back to USD and send it to their bank account. This is a two-step process:Request Fields:Response:Response Fields:Response:✅ Quote accepted! The status has changed to
- Create offramp request - Get a quote for the conversion
- Accept the quote - Execute the offramp
Create Offramp Request
Create an offramp request using the Create an offramp endpoint:Request:Unique identifier (UUID) for this offramp request.
Source of the offramp (crypto side).
Destination of the offramp (fiat side).
Unique offramp transaction ID. Save this - you’ll need it to accept the
quote and check status.
Current status:
OPEN_QUOTE means you have an active quote that needs to be
accepted.Critical: Contains the conversion rate and amounts. Review this before accepting.
Error message if the offramp request failed.
Source of the offramp transfer (crypto wallet details).
Destination of the offramp transfer (fiat account details).
Transaction receipt information.
Detailed error information for troubleshooting.
Quote Expiration: Quotes typically expire after 15-30 minutes. If your
quote expires before you accept it, you’ll need to create a new offramp
request to get a fresh quote with updated rates.
Accept the Quote
After reviewing the quote, accept it to start the offramp process using the Accept Quote endpoint:Request:CRYPTO_INITIATED.Offramp Status Progression:OPEN_QUOTE- Quote generated, waiting for acceptanceCRYPTO_INITIATED- Processing crypto conversionCRYPTO_PENDING- Waiting for blockchain confirmationFIAT_PENDING- Converting to fiatCOMPLETE- USD sent to bank account
- Polling: Call Retrieve an offramp with the transaction ID
- Webhooks: Subscribe to
OFFRAMP.UPDATEevents for real-time notifications
🎉 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 onramping
- ✅ Add offramp bank accounts for withdrawals
- ✅ Execute the complete transfer flow: onramp → transfer → offramp
Next Steps
Ready to build your integration? Here’s what to explore next:- Webhooks - Set up real-time event notifications for transaction updates
- Rails Overview - Learn about additional currency rails
- Error Handling - Understand error codes and how to handle failures
- API Reference - Explore all available endpoints and parameters