Skip to main content
Facilitate split payment services where a single payment is divided among multiple recipients. Perfect for splitting bills, shared expenses, or distributing funds to multiple stakeholders efficiently. ⏱️ Time to complete: 25-35 minutes 🎯 What you’ll build: A split payment system where users deposit USD into a virtual account, funds convert to USDC, then split payments are distributed to multiple recipients. This guide covers two approaches: settlement rules for configured automatic splits, and batch transfers for on-demand splits.

Use Case Overview

This recipe demonstrates a split payment flow where:
  • ✅ Users deposit USD into dedicated virtual accounts
  • ✅ USD automatically converts to USDC stablecoin
  • ✅ Payments are split among multiple recipients using one of two methods
  • ✅ Operational overhead is minimized through automation
This flow enables scalable split payment services with reduced processing costs and efficient fund distribution. Choose the method that best fits your use case:
  • Settlement Rules (Option 1): Configure split percentages or amounts once, then every deposit automatically splits according to your rules. Perfect for recurring splits with fixed recipients and ratios.
  • Batch Transfers (Option 2): Manually initiate split payments on-demand with full control over amounts and recipients. Perfect for bill payments or dynamic splits that vary per transaction.

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 - Onboard a user and complete KYC for USD rail
  3. Add Virtual Account - Set up account for collecting USD payments that convert to USDC
  4. Choose Your Split Method:
    • Option 1: Settlement Rules - Configure automatic split payment distribution
    • Option 2: Batch Transfers - Execute on-demand split payments
Payment Flow (Option 1 - Settlement Rules):
USD → User Bank Account → Virtual Account → USDC → Settlement Rule → Automatic Split to Multiple Recipients
Payment Flow (Option 2 - Batch Transfers):
USD → User Bank Account → Virtual Account → USDC → Batch Transfer → Multiple Recipients

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'
For a complete guide on API authentication, see our Authentication Documentation.

Create User

Create a verified user account for the person making the split payment. Every user must accept HIFI’s Terms of Service and complete KYC verification before they can access fiat rails and make payments.
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

Now that the user has passed KYC, create a Virtual Account for collecting the payment to be split. This is a bank account number automatically created by HIFI that users can deposit USD into. When fiat arrives, it’s automatically converted to USDC and ready for distribution.
Virtual Account for Split Payments: Each virtual account comes with unique ACH/wire/RTP details you can surface in your app. When deposits arrive, HIFI detects the funds and applies your conversion settings (e.g., USD → USDC). You can then use settlement rules for automatic splitting or batch transfers for on-demand splitting.
A Virtual Account enables users to deposit USD from their bank, which automatically converts to USDC on Polygon for split payment distribution.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.
provider
string
Banking partner providing the virtual account infrastructure.
source
object
Source configuration for fiat deposits.
destination
object
Destination configuration for crypto conversion.
depositInstructions
object
Most Important: Bank account details users need to send money to.
How to Use: Provide these deposit instructions to your users through your app/website. When they send money to this account via their bank, HIFI automatically detects the deposit and converts it to USDC. You can then split the payment using settlement rules (automatic) or batch transfers (on-demand). For monitoring deposits, subscribe to ONRAMP.CREATE webhook events.
For a complete guide on virtual accounts and onramping, see our Virtual Accounts Guide.

Option 1: Split Payments with Settlement Rules

