Skip to main content
Facilitate marketplace payments where buyers can pay sellers across regions and currencies, with structured payout flows that reflect how modern marketplaces operate. Support common marketplace behaviors such as holding funds until conditions are met, confirming completed orders, and releasing payouts with added security. 🎯 What you’ll build: A complete marketplace payment flow where a buyer in the US pays a seller in Hong Kong in USDC. The seller then offramps HKD from their wallet to their bank account.

Use Case Overview

This recipe demonstrates a marketplace payment where:
  • ✅ User A deposits USD from their bank account
  • ✅ USD automatically converts to USDC stablecoin
  • ✅ USDC is transferred to User B wallet
  • ✅ USDC is converted to HKD and sent to User B’s bank account
This flow will demonstrate the use of transfer approvals to hold funds until transfers are approved. Marketplaces may use approval steps for things like confirming delivery, holding funds during a dispute window, or simply adding a release step before paying out a seller.

What you’ll build

Here’s what we’ll accomplish in this recipe:
  1. Add Virtual Account (Buyer / User A) - Set up account for USD deposits that convert to USDC
  2. Create Business User B (Seller) - Onboard Hong Kong seller
  3. Execute Payment - Send USDC from User A wallet to User B wallet
  4. Initiate Offramp - Convert crypto funds from User B’s wallet to User B HKD bank account
Payment Flow:
USD → User A Bank Account → USDC → User A Wallet → USDC → Business B Wallet → HKG → Business B Bank Account
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.

Prerequisites

Before you begin, make sure you have: User A – Individual user created and KYC submitted with status = active User B – Business user created and KYB submitted with status = active For a complete guide on user onboarding, see:

Add Virtual Account (Buyer)

The buyer needs 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.
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"
}
'
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."
  }
}

Create Business B (Seller)

The seller (Business B in Hong Kong) needs a wallet address to receive the payment. This is created automatically when the business user is onboarded. Some sellers may choose to use a separate wallet dedicated to marketplace-related activity to make tracking incoming payments easier.
Using an Existing Business: If Business B already exists in your system, you can skip business creation and just ensure they have an active wallet address and Hong Kong bank account for later offramping. You’ll need either their userid or walletaddress for the crypto transfer.

Required Information

To complete this recipe, you’ll need:
  • Business B’s userId - From creating their business account
  • Business B’s walletAddress - Provisioned upon creating the business user
  • Business B’s HKD accountId - From adding their Hong Kong bank account
For detailed instructions on adding offramp accounts for international recipients, see our Wallet Guide.

Execute Payment

Now you can send the wallet transfer payment from User A (US) to Business B (Hong Kong). Create a crypto transfer that sends USDC from User A’s wallet to Business B’s wallet.
Transfers can be sent to other HIFI users or external wallet addresses. For this example, we will send to another HIFI user (Business B).
For this recipe, we will demonstrate the use of Transfer Approvals. This is a two-step process:
  1. Create crypto transfer request - Mark requireApproval as true in the request fields (User A)
  2. Accept the transfer approval - Accept the approval through the Approve a transfer endpoint (Business B)
