Skip to main content
Build remittance products that enable users to send money home to family and friends across borders. Our platform provides the infrastructure you need to create seamless, compliant international money transfer experiences. ⏱️ Time to complete: 30-40 minutes 🎯 What you’ll build: A complete remittance flow where User A (in the US) sends $11 USD that converts to USDC, then offramps to User B’s bank account in Mexico as MXN pesos.

Use Case Overview

This recipe demonstrates a cross-border remittance payment where:
  • ✅ User A deposits USD from their US bank account
  • ✅ USD automatically converts to USDC stablecoin
  • ✅ USDC is sent and converted to MXN pesos
  • ✅ MXN is deposited to User B’s Mexican bank account
This flow enables fast, cost-effective international money transfers with transparent pricing.

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 recipe:
  1. Generate API Keys - Set up authentication for HIFI API
  2. Create User A - Onboard the sender and complete KYC for USD rail
  3. Add Virtual Account - Set up account for USD deposits that convert to USDC
  4. Create User B - Onboard the recipient (or use existing user)
  5. Execute Remittance - Send USDC from User A → MXN to User B’s bank account
Payment Flow:
USD → User A Bank Account → USDC → User A Wallet → MXN → User B Bank Account

Generate API Keys

Access to the HIFI API requires authentication via API keys. Generate your keys from the HIFI Dashboard before making any API calls.
Steps:
  1. Navigate to dashboard.hifibridge.com
  2. Log in to your account
  3. Go to Developer → API Keys
  4. Click Generate New Key
  5. Select your environment: Sandbox (for testing) or Production (for live transactions)
  6. Copy the key immediately - it’s only shown once
Important Security Notes:
  • Store your API key securely (environment variables, secrets manager, etc.)
  • Never commit API keys to version control
  • Your key authenticates all HIFI API requests
  • If compromised, immediately revoke in the Dashboard and generate a new one
API keys are shown only once. If you lose your key, you must revoke it and generate a new one. There is no way to retrieve a lost key.
Using Your API Key:Include your API key in the Authorization header of all API requests:
--header 'authorization: Bearer YOUR_API_KEY'

Create User A (Sender)

The sender needs a verified user account to access fiat rails and send remittances. Every user must accept HIFI’s Terms of Service and complete KYC verification before they can move money between fiat and crypto.
Complete Onboarding Guide: For a comprehensive walkthrough of user onboarding and KYC verification, see our User Guide.

User Creation Flow

Creating a user involves four steps:
  1. Generate Terms of Service Link - Get acceptance link for your customer
  2. Create User - Create the user account after TOS acceptance
  3. Update KYC Information - Provide required personal details
  4. Submit KYC - Submit for verification to unlock USD rail
