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

1

Log In

Access the HOST Pay dashboard
2

Select Application

Navigate to your application
3

Get Test Keys

Generate Test Mode API credentials
4

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

1

Install ngrok

bash # Download from ngrok.com or npm install -g ngrok
2

Start Your Server

bash python app.py # or node server.js
3

Create Tunnel

bash ngrok http 3000
4

Configure Webhook

Add the ngrok URL to your dashboard: https://abc123.ngrok.io/webhooks/hostpay
5

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