Create a crypto transfer request that requires approval by setting requireApproval: true in the Create a Crypto Transfer endpoint.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/wallets/transfers \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '
{
  "requestId": "86dbb25a-ef63-496a-a26c-8bdeaf277568",
  "currency": "usdc",
  "amount": 10,
  "chain": "POLYGON",
  "source": {
    "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429"
  },
  "destination": {
    "userId": "e06caa8a-4c0f-58d7-95a5-baf676e1e39a",
    "requireApproval": true
  }
}
'
Request Fields:
requestId
string
required
Unique identifier (UUID) for this transfer request to ensure idempotency.
currency
string
required
Source cryptocurrency (e.g., usdc, usdt).
amount
number
required
Amount of USDC to send from User A’s wallet.
chain
string
required
Blockchain network (e.g., POLYGON, ETHEREUM).
source
object
required
Source of the transfer (User A).
destination
object
required
Destination of the transfer (Business B)
Response:
{
  "transferType": "WALLET.TRANSFER",
  "transferDetails": {
    "id": "ec2702f3-fe0e-46b0-9fd8-24a12dbd33a3",
    "requestId": "c776758a-3246-4347-badf-6a6aa97f0529",
    "createdAt": "2025-11-25T18:08:28.924Z",
    "updatedAt": "2025-11-25T18:08:28.924Z",
    "chain": "POLYGON",
    "currency": "usdc",
    "contractAddress": "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
    "status": "PENDING_APPROVAL",
    "failedReason": null,
    "source": {
      "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
      "walletAddress": "0x63dAbB631bcE6d6090A4e6c5c7aB20d3D853C338",
      "walletType": "INDIVIDUAL",
      "user": {
        "email": "[email protected]",
        "lastName": "Doe",
        "firstName": "John"
      }
    },
    "destination": {
      "userId": "e06caa8a-4c0f-58d7-95a5-baf676e1e39a",
      "walletAddress": "0x8356d234077d4b7c71E35c95B075ed4ba5FF7681",
      "user": {
        "email": "[email protected]",
        "businessName": "HKG Test Business"
      }
    },
    "amount": 10,
    "approval": {
      "id": "528f0c38-6a82-41b1-8e35-c07c7b6cc556",
      "status": "PENDING",
      "createdAt": "2025-11-25T18:08:28.976103+00:00"
    }
  }
}
Response Fields:
transferDetails.id
string
Unique crypto transfer transaction ID.
transferDetails.type
string
Transfer type.
transferDetails.status
string
Current status. PENDING_APPROVAL means you have an active transfer approval waiting to be accepted.
transferDetails.source
object
Source details showing User A’s wallet.
transferDetails.destination
object
Destination details showing Business B’s wallet info.
transferDetails.amount
number
Amount of USDC being transferred.
transferDetails.approval
object
Transfer approval details.

Understanding Transfer Approvals

After submitting a transfer request with requireApproval: true:
  • The transfer status becomes PENDING_APPROVAL and does not execute
  • Dashboard admins receive email notifications about the pending approval
  • Authorized admins review and either approve or reject the transfer
  • If approved → transfer executes normally. If rejected, transfer is cancelled
For detailed instructions on the approval workflow, see:
👉 Transfer Approvals Guide

Execute Offramp

With the approved transfer, Business B can now transfer the USDC from their wallet into their HKD bank account. This is a two-step process:
  1. Create offramp request - Get a quote for the conversion
  2. Accept the quote - Execute the payment

Required Information

In order to execute the offramp and complete this recipe, follow these steps:
  1. Create an offramp request with the source (wallet, chain, amount) and destination (fiat account), optionally including developer fees.
  2. Review the returned quote—rate, fees, send/receive amounts, and expiration—in transferDetails.quoteInformation.
  3. Confirm status is OPEN_QUOTE and save transferDetails.id to track and accept the quote.
  4. Accept the quote via POST /v2/offramps/{id}/quote/accept to convert stablecoins to fiat and initiate payout.
  5. Monitor statuses through crypto and fiat phases (e.g., CRYPTO_INITIATED → completion) using the receipt fields or webhooks.
For detailed instructions on creating an offramp transaction, see our Offramp Guide.

🎉 Congratulations!

You’ve successfully completed a marketplace payment! By following this recipe, you can now:
  • ✅ Create virtual accounts for fiat-to-crypto conversion
  • ✅ Execute marketplace payments with transfer approvals
  • ✅ Provide transparent fee structures and quote expiration

Next Steps

Ready to build a full marketplace payment platform? 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
  • Onchain Transfers - Learn how to initiate and track onchain wallet-to-wallet transfers
  • Transfer Approvals - Configure optional approvals for higher-control transfer workflows
  • Error Handling - Implement robust error handling for failed transactions and expired quotes
  • API Reference - Explore all available endpoints and parameters for advanced features