Once your user has accepted the Terms of Service, 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": "johndoe@gmail.com",
  "dateOfBirth": "1990-01-01",
  "address": {
    "addressLine1": "123 Park Ave",
    "city": "Kansas City",
    "stateProvinceRegion": "KS",
    "postalCode": "10001",
    "country": "USA"
  },
  "signedAgreementId": "c9c91801-d3a2-4a1c-aa2e-fcb2c473198c",
  "requestId": "705f1f8b-a080-467c-b683-174eca409928"
}
'
Request Fields:
type
string
required
User type. Use individual for personal accounts or business for business accounts.
firstName
string
required
User’s first name.
lastName
string
required
User’s last name.
email
string
required
User’s email address.
dateOfBirth
string
required
User’s date of birth in YYYY-MM-DD format.
address
object
required
User’s residential address.
signedAgreementId
string
required
The signedAgreementId from the Terms of Service acceptance.
requestId
string
required
Unique identifier (UUID) for this request to ensure idempotency.
Response:
{
  "id": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
  "type": "individual",
  "email": "johndoe@gmail.com",
  "name": "John Doe",
  "wallets": {
    "INDIVIDUAL": {
      "ETHEREUM": {
        "address": "0x062f27D749Db9AdE709FaCF753e71618a0d64eF7"
      },
      "POLYGON": {
        "address": "0x63dAbB631bcE6d6090A4e6c5c7aB20d3D853C338"
      }
    }
  }
}
User created successfully!Response Fields:
id
string
The unique user ID. Save this - you’ll use it for all future operations with this user.
wallets
object
Automatically provisioned wallet addresses on supported blockchain networks.
What you get:
  • User ID (3b77cec8-1bb9-5ea0-91a1-e8c1411dd429) - Save this for all future operations
  • Wallet addresses - Pre-provisioned on multiple blockchains, ready to use immediately
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.
Provide the required personal information for KYC verification using the Update KYC endpoint.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/users/3b77cec8-1bb9-5ea0-91a1-e8c1411dd429/kyc \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data '
{
  "firstName": "John",
  "phone": "+11111111111",
  "taxIdentificationNumber": "678898765",
  "nationality": "USA"
}
'
Request Fields:
firstName
string
User’s first name (can be used to update if needed).
phone
string
required
User’s phone number with country code (E.164 format).
taxIdentificationNumber
string
required
Tax identification number (e.g., SSN for US users).
nationality
string
required
User’s nationality (ISO 3166-1 alpha-3 country code).
Response:
{
  "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
  "kycInfo": {
    "type": "individual",
    "firstName": "John",
    "lastName": "Doe",
    "nationality": "USA",
    "email": "johndoe@gmail.com",
    "phone": "+11111111111",
    "address": {
      "city": "Kansas City",
      "country": "USA",
      "postalCode": "10001",
      "addressLine1": "123 Park Ave",
      "stateProvinceRegion": "KS"
    },
    "dateOfBirth": "1990-01-01T00:00:00+00:00",
    "taxIdentificationNumber": "678898765",
    "documents": []
  }
}
Personal information updated!
Document Upload: For a complete KYC submission in production, you’ll also need to upload identity documents (passport, driver’s license, etc.). See the Quickstart Guide for detailed document upload instructions.
Submit the KYC application to unlock the USD rail using the Submit KYC endpoint.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/users/3b77cec8-1bb9-5ea0-91a1-e8c1411dd429/kyc/submissions \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data '
{
  "rails": "USD"
}
'
Request Fields:
rails
string
required
The currency rail to unlock. Use USD for US Dollar operations.
Response:
{
  "currency": "USD",
  "status": "ACTIVE",
  "reviewResult": {
    "reviewAnswer": "APPROVED",
    "reviewRejectType": "",
    "rejectReasons": [],
    "comment": ""
  },
  "details": {
    "identity": {
      "reviewAnswer": "APPROVED",
      "documents": [
        {
          "id": "c00791d0-213a-480a-9e54-1c535673f10c",
          "type": "PASSPORT",
          "subType": "SINGLE_SIDE",
          "reviewAnswer": "APPROVED"
        }
      ]
    },
    "questionnaire": {
      "reviewAnswer": "APPROVED",
      "details": []
    },
    "personalInfo": {
      "reviewAnswer": "APPROVED",
      "details": []
    }
  }
}
KYC approved! USD rail is now active.Response Fields:
status
string
Overall KYC status. ACTIVE means the USD rail is unlocked and the user can now onramp and offramp USD.
reviewResult
object
High-level review outcome.
details
object
Detailed review results broken down by category.
Sandbox Auto-Approval: In sandbox, KYC applications are typically automatically approved within minutes. In production, review typically takes 1-3 business days.

Add Virtual Account (User A)

Now that User A has passed KYC, create a Virtual Account for onramping. This is a bank account number automatically created by HIFI that User A can deposit USD into. When fiat arrives, it’s automatically converted to USDC and sent to their wallet.
Complete Virtual Account Guide: For more details on virtual accounts and onramping, see our Virtual Accounts Guide.
A Virtual Account enables User A to deposit USD from their bank, which automatically converts to USDC on Polygon.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/users/3b77cec8-1bb9-5ea0-91a1-e8c1411dd429/virtual-accounts \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data '
{
  "sourceCurrency": "usd",
  "destinationCurrency": "usdc",
  "destinationChain": "POLYGON"
}
'
Request Fields:
sourceCurrency
string
required
Fiat currency to deposit. Use usd for US Dollars.
destinationCurrency
string
required
Stablecoin to receive after conversion. Use usdc for USD Coin.
destinationChain
string
required
Blockchain network for the stablecoin. Options: POLYGON, ETHEREUM
Response:
{
  "id": "c48d1dd1-b5cd-5bc7-b85e-df1b0f17c1c8",
  "status": "activated",
  "provider": "CROSS_RIVER",
  "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
  "source": {
    "paymentRails": ["ach", "wire", "rtp"],
    "currency": "usd"
  },
  "destination": {
    "chain": "POLYGON",
    "currency": "usdc",
    "walletAddress": "0x63dAbB631bcE6d6090A4e6c5c7aB20d3D853C338"
  },
  "depositInstructions": {
    "bankName": "Cross River Bank",
    "bankAddress": "885 Teaneck Road, Teaneck, NJ 07666",
    "beneficiary": {
      "name": "John Doe",
      "address": "123 Park Ave, Kansas City, KS, 10001, US"
    },
    "ach": {
      "routingNumber": "021214891",
      "accountNumber": "372232122120"
    },
    "wire": {
      "routingNumber": "021214891",
      "accountNumber": "372232122120"
    },
    "instruction": "Please deposit USD to the bank account provided. Ensure that the beneficiary name matches the account holder name provided, or the payment may be rejected."
  }
}
Virtual account created!Response Fields:
id
string
The unique virtual account ID. Save this for monitoring deposits.
status
string
Account status. activated means it’s ready to receive deposits.
source
object
Source configuration for fiat deposits.
destination
object
Destination configuration for crypto conversion.
depositInstructions
object
Most Important: Bank account details User A needs to send money to.
How to Use: Provide these deposit instructions to User A 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. For monitoring deposits, subscribe to ONRAMP.CREATE webhook events.

