Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.dubupay.com/llms.txt

Use this file to discover all available pages before exploring further.

Virtual bank accounts are the primary way your customers pay you in Nigerian Naira through Dubu Pay. When a customer sends a bank transfer to the account number you provide, Dubu Pay detects the deposit, converts it to USDT (or credits your internal balance), and notifies your server via webhook. This guide walks you through every step: creating a customer, choosing the right account type, issuing the account, sharing the details, and confirming the payment.
1

Create a customer

Before issuing a virtual bank account, you need a customer record. The customer ties the account to a real person and is required for permanent accounts.
cURL
curl -X POST https://api.dubupay.com/api/v1/payments/customers \
  -H "X-Api-Key: dubu_sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "amara@example.com",
    "first_name": "Amara",
    "last_name": "Okafor"
  }'
Node.js
const response = await fetch(
  "https://api.dubupay.com/api/v1/payments/customers",
  {
    method: "POST",
    headers: {
      "X-Api-Key": "dubu_sk_live_your_api_key",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      email: "amara@example.com",
      first_name: "Amara",
      last_name: "Okafor",
    }),
  }
);
const { data: customer } = await response.json();
The response contains the new customer’s id, which you’ll use in the next step.
{
  "success": true,
  "data": {
    "id": "cus_01hx7k9p2qr3st4uv5wx6yz",
    "email": "amara@example.com",
    "first_name": "Amara",
    "last_name": "Okafor",
    "tier1_status": "NONE",
    "tier2_status": "NONE",
    "created_at": "2024-11-01T09:00:00.000Z"
  }
}
2

Choose an account type

Dubu Pay offers two virtual bank account types. Pick the one that fits your use case:
TypeTTLRateWhen to use
TEMPORARY25 minutesLocked at creationOne-off payments with a known amount
PERMANENTNo expiryFloatingRecurring top-ups, wallets, long-lived accounts
Permanent accounts require the customer to have completed BVN (Tier 1) verification. If tier1_status is not APPROVED, the request will be rejected.
Temporary onramps require you to pass an amount when creating the account. The rate is locked at that moment so the customer always knows exactly how much to send.
3

Issue a virtual bank account

Call POST /payments/onramps to create the virtual bank account. You can also use POST /customers/:id/ngn-virtual-account if you want the account linked directly to a specific customer record.
curl -X POST https://api.dubupay.com/api/v1/payments/onramps \
  -H "X-Api-Key: dubu_sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "TEMPORARY",
    "customer_id": "cus_01hx7k9p2qr3st4uv5wx6yz",
    "amount": 5000,
    "settlement": {
      "mode": "INTERNAL_BALANCE",
      "asset": "USDT"
    }
  }'
The response includes the virtual_account object with the bank account details to show your customer.
{
  "success": true,
  "data": {
    "id": "onramp_01hx7kbp2qr3st4uv5wx6ab",
    "type": "TEMPORARY",
    "status": "ACTIVE",
    "customer_id": "cus_01hx7k9p2qr3st4uv5wx6yz",
    "virtual_account": {
      "bank_name": "Wema Bank",
      "account_number": "9901234567",
      "account_name": "Dubu Pay / Amara Okafor",
      "expires_at": "2024-11-01T09:25:00.000Z"
    },
    "settlement": {
      "mode": "INTERNAL_BALANCE",
      "asset": "USDT"
    },
    "created_at": "2024-11-01T09:00:00.000Z"
  }
}
Settlement modes:
  • INTERNAL_BALANCE — converted USDT is credited to your merchant balance or the customer’s internal ledger
  • ONCHAIN — converted USDT is sent directly to the destination_address you provide
Supported settlement assets: USDT, USDCSupported chains for onchain settlement: APTOS, BASE, CELO, ETHEREUM, POLYGON, SOLANA, TRON
4

Share the account details with your payer

Present the virtual_account fields to your customer in your UI or payment flow:
  • Bank name: Wema Bank
  • Account number: 9901234567
  • Account name: Dubu Pay / Amara Okafor
  • Amount to send: ₦5,000 (for temporary accounts)
  • Expiry: 25 minutes from creation (for temporary accounts)
For temporary accounts, always show the exact amount and the countdown timer. If the account expires before payment, create a new onramp with a fresh rate.
5

Detect the deposit

You have two options for detecting when a payment arrives:Option A — Webhooks (recommended)Register a webhook endpoint to receive real-time deposit.* events. See the Webhooks guide for setup instructions. The events you’ll receive are:
EventMeaning
deposit.receivedNGN transfer received; FX conversion in progress
deposit.pending_withdrawalFX complete; USDT being sent to destination
deposit.settledUSDT delivered; settlement complete
deposit.failedSomething went wrong
deposit.flaggedDeposit held for compliance review
Option B — PollingPoll GET /payments/deposits filtered by the onramp ID:
curl "https://api.dubupay.com/api/v1/payments/deposits?onramp_id=onramp_01hx7kbp2qr3st4uv5wx6ab" \
  -H "X-Api-Key: dubu_sk_live_your_api_key"
Prefer webhooks over polling in production. Polling introduces latency and adds unnecessary API calls.
6

Check deposit status

Fetch a specific deposit by ID to get the full status and settlement details:
curl https://api.dubupay.com/api/v1/payments/deposits/dep_01hx7kcp2qr3st4uv5wx6cd \
  -H "X-Api-Key: dubu_sk_live_your_api_key"
{
  "success": true,
  "data": {
    "id": "dep_01hx7kcp2qr3st4uv5wx6cd",
    "onramp_id": "onramp_01hx7kbp2qr3st4uv5wx6ab",
    "status": "SETTLED",
    "amount_ngn": "5000.00",
    "amount_asset": "3.21",
    "asset": "USDT",
    "chain": "TRON",
    "tx_hash": "0xabc123...",
    "payment_reference": "TRF20241101090012",
    "settled_at": "2024-11-01T09:04:32.000Z"
  }
}
Deposit status lifecycle:
PENDING_FX → PENDING_WITHDRAWAL → SETTLED
                               ↘ FAILED
                               ↘ FLAGGED
                               ↘ REVERSED
Only take action (e.g., credit your customer’s account or fulfil an order) when the status is SETTLED.

Testing in sandbox

Use the sandbox endpoint to simulate a deposit without sending real funds:
curl -X POST https://api.dubupay.com/api/v1/payments/sandbox/deposits \
  -H "X-Api-Key: dubu_sk_test_your_test_key" \
  -H "Content-Type: application/json" \
  -d '{
    "onramp_id": "onramp_01hx7kbp2qr3st4uv5wx6ab"
  }'
Pass "should_flag": true to simulate a flagged deposit instead of a settled one.
Sandbox deposits only work with test API keys (dubu_sk_test_*). Never use test keys in production.