Settlement rules automatically distribute funds to multiple recipients whenever a deposit arrives at the virtual account. Configure the split percentages or amounts once, and every deposit will automatically split according to your rules.
When to Use Settlement Rules: Use settlement rules when you have: - Fixed recipient lists that don’t change frequently - Consistent split ratios (e.g., always split 50/50 or 33/33/34) - Recurring split payments that should happen automatically - Set-and-forget split configurations Perfect for shared expenses, recurring bill splits, or fixed revenue sharing.
Create a settlement rule that defines how to split payments among multiple recipients. Each rule in the array sends a portion of the payment to a different wallet address.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/virtual-accounts/settlement-rules \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data '
{
  "requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "chain": "POLYGON",
  "includeHIFIFee": false,
  "rules": [
    {
      "type": "PERCENTAGE",
      "calculationModel": "FIXED",
      "value": 0.3333,
      "walletAddress": "0xA4C951a7ca4138220a9D4611e7A058d4673e14c3"
    },
    {
      "type": "PERCENTAGE",
      "calculationModel": "FIXED",
      "value": 0.3333,
      "walletAddress": "0x0466DCD644Ae2Ee5d88CF0e1976c3ce237A0D760"
    },
    {
      "type": "PERCENTAGE",
      "calculationModel": "FIXED",
      "value": 0.3334,
      "walletAddress": "0x8356d234077d4b7c71E35c95B075ed4ba5FF7681"
    }
  ]
}
'
Request Fields:
requestId
string
required
Unique identifier (UUID) for this request to ensure idempotency.
chain
string
required
Blockchain network for the settlement rule. Must match the virtual account’s destination chain (e.g., POLYGON, ETHEREUM, BASE, SOLANA).
includeHIFIFee
boolean
Whether to include HIFI’s platform fee in the calculation. Defaults to false. Contact HIFI support if you want to include HIFI’s fee.
rules
array
required
Array of settlement rules. Each rule defines a portion of the payment to send to a recipient wallet.
Response:
{
  "id": "15c786fb-de7a-520c-a4b3-f312d4a122d2",
  "chain": "POLYGON",
  "includeHIFIFee": false,
  "rules": [
    {
      "type": "PERCENTAGE",
      "calculationModel": "FIXED",
      "value": 0.3333,
      "tiers": null,
      "walletAddress": "0xA4C951a7ca4138220a9D4611e7A058d4673e14c3"
    },
    {
      "type": "PERCENTAGE",
      "calculationModel": "FIXED",
      "value": 0.3333,
      "tiers": null,
      "walletAddress": "0x0466DCD644Ae2Ee5d88CF0e1976c3ce237A0D760"
    },
    {
      "type": "PERCENTAGE",
      "calculationModel": "FIXED",
      "value": 0.3334,
      "tiers": null,
      "walletAddress": "0x8356d234077d4b7c71E35c95B075ed4ba5FF7681"
    }
  ]
}
Settlement rule created!Response Fields:
id
string
The unique settlement rule ID. Save this - you’ll need it to apply the rule to the virtual account.
chain
string
Blockchain network the rule is configured for. Must match your virtual account’s destination chain.
rules
array
Array of rules defining how the payment is split among recipients.
Split Payment Example: In this example, we’re splitting payments equally among three recipients (33.33%, 33.33%, 33.34%). You can adjust the percentages to split unevenly, or use fixed amounts if you prefer. The remaining amount after all rules are applied goes to the user’s wallet.
After creating the settlement rule, apply it to the virtual account. Once applied, every deposit will automatically be split according to the rule.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/users/3b77cec8-1bb9-5ea0-91a1-e8c1411dd429/virtual-accounts/c48d1dd1-b5cd-5bc7-b85e-df1b0f17c1c8/settlement-rules/15c786fb-de7a-520c-a4b3-f312d4a122d2 \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY'
Path Parameters:
userId
string
required
The user ID who owns the virtual account.
accountId
string
required
The virtual account ID to apply the rule to.
ruleId
string
required
The settlement rule ID from the create response.
Response:
{
  "success": true
}
Settlement rule applied!
Chain Compatibility: The settlement rule must be created on the same blockchain network as the virtual account’s destination chain. For example, a virtual account configured for POLYGON can only use settlement rules created on POLYGON.
Automatic Split Payments: Once the settlement rule is applied, every deposit to this virtual account will automatically be split according to your rules. No manual intervention required! Monitor split payments by subscribing to ONRAMP.CREATE and ONRAMP.UPDATE webhook events.
For a complete guide on settlement rules including tiered pricing and advanced configurations, see our Settlement Rules Guide.

Option 2: Split Payments with Batch Transfers

Batch transfers let you manually initiate split payments with full control over amounts and recipients for each transaction. You decide when to split and can customize the distribution for each payment.
When to Use Batch Transfers: Use batch transfers when you need: - On-demand split payments that vary per transaction - Dynamic recipient lists that change based on the payment - Conditional logic before splitting (e.g., verify amounts, check balances) - Bill payments where amounts differ each time
  • One-time or irregular split payments Perfect for bill payment services, dynamic revenue sharing, or variable expense splits.