Create User B (Recipient)

The recipient (User B) needs a user account with a mexicoGlobalNetwork account to receive the remittance. Follow the same user creation flow as User A, but complete KYC for the GLOBAL_NETWORK rail instead of USD.
Using an Existing User: If User B already exists in your system, you can skip user creation and just ensure they have an active mexicoGlobalNetwork account. You’ll need their userId and accountId for the remittance transaction.

Required Information for User B

To complete this recipe, you’ll need:
  • User B’s userId - From creating their user account
  • User B’s MXN accountId - From adding their Mexican bank account
For the complete flow of creating User B and adding their MXN bank account, follow the same steps as User A but:
  1. Submit KYC for the GLOBAL_NETWORK rail instead of USD
  2. Add a mexicoGlobalNetwork account (Mexican bank account) instead of a Virtual Account
For detailed instructions on adding offramp accounts, see our Offramp Guide.

Execute Transaction

Now you can send the remittance from User A to User B. Create an offramp transaction that converts USDC to MXN and sends it to User B’s Mexican bank account. This is a two-step process:
  1. Create offramp request - Get a quote for the conversion
  2. Accept the quote - Execute the remittance
Complete Offramp Guide: For more details on offramps and cross-border transfers, see our Offramp Transfer Guide.
Create an offramp request to get a quote for converting 11 USDC to MXN using the Create an offramp endpoint.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": "1c74a5f7-0dd6-4e81-bb31-5b1857e5fc3e",
  "purposeOfPayment": "payment_for_services",
  "supportingDocumentType": "billing_document",
  "source": {
    "amount": 11,
    "currency": "usdc",
    "chain": "POLYGON",
    "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429"
  },
  "destination": {
    "currency": "mxn",
    "accountId": "64fbf048-378d-409a-a11b-cfa5a3d5cf6d",
    "userId": "64e9b060-4c28-53f0-ab35-9e516f3dfb45"
  }
}
'
Request Fields:
requestId
string
required
Unique identifier (UUID) for this offramp request to ensure idempotency.
purposeOfPayment
string
Purpose of the payment for compliance. Common values: payment_for_services, family_support, gift, salary, etc.
supportingDocumentType
string
Type of supporting document if required. Options: billing_document, invoice, contract, etc.
supportingDocumentUrl
string
URL to the supporting document if required by the destination country’s regulations.
description
string
Optional description of the payment.
source
object
required
Source of the offramp (crypto side - User A).
destination
object
required
Destination of the offramp (fiat side - User B).
developerFee
array
Optional: Developer fees to collect on the transaction.
Response:
{
  "id": "e1821e0a-ba62-4022-83b8-aab9866ee0a1",
  "type": "OFFRAMP",
  "status": "OPEN_QUOTE",
  "source": {
    "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
    "name": "John Doe",
    "email": "johndoe@gmail.com",
    "chain": "POLYGON",
    "currency": "usdc",
    "amount": 11,
    "walletAddress": "0x63dAbB631bcE6d6090A4e6c5c7aB20d3D853C338"
  },
  "destination": {
    "userId": "64e9b060-4c28-53f0-ab35-9e516f3dfb45",
    "name": "Jane Doe",
    "email": "janedoe@gmail.com",
    "accountId": "64fbf048-378d-409a-a11b-cfa5a3d5cf6d",
    "currency": "mxn",
    "amount": 201.26
  },
  "quoteInformation": {
    "sendGross": {
      "amount": "11.000000",
      "currency": "usdc"
    },
    "sendNet": {
      "amount": "10.710000",
      "currency": "usdc"
    },
    "taxFee": {
      "amount": "0.187000",
      "currency": "usdc"
    },
    "railFee": {
      "amount": "0.110000",
      "currency": "usdc"
    },
    "receiveGross": {
      "amount": "201.26",
      "currency": "mxn"
    },
    "receiveNet": {
      "amount": "201.26",
      "currency": "mxn"
    },
    "rate": "18.296364",
    "expiresAt": "2025-11-12T23:25:23.151+00:00"
  }
}
Offramp quote created!Response Fields:
id
string
Unique offramp transaction ID. Save this - you’ll need it to accept the quote and monitor status.
type
string
Transfer type. Always OFFRAMP for remittance transactions.
status
string
Current status. OPEN_QUOTE means you have an active quote waiting to be accepted.
source
object
Source details showing User A’s wallet and amount being sent.
destination
object
Destination details showing User B’s bank account and amount they’ll receive.
quoteInformation
object
Critical: Detailed breakdown of the conversion including exchange rate, fees, and amounts.
Understanding the Quote:In this example:
  • User A sends 11 USDC
  • After fees (tax: 0.187 USDC, rail: 0.110 USDC), 10.71 USDC is converted
  • At a rate of 18.30 MXN per USDC
  • User B receives 201.26 MXN in their bank account
