> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hifi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Marketplace Payments

> 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 transaction approvals to hold funds until transactions 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
```

<Note>
  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.
</Note>

***

## 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:

* [Authentication Guide](/docs/api/authentication)
* [User Guide](/docs/users/overview)
* [KYC Guide](/docs/kyc)

***

## 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.

<Note>
  **Complete Virtual Account Guide:** For more details on virtual accounts and
  onramping, see our [Virtual Accounts Guide](/docs/virtual-accounts).
</Note>

<AccordionGroup>
  <Accordion title="Create Virtual Account">
    **Request:**

    ```bash theme={null}
    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:**

    ```json theme={null}
    {
      "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."
      }
    }
    ```
  </Accordion>
</AccordionGroup>

***

## 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.

<Note>
  **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.
</Note>

### 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](/docs/wallets).

***

## 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.

<Note>
  Transfers can be sent to other HIFI users or external wallet addresses. For
  this example, we will send to another HIFI user (Business B).
</Note>

For this recipe, we will demonstrate the use of Transaction 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)

<AccordionGroup>
  <Accordion title="Create Crypto Transfer Request">
    Create a crypto transfer request that **requires approval** by setting `requireApproval: true` in the [Create a Crypto Transfer](https://docs.hifi.com/api-reference/wallets/create-transfer) endpoint.

    **Request:**

    ```bash theme={null}
    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:**

    <ResponseField name="requestId" type="string" required>
      Unique identifier (UUID) for this transfer request to ensure idempotency.
    </ResponseField>

    <ResponseField name="currency" type="string" required>
      Source cryptocurrency (e.g., **usdc**, **usdt**).
    </ResponseField>

    <ResponseField name="amount" type="number" required>
      Amount of USDC to send from User A's wallet.
    </ResponseField>

    <ResponseField name="chain" type="string" required>
      Blockchain network (e.g., POLYGON, ETHEREUM).
    </ResponseField>

    <ResponseField name="source" type="object" required>
      Source of the transfer (User A).

      <Expandable title="properties">
        <ResponseField name="userId" type="string" required>
          User A’s user ID (sender)
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="destination" type="object" required>
      Destination of the transfer (Business B)

      <Expandable title="properties">
        <ResponseField name="userId" type="string" required>
          Business B’s user ID (either the userid or the `walletAddress` can be provided)
        </ResponseField>

        <ResponseField name="requireApproval" type="boolean" required>
          Require approval from Business B (true)
        </ResponseField>
      </Expandable>
    </ResponseField>

    **Response:**

    ```json theme={null}
    {
      "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": "johndoe@gmail.com",
            "lastName": "Doe",
            "firstName": "John"
          }
        },
        "destination": {
          "userId": "e06caa8a-4c0f-58d7-95a5-baf676e1e39a",
          "walletAddress": "0x8356d234077d4b7c71E35c95B075ed4ba5FF7681",
          "user": {
            "email": "hkgtestbusiness@gmail.com",
            "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:**

    <ResponseField name="transferDetails.id" type="string">
      Unique crypto transfer transaction ID.
    </ResponseField>

    <ResponseField name="transferDetails.type" type="string">
      Transfer type.
    </ResponseField>

    <ResponseField name="transferDetails.status" type="string">
      Current status. `PENDING_APPROVAL` means you have an active transfer approval
      waiting to be accepted.
    </ResponseField>

    <ResponseField name="transferDetails.source" type="object">
      Source details showing User A’s wallet.

      <Expandable title="properties">
        <ResponseField name="userId" type="string">
          User A's user ID
        </ResponseField>

        <ResponseField name="walletAddress" type="string">
          User A's wallet address
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="transferDetails.destination" type="object">
      Destination details showing Business B’s wallet info.

      <Expandable title="properties">
        <ResponseField name="userId" type="string">
          Business B’s user ID
        </ResponseField>

        <ResponseField name="walletAddress" type="string">
          Business B’s wallet address. This address was provisioned upon creating the user
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="transferDetails.amount" type="number">
      Amount of USDC being transferred.
    </ResponseField>

    <ResponseField name="transferDetails.approval" type="object">
      Transfer approval details.

      <Expandable title="properties">
        <ResponseField name="approval.id" type="string">
          Unique transfer approval ID
        </ResponseField>

        <ResponseField name="approval.status" type="string">
          Approval status. **PENDING** means you have an active transfer approval
          waiting to be accepted
        </ResponseField>
      </Expandable>
    </ResponseField>

    ### Understanding Transaction Approvals

    After submitting a transaction request with `requireApproval: true`:

    * The transaction 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 transaction
    * If approved → transaction executes normally. If rejected, transaction is cancelled

    For detailed instructions on the approval workflow, see:\
    👉 **[Transaction Approvals Guide](https://docs.hifi.com/features/transfer-approvals)**
  </Accordion>
</AccordionGroup>

***

## 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](/docs/transactions/offramps).

***

## 🎉 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 transaction 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](/docs/webhooks)** - Set up real-time notifications for transaction status updates and user engagement
* **[Offramp Guide](/docs/transactions/offramps)** - Deep dive into offramp transactions and compliance requirements
* **[Onchain Transfers](/docs/transactions/transfers)** - Learn how to initiate and track onchain wallet-to-wallet transfers
* **[Transaction Approvals](/docs/features/transfer-approvals)** - Configure optional approvals for higher-control transaction workflows
* **[Error Handling](/docs/api/errors)** - Implement robust error handling for failed transactions and expired quotes
* **[API Reference](https://docs.hifi.com/api-reference)** - Explore all available endpoints and parameters for advanced features
