Skip to content
Test money only. BitMomo currently runs on test networks. Payments use testnet coins and no real money moves. Live keys are not available yet.

Quickstart

This guide takes you from nothing to a verified test payment. Everything here uses test money: testnet coins, no real funds.

  1. Sign in to the merchant dashboard at merchant.dev.bitmomo.app.
  2. Open Settings → API keys and choose Create key.
  3. Pick Test mode and Read & write access, then copy the key. It starts with bm_test_ and is shown only once.

Keep the key on your server, for example in an environment variable. Never put it in a browser, mobile app or public repository.

Terminal window
export BITMOMO_API_KEY="bm_test_..."
export BITMOMO_API_URL="https://api.dev.bitmomo.app"

The SDK runs on Node.js 18 or later.

Terminal window
npm install @bitmomo/merchant-sdk

You can also call the HTTP API directly; every step below shows both.

Create the payment from your server, using the price from your own order record. Pass an idempotency_key that you store with the order before calling BitMomo, so a retry after a timeout returns the same payment instead of creating a second one.

import { CryptoPOS, newIdempotencyKey } from '@bitmomo/merchant-sdk';
const bitmomo = new CryptoPOS({
apiKey: process.env.BITMOMO_API_KEY!,
baseURL: process.env.BITMOMO_API_URL!,
});
const payment = await bitmomo.createPayment({
amount: '100.00', // Ghana cedis, as a decimal string
crypto_type: 'USDT_TRC20',
fiat_currency: 'GHS',
order_id: 'order_1001',
idempotency_key: newIdempotencyKey(), // store this with the order first
});
console.log(payment.id, payment.crypto_amount, payment.deposit_address, payment.expires_at);

The same call over HTTP:

Terminal window
curl -X POST "$BITMOMO_API_URL/api/v1/gateway/payments" \
-H "x-api-key: $BITMOMO_API_KEY" \
-H "content-type: application/json" \
-d '{"amount":"100.00","crypto_type":"USDT_TRC20","fiat_currency":"GHS","order_id":"order_1001","idempotency_key":"7f1c0a7e-5d9b-4a51-9c1e-2a6f0f3b8d11"}'

The response includes the locked crypto amount, the deposit address, a qr_code_data payment URI and an expiry time.

Send the customer to the hosted checkout page for the payment:

https://customer.dev.bitmomo.app/pay/{payment.id}

It shows the QR code, amount and countdown, and updates live as the payment progresses. You can also build your own page from the fields in the create response.

  1. In the dashboard, open Settings → Webhooks, enter your HTTPS endpoint and select at least payment.completed.
  2. Save, then copy the signing secret. It is shown only once.
  3. Verify every request before trusting it:
import express from 'express';
import { CryptoPOS } from '@bitmomo/merchant-sdk';
const app = express();
// Use the raw body: the signature covers the exact bytes BitMomo sent.
app.post('/webhooks/bitmomo', express.raw({ type: 'application/json' }), (req, res) => {
const verified = CryptoPOS.verifyWebhookEvent(req.body, req.header('x-webhook-signature') ?? '', {
// A new endpoint's secret is version 1; each rotation adds one.
secrets: [{ version: 1, secret: process.env.BITMOMO_WEBHOOK_SECRET! }],
timestamp: req.header('x-webhook-timestamp'),
keyVersion: req.header('x-webhook-key-version'),
});
if (!verified.valid) return res.status(400).send(verified.reason);
// Store the event durably (keyed by verified.envelope.deliveryId), then reply 2xx.
res.sendStatus(200);
});

A webhook tells you something changed; it is not proof by itself. Before you ship goods, fetch the payment and check it against your order:

// Exact decimal comparison: never convert money to floating point.
const units = (value: string) => {
const [whole, fraction = ''] = value.split('.');
return BigInt(whole) * 100_000_000n + BigInt(fraction.padEnd(8, '0'));
};
const current = await bitmomo.getPayment(paymentId);
const paidInFull =
current.status === 'completed' &&
current.environment === 'test' &&
current.order_terms?.order_id === order.id &&
current.economics !== null &&
units(current.economics.recognized_gross_ghs) >= units(order.amountGhs);

Payments explains each field, and Build a merchant server shows a complete, crash-safe integration.