Quote Expiration: Quotes typically expire after 15-30 minutes to protect against exchange rate volatility. If your quote expires before acceptance, create a new offramp request for a fresh quote with updated rates.
After reviewing the quote and fees, accept it to execute the remittance using the Accept Quote endpoint.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/offramps/e1821e0a-ba62-4022-83b8-aab9866ee0a1/quote/accept \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY'
Response:
{
  "id": "e1821e0a-ba62-4022-83b8-aab9866ee0a1",
  "type": "OFFRAMP",
  "status": "CRYPTO_INITIATED",
  "source": {
    "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
    "name": "John Doe",
    "email": "johndoe@gmail.com",
    "chain": "POLYGON",
    "currency": "usdc",
    "amount": 11,
    "walletAddress": "0x63dAbB631bcE6d6090A4e6c5c7aB20d3D853C338"
  },
  "destination": {
    "userId": "64e9b060-4c28-53f0-ab35-9e516f3dfb45",
    "name": "Jane Doe",
    "email": "janedoe@gmail.com",
    "accountId": "64fbf048-378d-409a-a11b-cfa5a3d5cf6d",
    "currency": "mxn",
    "amount": 201.26
  },
  "quoteInformation": {
    "sendGross": {
      "amount": "11.000000",
      "currency": "usdc"
    },
    "sendNet": {
      "amount": "10.710000",
      "currency": "usdc"
    },
    "taxFee": {
      "amount": "0.187000",
      "currency": "usdc"
    },
    "railFee": {
      "amount": "0.110000",
      "currency": "usdc"
    },
    "receiveGross": {
      "amount": "201.26",
      "currency": "mxn"
    },
    "receiveNet": {
      "amount": "201.26",
      "currency": "mxn"
    },
    "rate": "18.296364",
    "expiresAt": "2025-11-12T23:25:23.151+00:00"
  }
}
Quote accepted! Remittance is processing.The status has changed from OPEN_QUOTE to CRYPTO_INITIATED, meaning the transaction is now being executed.Remittance Status Progression:
  1. OPEN_QUOTE - Quote generated, waiting for acceptance
  2. CRYPTO_INITIATED - Processing crypto conversion
  3. CRYPTO_PENDING - Waiting for blockchain confirmation
  4. FIAT_PENDING - Converting to MXN and initiating bank transfer
  5. COMPLETED - MXN deposited to User B’s bank account
Monitoring Remittance Status:Track the remittance progress using:
  • Polling: Call Retrieve an offramp with the transaction ID (e1821e0a-ba62-4022-83b8-aab9866ee0a1)
  • Webhooks: Subscribe to OFFRAMP.UPDATE events for real-time status notifications
Settlement Times:
  • Sandbox: Instant simulation for testing
  • Production: Typically 1-3 business days depending on the destination country and payment rail
User Notifications: Consider implementing webhook handlers to send notifications to both User A (sender) and User B (recipient) as the remittance progresses through each status. This provides transparency and builds trust in your remittance product.

🎉 Congratulations!

You’ve successfully completed a cross-border remittance transaction! By following this recipe, you can now:
  • ✅ Generate API keys and authenticate with HIFI
  • ✅ Onboard users and complete KYC for multiple currency rails
  • ✅ Create virtual accounts for fiat-to-crypto conversion
  • ✅ Execute cross-border remittances with competitive exchange rates
  • ✅ Provide transparent fee structures and quote expiration

Next Steps

Ready to build a full remittance product? Here’s what to explore next:
  • Webhooks - Set up real-time notifications for transaction status updates and user engagement
  • Offramp Guide - Deep dive into offramp transactions and compliance requirements
  • Error Handling - Implement robust error handling for failed transactions and expired quotes
  • API Reference - Explore all available endpoints and parameters for advanced features