Create a batch transfer to split a payment among multiple recipients in a single transaction using the Create Batch Transfer endpoint.In this example, we’ll split a payment to three different recipients with 10 USDC each from the user’s wallet.Request:
curl --request POST \
  --url https://sandbox.hifibridge.com/v2/wallets/transfers/batches \
  --header 'accept: application/json' \
  --header 'authorization: Bearer YOUR_API_KEY' \
  --header 'content-type: application/json' \
  --data '
{
  "requestId": "b91772a6-f9c0-4479-a34c-c8723608d2e8",
  "currency": "usdc",
  "chain": "POLYGON",
  "source": {
    "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429"
  },
  "destination": {
    "batch": [
      {
        "walletAddress": "0xA4C951a7ca4138220a9D4611e7A058d4673e14c3",
        "amount": "10"
      },
      {
        "walletAddress": "0x0466DCD644Ae2Ee5d88CF0e1976c3ce237A0D760",
        "amount": "10"
      },
      {
        "walletAddress": "0x8356d234077d4b7c71E35c95B075ed4ba5FF7681",
        "amount": "10"
      }
    ]
  },
  "requireApproval": false
}
'
Request Fields:
requestId
string
required
Unique identifier (UUID) for this batch transfer request to ensure idempotency.
currency
string
required
Cryptocurrency to transfer. Use usdc for USD Coin.
chain
string
required
Blockchain network for the transfer. Options: POLYGON, ETHEREUM
source
object
required
Source of the batch transfer (the user making the split payment).
destination
object
required
Destination configuration containing the batch of recipients.
requireApproval
boolean
Whether the batch transfer requires manual approval before execution. Set to false for automatic processing.
Response:
{
  "id": "467e8eed-c6e2-4f78-9404-a82148c49e0e",
  "type": "WALLET.TRANSFER.BATCH",
  "status": "CREATED",
  "chain": "POLYGON",
  "currency": "usdc",
  "contractAddress": "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
  "source": {
    "userId": "3b77cec8-1bb9-5ea0-91a1-e8c1411dd429",
    "walletAddress": "0x63dAbB631bcE6d6090A4e6c5c7aB20d3D853C338",
    "walletType": "INDIVIDUAL"
  },
  "destination": {
    "batch": [
      {
        "amount": "10",
        "walletAddress": "0xA4C951a7ca4138220a9D4611e7A058d4673e14c3"
      },
      {
        "amount": "10",
        "walletAddress": "0x0466DCD644Ae2Ee5d88CF0e1976c3ce237A0D760"
      },
      {
        "amount": "10",
        "walletAddress": "0x8356d234077d4b7c71E35c95B075ed4ba5FF7681"
      }
    ]
  },
  "receipt": {
    "transactionHash": null,
    "userOpHash": null
  }
}
Batch transfer created!Response Fields:
id
string
Unique batch transfer ID. Save this to monitor the batch status and retrieve transaction details.
type
string
Transfer type. Always WALLET.TRANSFER.BATCH for batch transfers.
status
string
Current batch status. Starts as CREATED, then progresses through: - CREATED - Batch transfer initiated - PENDING - Being processed on blockchain - COMPLETED - All payments successfully delivered - FAILED - One or more payments failed (check individual statuses)
chain
string
Blockchain network where the transfer is being executed.
currency
string
Cryptocurrency being transferred.
contractAddress
string
Smart contract address handling the USDC transfers on the blockchain.
source
object
Source details showing the user’s wallet information.
destination
object
Destination details showing all recipients in the batch.
receipt
object
Transaction receipt information.
Understanding the Batch Transfer:In this example:
  • Source: User’s wallet (0x63dA...C338) with 30+ USDC available
  • Batch: 3 recipients receiving 10 USDC each
  • Total: 30 USDC distributed in a single blockchain transaction
  • Cost Savings: One transaction fee instead of three separate transactions
Monitoring Batch Transfers: Subscribe to WALLET.TRANSFER.BATCH.UPDATE webhook events to receive real-time notifications as the batch progresses. You can also poll the Retrieve Batch Transfer endpoint to check individual payment statuses within the batch.
For a complete guide on batch transfers including advanced features like approval workflows and error handling, see our Batch Transfers Guide.

🎉 Congratulations!

You’ve successfully built a split payment system! By following this recipe, you can now:
  • ✅ Generate API keys and authenticate with HIFI
  • ✅ Onboard users and complete KYC for USD operations
  • ✅ Create virtual accounts for collecting payments with automatic conversion
  • ✅ Configure settlement rules for automatic split payments (Option 1)
  • ✅ Execute batch transfers for on-demand split payments (Option 2)
  • ✅ Choose the right method based on your use case
  • ✅ Reduce operational overhead with automated or consolidated transactions

Next Steps

Ready to scale your split payment service? Here’s what to explore next:
  • Settlement Rules Guide - Deep dive into advanced settlement rule features like tiered pricing, fixed amounts, and multiple rule configurations
  • Batch Transfers Guide - Learn about batch transfers with approval workflows, failure handling, and advanced features
  • Webhooks - Set up real-time notifications for deposit detection, conversion completion, and split payment distribution
  • Virtual Accounts Guide - Learn about monitoring deposits and handling multiple virtual accounts per user
  • API Reference - Explore all available endpoints and parameters for advanced features