Testing Cross-border Transfers

Test sender creation, collection, CNY payout and recovery in sandbox.

Use sandbox credentials and https://api-v2.honeycoin.app/api/sandbox/b2b/cross-border/requests as {crossBorderBaseUrl}. Generate a sandbox bearer token at POST https://api-v2.honeycoin.app/api/sandbox/b2b/auth/generate-bearer-token. Sandbox simulates payments; no real money is charged or paid out.

Create a sandbox sender, create a request, and then initiate its charge. Use a new request externalReference for each separate scenario. The sender and request must belong to the same sandbox account.

Sandbox still validates sender data, beneficiary identity, payment purpose, source currency, collection availability and operator details. Include a beneficiary with type, idType, idCountry, and nested payoutDetails. Both senders and beneficiaries use idNumber for individuals or registrationNumber for businesses; the other number field is forbidden. Test values choose an outcome only after the request is accepted; they do not activate an unavailable currency, country or method. The source currency must be KES or NGN and the receiver currency must be CNY.

Mobile money to CNY

Use the collection country's numeric calling code followed by the scenario digits. Send the number as a string without +, spaces or a local leading zero. Match chargeDetails.country, chargeCurrency, and momoOperatorId to the same available collection market.

OutcomechargeDetails.phoneNumber
Collection success<CALLING_CODE>712345678
Collection failure<CALLING_CODE>787654321

For example, the Kenya success fixture is 254712345678 with country: KE, chargeCurrency: KES, and momoOperatorId: mpesa. The sender's separate phoneNumber still uses the + format required by the sender API.

For bank and Alipay payouts, use these beneficiary account numbers as strings:

Outcomebeneficiary.payoutDetails.payoutMethod.accountNumber
Payout success1234567890
Payout failure0987654321

This sandbox Alipay account number is a test fixture. For production, supply the real recipient account identifier. Alipay requires an individual sender in both environments.

Success example

Replace senderId with your sandbox individual sender ID. Include the recipient identity fields in beneficiary; use idType: business-registration-number and registrationNumber for a business recipient instead of the individual identity example below. Adjust the illustrative amount to one allowed for your account.

{
  "senderId": "sender_example_001",
  "purpose": "family_support",
  "amount": 1000,
  "chargeCurrency": "KES",
  "receiverCurrency": "CNY",
  "externalReference": "sandbox-cny-success-001",
  "requestType": "transfer",
  "chargeDetails": {
    "method": "momo",
    "firstName": "Amina",
    "lastName": "Otieno",
    "country": "KE",
    "email": "[email protected]",
    "phoneNumber": "254712345678",
    "momoOperatorId": "mpesa"
  },
  "beneficiary": {
    "type": "individual",
    "idType": "national-id",
    "idCountry": "CN",
    "idNumber": "EXAMPLE-CN-ID-001",
    "payoutDetails": {
      "method": "alipay",
      "country": "CN",
      "payoutMethod": {
        "accountName": "Example Recipient",
        "accountNumber": "1234567890"
      }
    }
  }
}

Send this body to POST {crossBorderBaseUrl}, save data.id, and initiate POST {crossBorderBaseUrl}/charges/{requestId} with no body. Save the returned transaction ID.

The sandbox automatically initiates a simulated payout after the charge succeeds. Check the charge's chargeStatus: successful separately from request status: payout_successful. Production payout processing follows HoneyCoin review and does not have the same timing as sandbox simulation.

Sandbox bank collections

Sandbox accepts chargeDetails.method: bank on new requests. Production currently accepts only momo for new requests, so successful bank testing does not establish production availability.

Replace the full chargeDetails object with the example below. Keep the sender, purpose, currencies, amount, reference and beneficiary fields required by the create-request API. Omit phoneNumber and momoOperatorId from bank chargeDetails; those fields are forbidden for bank charges. firstName, lastName, country, and email remain required.

{
  "method": "bank",
  "firstName": "Amina",
  "lastName": "Otieno",
  "country": "NG",
  "email": "[email protected]"
}

For this example use chargeCurrency: NGN and an account with the bank collection route available. email: [email protected] simulates collection success; [email protected] simulates failure. These email fixtures apply to bank collections, not mobile money outcomes.

After charge initiation, read the charge transaction to inspect its virtualAccount. The sandbox charge response contains the transaction ID; do not require virtual account details to appear in the initial response, and do not send real funds to sandbox bank details.

Scenarios to verify

TestSetupExpected behavior
End-to-end successSuccess collection fixture and success beneficiary accountCharge succeeds; request reaches payout_successful
Collection failureFailure collection fixtureRequest reaches charge_failed; no successful beneficiary payout
Payout failureSuccess collection fixture and beneficiary 0987654321Collection succeeds; request reaches payout_failed; do not recharge
Duplicate request referenceRepeat an existing reference with changed request details409 DUPLICATE_EXTERNAL_REFERENCE; an identical recent call may replay its original response
Business sender with AlipayBusiness senderId, Alipay payout422 UNSUPPORTED_METHOD
Missing purpose or required sub-purposeOmit purpose, or omit subPurpose for goods/services400 VALIDATION_ERROR
Missing beneficiarySupply only the former top-level payoutDetails400 VALIDATION_ERROR; beneficiary is required
Wrong sender or beneficiary identity numberOmit the number field for the selected type, or include the other type's field400 VALIDATION_ERROR; use idNumber for an individual and registrationNumber for a business
Duplicate chargeCharge a request that already has a pending or successful depositA replay or state conflict; no second active charge
Close unpaid requestCreate a request and close it before chargingclosed with pendingChargesClosed: 0
Close paid or active requestAttempt to close while a deposit is pending/successful or a payout exists409 CROSS_BORDER_REQUEST_CANNOT_BE_CLOSED
Retry a closed requestInitiate its chargeRejected; no new charge
Sender deletionDelete an unused sender and fetch it404 SENDER_NOT_FOUND; it disappears from active listings
PaginationCreate enough records for multiple pagesUse each endpoint's documented cursor envelope and preserve filters

A retry on a failed request reuses its saved charge details, so a failure test number or email continues to select failure. Create a separate request with a new external reference to test success with different collection details.

Use request and transaction lookups to verify persisted outcomes, and test webhook handling for both transaction_updated and crossborder_updated. Do not infer completion from the initiation response or from elapsed time.