Testing
NjiaPay provides a comprehensive testing environment with MockPSP that allows you to simulate various payment scenarios without processing real payments.
MockPSP Overview
MockPSP is a mock payment service provider available in the sandbox environment that simulates different payment outcomes based on the data you provide.
Key Features:
- Simulate successful payments
- Test declined transactions
- Trigger error responses
- No real money involved
- Instant responses
https://app.staging.infinic.dev/).Test Payment Scenarios
Successful Payment (Default)
By default, all payments succeed when using MockPSP. Enter any card details and the payment will be authorized.
Example:
{
"payment_method": {
"number": "4242424242424242",
"holder_name": "John Doe",
"expiry_month": "12",
"expiry_year": "2025",
"cvv": "123"
}
}
Result: ✅ Payment succeeds with status AUTHORISED
Declined Payment
To simulate a declined payment, set the cardholder name to DECLINED:
Example:
{
"payment_method": {
"number": "4242424242424242",
"holder_name": "DECLINED", // ← Magic keyword
"expiry_month": "12",
"expiry_year": "2025",
"cvv": "123"
}
}
Result: ❌ Payment declined with status REFUSED
Use this to test:
- How your application handles declined payments
- Error messages shown to customers
- Retry logic
- Alternative payment methods
Error Response
To simulate a payment error, set the cardholder name to ERROR:
Example:
{
"payment_method": {
"number": "4242424242424242",
"holder_name": "ERROR", // ← Magic keyword
"expiry_month": "12",
"expiry_year": "2025",
"cvv": "123"
}
}
Result: ❌ Payment fails with status ERROR
Use this to test:
- System error handling
- Error logging
- Customer communication for technical failures
- Retry mechanisms
Alternative Testing Methods
Using Merchant Reference
You can also control MockPSP behavior via the reference_id field by passing JSON:
Declined via Reference:
{
"reference_id": "{\"status\": \"declined\"}"
}
Error via Reference:
{
"reference_id": "{\"status\": \"error\"}"
}
This is useful when testing via API where you can't control the cardholder name.
Testing Complete Workflows
Test Hosted Checkout Flow
- Create Intent:
curl -X POST https://app.staging.infinic.dev/api/intents \
-H "Authorization: Bearer YOUR_SANDBOX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 10000,
"currency": "ZAR",
"reference_id": "test_order_001",
"purchaser_id": "test_customer_001",
"return_url": "https://yoursite.com/callback",
"allow_remember_credentials": false
}'
- Open Checkout:
- Copy the
redirect_urlfrom response - Open in browser
- Select payment method (card)
- Copy the
- Test Success:
- Holder name: "Test Customer"
- Any card number: 4242424242424242
- Any future expiry date
- Any CVV
- Click Pay
- Test Decline:
- Holder name: "DECLINED"
- Click Pay
- Verify error message
- Test Error:
- Holder name: "ERROR"
- Click Pay
- Verify error handling
Test Webhook Delivery
- Set up webhook endpoint (e.g., using webhook.site)
- Configure in merchant portal → Settings → Webhooks
- Create test payment
- Verify webhook received with correct payload
Example expected webhook:
{
"type": "StatusChange",
"created": "2024-09-01T00:00:00Z",
"content": {
"intent_id": "550e8400-e29b-41d4-a716-446655440000",
"reference_id": "test_order_001",
"amount": 10000,
"currency": "ZAR",
"status": "success"
}
}
Test Auto-Payments
- Create initial intent with MIT:
{
"allow_remember_credentials": true,
"request_unscheduled_mit": true
}
- Complete payment successfully
- Receive PaymentCredential webhook with credential token
- Create auto-payment attempt:
curl -X POST https://app.staging.infinic.dev/api/intents/auto-attempt \
-H "Authorization: Bearer YOUR_SANDBOX_API_KEY" \
-d '{
"amount": 5000,
"currency": "ZAR",
"reference_id": "subscription_month_2",
"purchaser_id": "test_customer_001",
"credentials": ["credential_token_from_webhook"]
}'
- Verify auto-payment succeeds
Testing Refunds
- Create and complete a successful payment
- Create refund:
curl -X POST https://app.staging.infinic.dev/api/intents/{intent_id}/refund \
-H "Authorization: Bearer YOUR_SANDBOX_API_KEY" \
-d '{
"amount": 5000,
"reason": "customer_request"
}'
- Verify refund webhook received
Testing Split Payments
- Create beneficiaries (if not already created)
- Create intent with split:
{
"amount": 10000,
"split": {
"split_type": "AMOUNT",
"splits": [
{
"beneficiary_id": "beneficiary_1_id",
"amount": 7000
},
{
"beneficiary_id": "main_merchant_id",
"amount": 3000
}
]
}
}
- Complete payment
- Verify splits in merchant portal
Test Data
Valid Test Card Numbers
Any of these card numbers work in MockPSP:
| Card Number | Brand |
|---|---|
| 4242424242424242 | Visa |
| 5555555555554444 | Mastercard |
| 378282246310005 | American Express |
| 6011111111111117 | Discover |
Test Customer Data
Use realistic but fake data:
{
"email": "test.customer@example.com",
"phone": "+27123456789",
"country": "ZA"
}
Sandbox Limitations
MockPSP simulates basic payment flows but has some limitations:
MockPSP does NOT simulate:
- Real 3D Secure flows (just returns success)
- Actual bank redirects
- Real processing delays
- PSP-specific validation errors
- Network timeouts
For realistic testing:
- Test with real PSPs in sandbox when available
- Test edge cases manually
- Use staging environment for pre-production testing
Troubleshooting Tests
Sandbox Slow on First Request
Issue: First API call takes 10-20 seconds
Solution: This is normal due to spin-down. Warm up sandbox with a health check request before running test suite.
Webhook Not Received
Issue: Webhook endpoint not getting notifications
Solutions:
- Verify webhook URL is publicly accessible (use ngrok for local testing)
- Check webhook URL configuration in merchant portal
- Verify endpoint returns 200 OK
- Check firewall/security rules
Payment Stuck in Pending
Issue: Payment never completes in tests
Solutions:
- Verify you're completing the checkout flow properly
- Check MockPSP is available (sandbox up)
- Try creating a new intent
- Check for API errors in response
Best Practices
✅ DO
- Test all payment scenarios (success, decline, error)
- Test webhook handling thoroughly
- Use unique
reference_idfor each test - Test refund flows
- Automate common test scenarios
- Test with different currencies
- Verify error messages are user-friendly
❌ DON'T
- Skip testing decline scenarios
- Use production API keys for testing
- Test with real payment data
- Hardcode test data
- Rely solely on manual testing
- Test in production