Overview
Testing is crucial for ensuring your integration works correctly before going live. HOST Pay provides a complete Test Mode environment that mirrors production functionality without processing real money.
Test Mode Features
Mock Services Simulated payment providers
Isolated Data Separate test database
Full API Access All endpoints available
Webhook Events Real webhook notifications
Getting Test Credentials
Log In
Access the HOST Pay dashboard
Select Application
Navigate to your application
Get Test Keys
Generate Test Mode API credentials
Store Securely
Save in environment variables
Test Mode Payment Methods
Mobile Money (Monime)
In Test Mode, mobile money uses MockMonimePaymentService :
# Make a mobile money deposit in Test Mode
response = requests.post(
"https://hpay-api.host-sl.com/api/v1/transactions/wallet/mobile-money-deposit" ,
headers = {
"api-key" : "test_ak_1234567890" ,
"secret-key" : "test_sk_0987654321"
},
json = {
"wallet_id" : "wallet_test_abc123" ,
"amount" : 100.00
}
)
# Returns mock USSD code
{
"transaction_id" : "txn_test_xyz789" ,
"payment_code" : {
"ussdCode" : "*715*1234567890#" ,
"status" : "pending"
}
}
Features:
✅ Instant mock responses
✅ No real money involved
✅ Predictable behavior
✅ Webhook events triggered
Card Payments (Stripe)
Test Mode uses Stripe’s test card numbers:
Success Cards:
4242 4242 4242 4242 (Visa - succeeds)
5555 5555 5555 4444 (Mastercard - succeeds)
Decline Cards:
4000 0000 0000 0002 (Card declined)
4000 0000 0000 9995 (Insufficient funds)
4000 0000 0000 0069 (Expired card)
Use any:
Future expiry date (e.g., 12/30)
Any 3-digit CVC (e.g., 123)
Any billing address
# Card deposit example
response = requests.post(
"https://hpay-api.host-sl.com/api/v1/transactions/wallet/card-deposit" ,
headers = test_headers,
json = {
"wallet_id" : "wallet_test_abc123" ,
"amount" : 100.00 ,
"card_token" : "tok_visa" # Stripe test token
}
)
Test Scenarios
Scenario 1: Happy Path
Test the complete user flow:
import requests
BASE_URL = "https://hpay-api.host-sl.com/api/v1"
headers = {
"api-key" : "test_ak_1234567890" ,
"secret-key" : "test_sk_0987654321"
}
# 1. Create user
user = requests.post( f " { BASE_URL } /users/" , headers = headers, json = {
"name" : "Test User" ,
"email" : "test@example.com" ,
"phone_number" : "+23279123456"
}).json()
print ( f "✅ Created user: { user[ 'id' ] } " )
# 2. Get wallet
wallet = requests.get(
f " { BASE_URL } /wallets/ { user[ 'id' ] } /" ,
headers = headers
).json()
print ( f "✅ Got wallet: { wallet[ 'id' ] } , Balance: $ { wallet[ 'balance' ] } " )
# 3. Make deposit
deposit = requests.post(
f " { BASE_URL } /transactions/wallet/mobile-money-deposit" ,
headers = headers,
json = {
"wallet_id" : wallet[ 'id' ],
"amount" : 100.00
}
).json()
print ( f "✅ Deposit initiated: { deposit[ 'transaction_id' ] } " )
# 4. Check balance
updated_wallet = requests.get(
f " { BASE_URL } /wallets/ { wallet[ 'id' ] } /balance" ,
headers = headers
).json()
print ( f "✅ New balance: $ { updated_wallet[ 'balance' ] } " )
Scenario 2: Error Handling
Test error cases:
# Test invalid credentials
try :
response = requests.get(
"https://hpay-api.host-sl.com/api/v1/users/" ,
headers = {
"api-key" : "invalid_key" ,
"secret-key" : "invalid_secret"
}
)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print ( f "✅ Correctly rejected invalid credentials: { e.response.status_code } " )
# Test disabled user
user_id = "user_test_disabled"
try :
response = requests.post(
f "https://hpay-api.host-sl.com/api/v1/transactions/wallet/mobile-money-deposit" ,
headers = headers,
json = {
"wallet_id" : "wallet_test_disabled" ,
"amount" : 100.00
}
)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
if e.response.status_code == 403 :
print ( "✅ Correctly blocked transaction for disabled user" )
# Test invalid amount
try :
response = requests.post(
f "https://hpay-api.host-sl.com/api/v1/transactions/wallet/mobile-money-deposit" ,
headers = headers,
json = {
"wallet_id" : wallet_id,
"amount" : - 50.00 # Invalid negative amount
}
)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print ( f "✅ Correctly rejected invalid amount: { e.response.status_code } " )
Scenario 3: Wallet Transfers
Test peer-to-peer transfers:
# Create two users
user1 = create_user( "Alice" , "alice@example.com" , "+23279111111" )
user2 = create_user( "Bob" , "bob@example.com" , "+23279222222" )
# Get their wallets
wallet1 = get_wallet(user1[ 'id' ])
wallet2 = get_wallet(user2[ 'id' ])
# Fund Alice's wallet
deposit_to_wallet(wallet1[ 'id' ], 100.00 )
# Transfer from Alice to Bob
transfer = requests.post(
"https://hpay-api.host-sl.com/api/v1/transactions/wallet/transfer" ,
headers = headers,
json = {
"sender_wallet_id" : wallet1[ 'id' ],
"recipient_wallet_id" : wallet2[ 'id' ],
"amount" : 50.00
}
).json()
print ( f "✅ Transfer completed: { transfer[ 'transaction_id' ] } " )
# Verify balances
alice_balance = get_balance(wallet1[ 'id' ])
bob_balance = get_balance(wallet2[ 'id' ])
assert alice_balance == 50.00 # 100 - 50
assert bob_balance == 50.00 # 0 + 50
print ( "✅ Balances correct after transfer" )
Testing Webhooks
Local Testing with ngrok
Install ngrok
bash # Download from ngrok.com or npm install -g ngrok
Start Your Server
bash python app.py # or node server.js
Create Tunnel
bash ngrok http 3000
Configure Webhook
Add the ngrok URL to your dashboard:
https://abc123.ngrok.io/webhooks/hostpay
Test
Make a transaction and verify webhook delivery
Webhook Testing Example
from flask import Flask, request
import json
app = Flask( __name__ )
@app.route ( '/webhooks/hostpay' , methods = [ 'POST' ])
def handle_webhook ():
event = request.json
print ( f "📬 Received webhook: { event[ 'event' ] } " )
print ( f " Transaction ID: { event[ 'data' ][ 'id' ] } " )
print ( f " Amount: $ { event[ 'data' ][ 'amount' ] } " )
print ( f " Status: { event[ 'data' ][ 'status' ] } " )
# Log for testing
with open ( 'webhook_log.json' , 'a' ) as f:
f.write(json.dumps(event) + ' \n ' )
return 'OK' , 200
if __name__ == '__main__' :
app.run( port = 3000 )
Test Data Management
Cleaning Up Test Data
# Delete test users (Test Mode only)
def cleanup_test_users ():
users = requests.get(
"https://hpay-api.host-sl.com/api/v1/users/" ,
headers = test_headers
).json()
for user in users:
if user[ 'email' ].endswith( '@test.example.com' ):
requests.delete(
f "https://hpay-api.host-sl.com/api/v1/users/ { user[ 'id' ] } " ,
headers = test_headers
)
print ( f "🗑️ Deleted test user: { user[ 'email' ] } " )
# Run cleanup
cleanup_test_users()
Test Mode data is isolated and can be safely deleted. Be careful not to use
live credentials when cleaning up!
Automated Testing
Unit Tests
import unittest
from hostpay import HostPayClient
class TestHostPayIntegration ( unittest . TestCase ):
def setUp ( self ):
self .client = HostPayClient(
api_key = "test_ak_1234567890" ,
secret_key = "test_sk_0987654321"
)
def test_create_user ( self ):
user = self .client.create_user(
name = "Test User" ,
email = f "test- { uuid.uuid4() } @example.com" ,
phone_number = "+23279123456"
)
self .assertIsNotNone(user[ 'id' ])
self .assertEqual(user[ 'name' ], "Test User" )
def test_wallet_created_automatically ( self ):
user = self .client.create_user( ... )
wallet = self .client.get_wallet(user[ 'id' ])
self .assertEqual(wallet[ 'user_id' ], user[ 'id' ])
self .assertEqual(wallet[ 'balance' ], 0.00 )
def test_deposit_increases_balance ( self ):
user = self .client.create_user( ... )
wallet = self .client.get_wallet(user[ 'id' ])
initial_balance = wallet[ 'balance' ]
deposit_amount = 100.00
self .client.deposit(wallet[ 'id' ], deposit_amount)
updated_wallet = self .client.get_wallet(user[ 'id' ])
expected_balance = initial_balance + deposit_amount
self .assertEqual(updated_wallet[ 'balance' ], expected_balance)
if __name__ == '__main__' :
unittest.main()
Integration Tests
import pytest
@pytest.fixture
def test_client ():
return HostPayClient(
api_key = os.getenv( "TEST_API_KEY" ),
secret_key = os.getenv( "TEST_SECRET_KEY" )
)
def test_full_transaction_flow ( test_client ):
# Create users
sender = test_client.create_user( ... )
recipient = test_client.create_user( ... )
# Fund sender
sender_wallet = test_client.get_wallet(sender[ 'id' ])
test_client.deposit(sender_wallet[ 'id' ], 100.00 )
# Transfer
transfer = test_client.transfer(
sender_wallet[ 'id' ],
recipient[ 'wallet_id' ],
50.00
)
# Verify
assert transfer[ 'status' ] == 'completed'
assert test_client.get_balance(sender_wallet[ 'id' ]) == 50.00
Best Practices
Generate unique emails/phone numbers for each test run to avoid conflicts: email = f "test- { uuid.uuid4() } @example.com"
Delete test data after each test run to keep the environment clean.
Zero amounts - Negative amounts - Very large amounts - Invalid wallet IDs -
Disabled accounts - Insufficient balances
Verify all webhook events are received and handled correctly.
Track API calls and errors to identify integration issues early.
Going Live Checklist
Before switching to Live Mode:
Need Help?
Test Mode Guide Learn about Test vs Live environments
Support Get help with testing