Testing Pay with Transfer on Monnify Sandbox

By Muhammad Samu 8th Apr, 2026

Pay with Transfer is one of the most popular payment methods on Monnify. Instead of entering card details, a customer receives a virtual bank account number, makes a transfer from their mobile banking app, and the payment is confirmed instantly with no redirects, no OTP prompts, and no card declines.

The good news is that Pay with Transfer works across every integration path Monnify supports: the frontend One-Time Payment SDK, a server-side API transaction, and even a fully custom UI where you surface just the account number yourself.

This guide covers all three paths, explains how to get a specific virtual account number for a chosen bank, and shows you how to use the Monnify Bank Simulator to complete test transfers in sandbox without touching a real bank account.

How Pay with Transfer Works

Regardless of how a transaction is started, the core flow is the same:

  1. A transaction is created and Monnify generates a virtual account number tied to it.
  2. The virtual account number (and its bank) is shown to the customer.
  3. The customer makes a transfer to that account for the exact amount.
  4. Monnify detects the transfer and fires a webhook to your server.
  5. Your server validates the webhook and fulfills the order.

In sandbox, step 3 is handled by the Monnify Bank Simulator instead of a real bank app. It works for every integration path described below.

Prerequisites

  1. A Monnify sandbox account. Sign up here if you haven't already.
  2. Your sandbox API Key, Secret Key, and Contract Code from the Monnify dashboard under Developer > API Keys & Contracts.
  3. A webhook URL configured in your dashboard under Settings > Webhook URL. You can use ngrok or smee.io to expose a local server during development.

Path 1 - One-Time Payment SDK (Frontend)

If you are already using the Monnify One-Time Payment SDK to open the checkout modal, enabling Pay with Transfer requires no extra API calls. Just include ACCOUNT_TRANSFER in the paymentMethods array when you call MonnifySDK.initialize(). Monnify handles everything else, and the virtual account is displayed inside the modal.

checkout.js (frontend)

When the modal opens, switch to the Pay with Transfer tab. You will see a bank name and account number. Use these in the Monnify Bank Simulator (Step 3) to complete the test transfer.

Path 2 - Initialize Transaction API (Backend)

When you initiate the transaction from your server using the Initialize Transaction API, Monnify returns a checkoutUrl and a transactionReference. The checkout URL leads to the same hosted page as the SDK modal, and opening it is the simplest way to show the customer their virtual account. You can also skip the checkout URL entirely and build your own account display, which is covered in Path 3.

initTransaction.js (server)

Redirect or link the customer to the checkoutUrl and they will see the virtual account details on the Monnify-hosted page. From there you follow the same simulator steps in Step 3.

Path 3 - Custom Account Display (Skip the Checkout URL)

Some businesses want full control over the payment UI and only need the raw virtual account number so they can render it themselves. Monnify supports this through the Bank Transfer Init Payment endpoint.

After calling Initialize Transaction (Path 2) and obtaining the transactionReference, make a second call to:

POST /api/v1/merchant/bank-transfer/init-payment

Pass the transactionReference and the bankCode of the bank you want to issue the virtual account from. Monnify returns the account number, account name, and bank name you can display directly in your own UI, with no Monnify-hosted page required.

getBankTransferAccount.js (server)

Step 3 - Simulate the Transfer with the Monnify Bank Simulator

Once you have a virtual account number, whether from the SDK modal, the Monnify checkout page, or your own custom UI, use the Monnify Bank Simulator to act as the customer and complete the transfer. This works for all three paths above.

  1. Open the simulator: Navigate to https://websim.sdk.monnify.com/?#/bankingapp. You will see an interface resembling a Nigerian mobile banking app.
  2. Click "Transfer": Click the Transfer option in the simulator's navigation.
  3. Enter the bank: Select the same bank shown on your checkout page or returned by /api/v1/merchant/bank-transfer/init-payment.
  4. Enter the account number: Paste the virtual account number displayed to the customer.
  5. Enter the amount: Type the exact amount specified when the transaction was initialized. Monnify matches transfers by both account number and amount.
  6. Submit the transfer: Click Make Payment. The simulator notifies Monnify's sandbox infrastructure, which marks the transaction as PAID and dispatches the webhook.

Step 4 - Verify the Payment

After the simulator posts the transfer, verify the payment server-side. There are two complementary approaches; use both for a robust integration.

Option A - Webhook (recommended)

Monnify POSTs a notification to your configured webhook URL when the payment is confirmed. Always validate the monnify-signature header before acting on the payload.

webhook.js (server)

Option B - Transaction Status API

Use the Get Transaction Status endpoint to query payment status on demand, useful for confirming on a callback page or reconciling missed webhooks.

verifyTransaction.js (server)

Troubleshooting Common Issues

  1. Transfer submitted but status stays pending: Confirm you entered the exact amount in the simulator. A mismatch is treated as an over- or underpayment and won't auto-complete the transaction.
  2. Wrong bank in the simulator: Select the bank shown on the checkout page or returned by /api/v1/merchant/bank-transfer/init-payment. Each sandbox contract is assigned specific test banks.
  3. Webhook not received: Ensure your webhook URL is publicly reachable (use ngrok locally) and is saved in your Monnify dashboard under Settings > Webhook URL. Check that your server returns 200; Monnify retries on any other status.
  4. /api/v1/merchant/bank-transfer/init-payment returns an error: Make sure the transactionReference is from a valid, unexpired transaction and that the bankCode you supplied is one of the banks available in your sandbox contract.
  5. Expired transaction: Checkout sessions have a limited validity window (Defaults to 40 mins). Initialize a fresh transaction and repeat from Step 1.

Quick Checklist

  1. Use https://sandbox.monnify.com during development. Switch to https://api.monnify.com in production.
  2. Set paymentMethods: ["ACCOUNT_TRANSFER"] to restrict checkout to transfer only (applies to both SDK and API paths).
  3. If building a custom UI, call /api/v1/merchant/bank-transfer/init-payment with your chosen bankCode and transactionReference to get the account details.
  4. Use the Monnify Bank Simulator to complete test transfers, which works for SDK, API, and custom UI paths.
  5. Enter the exact amount in the simulator to avoid partial-payment scenarios.
  6. Validate the monnify-signature header on every incoming webhook.
  7. Make your webhook handler idempotent, as Monnify may deliver the same event more than once.
  8. Always verify payment status server-side before fulfilling an order.

Summary

Pay with Transfer on Monnify works across every integration path: the One-Time Payment SDK for a quick frontend drop-in, the Initialize Transaction API for server-driven flows, and /api/v1/merchant/bank-transfer/init-payment when you want to surface a specific bank's virtual account inside your own UI. In sandbox, the Monnify Bank Simulator stands in for the customer's banking app and works identically across all three paths. Get the simulator flow solid in sandbox, validate your webhooks, and your live integration will behave exactly the same way.

Ready to go further? Read about securing and handling Monnify webhooks or explore the full Monnify API reference.

Copyright © 2026 Monnify
instagramfacebookicon